diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..6bb95b3 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,6 @@ +Kunihiro Ishiguro +Toshiaki Takada +Yasuhiro Ohara +Akihiro Mizutani +Gleb Natapov +Alex D. Zinin diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 0000000..161a3d1 --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,482 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, 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 library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, 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 companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..b005eed --- /dev/null +++ b/ChangeLog @@ -0,0 +1,678 @@ +2004-11-24 Yasuhiro Ohara + + * configure.ac: Net-SNMP support. + +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2002-06-28 Kunihiro Ishiguro + + * update-autotools: Change file name from update-auto-tools.sh. + +2002-06-21 Kunihiro Ishiguro + + * update-auto-tools.sh: Add a new script to clean up build + environment. + +2002-06-18 Kunihiro Ishiguro + + * Shift to the latest build environment autoconf-2.53 and + automake-1.6.2. + +2001-10-22 Kunihiro Ishiguro + + * Integrate Glen Turner 's pid option. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-19 "Peter Galbavy" + + * configure.in: SNMP library check problem fix when the library is + installed under /usr/local/lib. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-04-22 Kunihiro Ishiguro + + * configure.in (LIBPAM): Use ZEBRA_AC_C_BIGENDIAN to avoid a + warning. + (IF_METHOD): Use test -r instead of AC_CHECK_FILE to avoid + warnings. + + * config.guess: Update to 2000-11-10 version. + +2001-04-11 Kunihiro Ishiguro + + * configure.in: Use AC_TRY_COMPILE instead of AC_EGREP_HEADER to + detect in_pktinfo structure. Suggested by: Vlad Lungu + . + +2001-03-07 Michael Rozhavsky + + * configure.in: Add check for structure in_pktinfo. + +2001-02-07 "Bjoern A. Zeeb" + + * configure.in (USE_PAM): Fix PAM library detection code. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-12 Kunihiro Ishiguro + + * configure.in: Remove guile related definition. + +2001-01-11 Kunihiro Ishiguro + + * configure.in (ac_cv_htonl_works): HAVE_REPAIRABLE_HTONL is + removed. htonl should work fine on any platform. + +2001-01-10 Kunihiro Ishiguro + + * configure.in: Remove --enable-oldrib option. + + * acconfig.h: OLD_RIB definition is removed. + + * zebra-0.90 is released. + + * configure.in (LIBS): Add check for sun_len field in struct + sun_len. + +2001-01-09 Kunihiro Ishiguro + + * Makefile.am: Include init/redhat files to distribution. + +2001-01-07 Yasuhiro Ohara + + * configure.in: check libm.a for BGPd compile error. + AC_CHECK_LIB(m, main) was added. + +2000-12-29 Kunihiro Ishiguro + + * configure.in: --enable-unixdomain becomes default. Add + --enable-tcp-zebra for TCP/IP communication between protocol + daemon and zebra. + + * COPYING.LIB: Added for lib/getopt.c, lib/getopt.h, + lib/getopt1.c, lib/md5-gnu.h, lib/md5.c, lib/regex-gnu.h, + lib/regex.c. + + * Makefile.am (dist-hook): Include tools/*.cgi to distribution. + +2000-12-26 Kunihiro Ishiguro + + * configure.in (MULTIPATH_NUM): --enable-multipath=ARG specify + multipath number. ARG must be digit. + +2000-12-11 Kunihiro Ishiguro + + * configure.in: Add --enable-newrib for test new RIB code. + +2000-11-25 Yasuhiro Ohara + + * configure.in, config.h.in: Add check for libutil.h and + setproctitle(). + +2000-10-26 Kunihiro Ishiguro + + * configure.in: Add --enable-nssa for OSPF NSSA option. + + * acconfig.h: Define HAVE_NSSA. + +2000-10-25 "Bjoern A. Zeeb" + + * configure.in: pam_misc is only linked when the platform is + GNU/Linux. + +2000-10-24 Arkadiusz Miskiewicz + + * configure.in (LIBS): Add check for crypto library. test x`ls + ${ac_snmp}` is replaced with sipmle test -f. + +2000-10-23 Kunihiro Ishiguro + + * configure.in: Add --enable-unixdomain option. This will be + default behavior in zebra-0.90. + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-09-27 Kunihiro Ishiguro + + * configure.in: Add check for Intel CPU for Solaris on x86 check. + +2000-09-21 Kunihiro Ishiguro + + * configure.in: Add check for getifaddrs(). + Set AM_INIT_AUTOMAKE version to 0.89. + +2000-09-14 Kunihiro Ishiguro + + * config.guess: Update to the latest version. + + * config.sub: Likewise + +2000-09-14 David Lipovkov + + * REPORTING-BUGS: New file is added. + +2000-08-27 itojun@iijlab.net + + * configure.in: Add ncurses library check when --enable-vtysh is + specified. + +2000-08-22 Kunihiro Ishiguro + + * configure.in: Add check for readline/history.h. + + * acconfig.h: Remove pthread related variables. + + * configure.in: Add --with-libpam option for vtysh PAM + authentication. Remove --disable-pthread because we don't support + pthread. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + + * configure.in: Add Solaris -lcurses for vtysh. + +2000-08-02 Kunihiro Ishiguro + + * configure.in: Add check for ncurses for compiling on Solaris. + +2000-07-27 Kunihiro Ishiguro + + * configure.in: Add check for libreadline when --enable-vtysh is + specified. + +2000-07-23 Kunihiro Ishiguro + + * configure.in: Add AC_DEFINE(OPEN_BSD). When OS is OpenBSD + interface method is if_ioctl.o + +2000-07-09 Chris Dunlop + + * acconfig.h: Add HAVE_BROKEN_ALIASES. + + * configure.in: Add --enable-broken-aliases. + +2000-06-12 Kunihiro Ishiguro + + * Set version to zebra-0.87. + +2000-06-05 Kunihiro Ishiguro + + * configure.in: Remove --enable-mpls-vpn. Now MPLS-VPN support is + default. + + * Set version to zebra-0.87-pre + + * Makefile.am: Likewise. + +2000-04-27 Kunihiro Ishiguro + + * Set version to 0.86. + +2000-03-21 Kunihiro Ishiguro + + * Set version to 0.85b for ospfd test. + +2000-03-20 Kunihiro Ishiguro + + * Set version to 0.85a for ospfd test. + +2000-03-08 Kunihiro Ishiguro + + * Set version to 0.85. + +2000-01-26 Kunihiro Ishiguro + + * Makefile.in: Regenerated by patched automake for fixing "make + clean" problem on FreeBSD. + +1999-12-08 Kunihiro Ishiguro + + * Set version to 0.83a. This is for *BSD static route lookup + problem. + +1999-12-06 Kunihiro Ishiguro + + * Set version to 0.83. + +1999-11-29 Kunihiro Ishiguro + + * Set version to 0.82. + +1999-11-23 Kunihiro Ishiguro + + * aczebra.m4: New file added. + +1999-11-21 Michael Handler + + * configure.in (LIBS): Add sa_len check of sockaddr. + + * acconfig.h: Add HAVE_SA_LEN. + +1999-11-12 Kunihiro Ishiguro + + * version.h: Update version to zebra-0.81b for bgpd test. + +1999-11-09 Kunihiro Ishiguro + + * configure.in: Add --enable-mbgp. + +1999-11-05 Kunihiro Ishiguro + + * Makefile.am (EXTRA_DIST): Add TODO to the distribution. + +1999-11-04 Kunihiro Ishiguro + + * TODO: New file is added. + +1999-11-03 Kunihiro Ishiguro + + * version.h: Update version to zebra-0.81a for ospfd test. + +1999-10-28 Kunihiro Ishiguro + + * configure.in: New option --enable-snmp is added. + +1999-10-24 Kunihiro Ishiguro + + * version.h: Update version to zebra-0.80. + +1999-10-21 Kunihiro Ishiguro + + * version.h: Update version to zebra-0.80-pre3 + +1999-10-18 Kunihiro Ishiguro + + * configure.in (LIBS): SNMP check is done by ucd-snmp/asn1.h. + +1999-10-10 Peter Galbavy + + * configure.in: Add support of OpenBSD. + +1999-10-04 Kunihiro Ishiguro + + * version.h: Update version to zebra-0.80-pre2. + +1999-09-27 Kunihiro Ishiguro + + * version.h: Update version to zebra-0.80-pre. From this version, + access-list and prefix-list's name space is divided into IPv4 and + IPv6. + +1999-09-17 Kunihiro Ishiguro + + * version.h: For test recent fixes Set version to zebra-0.79a. + +1999-09-14 Kunihiro Ishiguro + + * version.h: zebra-0.79 is out. + +1999-09-08 Kunihiro Ishiguro + + * version.h: For ospfd's virtual link test. Set version to 0.78h. + +1999-09-07 Kunihiro Ishiguro + + * version.h: For ospfd test. Set version to 0.78g. + +1999-09-05 Kunihiro Ishiguro + + * version.h: For internal test of ospfd. Set version to 0.78f. + +1999-09-02 Kunihiro Ishiguro + + * version.h: To test ospfd's fix, set version to 0.78e. + +1999-09-01 Kunihiro Ishiguro + + * version.h: To test ospfd's area related bug fix, set version + to 0.78d. + +1999-09-01 Kunihiro Ishiguro + + * version.h: To test ospfd, set version to 0.78c. + +1999-08-31 Janos Farkas + + * Many misspelling correction. + +1999-08-31 Kunihiro Ishiguro + + * version.h: To test ospfd, set version to 0.78b. + +1999-08-31 Kunihiro Ishiguro + + * configure.in (LIBS): Add UCD-SNMP include path check. + +1999-08-31 Lars Fenneberg + + * configure.in: The logic which detects the UCD-SNMP library + should first check in the default system locations for the library + and then in /usr/local. + +1999-08-27 itojun@iijlab.net + + * configure.in (LIBS): Fix problem about libsnmp.a check. + +1999-08-26 kay + + * configure.in (CFLAGS): Add to check socklen_t. + +1999-08-24 VOP + + * filter.c: Include "sockunion.h". + plist.c: Likewise. + table.c: Likewise. + +1999-08-24 Kunihiro Ishiguro + + * configure.in: Add netinet6/in6.h check. + +1999-08-21 Masaki Minami + + * BSD/OS 4.0 porting. + +1999-08-15 Kunihiro Ishiguro + + * configure.in: Add --enable-netlink option to force to use Linux + netlink interface. + (CFLAGS): Add ucd-snmp library check. + + * acconfig.h: If socklen_t is not defined, typedef int to + socklen_t. + +1999-08-15 Arkadiusz Miskiewicz + + * configure.in: When --enable-ipv6 specified, then only kernel + version is checked. + +1999-08-14 Kunihiro Ishiguro + + * configure.in: Add GNU libc 2.1 check. + +1999-08-02 Kunihiro Ishiguro + + * configure.in: Fix privious Linux IPv6 check changes. + +1999-08-02 Arkadiusz Miskiewicz + + * configure.in: Improve Linux IPv6 feature check. + +1999-07-29 Rick Payne + + * Changed route-maps to behave in a more cisco-like fashion + +1999-07-27 Gerhard Poul + + * SERVICES: New file added. + +1999-07-12 itojun@iijlab.net + + * configure.in: Add check for getaddrinfo. Improve Kame related + library check. + +1999-07-07 Yasuhiro Ohara + + * configure.in, acconfig.h: Add check for FreeBSD 3.2. + +1999-07-07 Kunihiro Ishiguro + + * configure.in: Delete check for netinet/ip6.h. + +1999-06-30 Gerhard Poul + + * README: remixed the old files and added some new parts. + moved some INSTALL stuff into INSTALL file. + moved some other stuff to doc/zebra.texi + +1999-06-29 Kunihiro Ishiguro + + * configure.in (LIBS): Add libresolv check. + Change --enabe-all-in-one option to --enable-one-vty. + +1999-06-20 Kunihiro Ishiguro + + * configure.in: Add --enabe-all-in-one option. + +1999-06-16 Kunihiro Ishiguro + + * configure.in: Add socklen_t check. + +1999-06-16 Gerhard Poul + + * Many compile warnings fixed. + +1999-05-31 Kunihiro Ishiguro + + * configure.in: Change message from Linux 2.2.X IPv6 to Linux IPv6. + OpenBSD (NRL) check is enabled. + +1999-05-30 Kunihiro Ishiguro + + * configure.in (LIBS): Add crypt library check. + +1999-05-08 Kunihiro Ishiguro + + * configure.in: Add sin6_scope_id in struct sockaddr_in6 check. + +1999-04-30 Kunihiro Ishiguro + + * Set version to 0.63 for first beta package. + +1999-04-15 Kunihiro Ishiguro + + * guile.m4: Added from guile package. + +1999-04-14 Kunihiro Ishiguro + + * Set version to 0.60 for beta package preparation. + +1999-04-12 Kunihiro Ishiguro + + * Makefile.am: Add noninst_LIBRARIES each directory's Makefile.am. + This change is for linking these libraries to guile. + +1999-04-08 Kunihiro Ishiguro + + * configure.in (LIBS): Add struct rt_addrinfo check. + +1999-04-07 Kunihiro Ishiguro + + * configure.in: AC_STDC_HEADERS added. + +1999-03-29 Kunihiro Ishiguro + + * Add dependencies to each directory's Makefile.am. + +1999-03-02 Peter Galbavy + + * reworked include file structure, and configure so that all + source files get all system-dependent include files by including + which is really lib/zebra.h. This means that the + different programs include files are now available as #include + "zebra/zebra.h" - note the use of quotes, not <> as delimiters. + + In practical terms, if I haven't really screwed up, the main file + that maintainers for other OSes have to change is lib/zebra.h for + all the conditional includes etc. + + * added --disable-pthread for those systems that seem to have + POSIX threads, but do not work. OpenBSD 2.4+ is like that just + now. Changed all occurance of #ifdef PTHREAD to use HAVE_PTHREAD + instead. + +1999-02-24 + + * configure.in: update to AC_PREREQ(1.13). + Change message from Linux 2.1.x to Linux 2.2.x. + * Added ospf6d directory support. + +1999-02-22 Peter Galbavy + + * added a "log" element to the BGPd peer structure, enabling us to + start thinging about a log stream per peer. This is currently + ignored by the wrapper code, but developers should try to use the + "appropriate" ZLOG stream. Documentation will follow, when the + real routines start to exist. + + The current plan is to use a copy of the BSD syslog() routines and + replace the syslog library function with our own. I will need + feedback from users of other platforms as this work is done to see + if all is well elsewhere. + + * preliminary work on zlog() library. directly replaces syslog() + currently with zlog(ZLOG *, ...) where the new first argument + is a pointer to a ZLOG structure (defined in lib/log.h) and will + encapsulate all the information necessary to maintain multiple + logging streams. + +1999-02-19 Peter Galbavy + + * added vsnprintf() macro to lib/str.h if required and removed + #ifdef SUNOS_5 dependency on it + +1999-02-18 Peter Galbavy + + * syslog support added + +1999-02-18 Peter Galbavy + + * configure.in: Add daemon function check. + +1999-01-21 Kunihiro Ishiguro + + * configure.in: Add --disable-ipv6, --disable-zebra, + --disable-bgpd, --disable-ripd, --disable-ripngd, --disable-ospfd + options to configure. + +1998-12-07 Kunihiro Ishiguro + + * configure.in: Check /usr/inet6/lib/libinet6.a exists or not. + +1998-10-14 Kunihiro Ishiguro + + * configure.in: Comment out FreeBSD's libc_r detect section. At + this moment it doesn't work correctly with zebra. + + Netlink interface is only enabled when Linux kernel version is + upper than 2.1.0. + +1998-09-15 HEO SeonMeyong + + * Hydrangea is now called KAME, so change all defines. + +1998-08-16 Kunihiro Ishiguro + + * configure.in: ifaliasreq check added. + +1998-08-12 Katsuhiro Kondou + + * Patch is applied for compile under EWS4800 + +1998-06-09 Kunihiro Ishiguro + + * configure.in: delete old mtu_method check. + + * doc/zebra.texi (Kernel interface): chapter `Kernel interface' added + +1998-06-08 Kunihiro Ishiguro + + * configure.in: add new netlink check for GNU/Linux + +1998-06-07 Kunihiro Ishiguro + + * doc/zebra.texi: Update Linux netlink chapter. + +1998-05-18 Yamashita TAKAO + + * config.h.in: define PTHREAD if work on Solaris 2.6 + why delete the definition? I miss? + +1998-05-08 Kunihiro Ishiguro + + * configure.in: add net/if.h header check. + +1998-05-02 SeonMeyong HEO + + * zebra.tex,archfig.tex,zebra.sty: Manual file is added. + * zebra.texi: Modify Introduction text. + * RIPngd.c: Patch Hydrangea code. + +1998-05-01 Kunihiro Ishiguro + + * .cvsignore: added. + + * Makerule.in: is gone. + * Makefile.am: Now we use automake to generate Makefile.in + +1998-03-19 Yamashita TAKAO + + * lib/vty.c: modified the definition of *master + * lib/sockunion.c (inet_aton): add, but don't work. uum... + + +1998-03-15 Yamashita TAKAO + + * configure.in: define PTHREAD if work on Solaris 2.6 + * config.h.in: likewise + * lib/thread.c: likewise + * lib/vty.c: likewise + +1998-03-15 SeonMeyong HEO + + * config.h.in: define INET6 if defined HAVE_IPV6 & HYDRANGEA + * bgpd/: remove include line. + * lib/: remove include line. + * ripbgd/: remove include line. + * zebra/: remove include line. + * ripd/*.c: remove include line. + undefine IPV6 difinitions because RIPd is not worked for + IPv6 protocol. + + +1998-01-30 Kunihiro Ishiguro + + * configure.in: Change routing socket check method from + AC_TRY_COMPILE to AC_TRY_RUN because GNU libc version 2 has + AF_ROUTE but over linux it's meenigless. + +1998-01-06 Kunihiro Ishiguro + + * config.h.in: remove err_t define. + +1997-11-18 Kunihiro Ishiguro + + * configure.in (canonical): add check of IF_METHOD + +1997-09-27 Kunihiro Ishiguro + + * configure.in: add INRIA check + +1997-09-25 Kunihiro Ishiguro + + * configure.in (canonical): change ipforward_snmp.o to ipforward_proc.o + +1997-09-12 Kunihiro Ishiguro + + * configure.in: change IRDPD to NDPD + +1997-08-18 Kunihiro Ishiguro + + * INSTALL: new file + +1997-08-14 Kunihiro Ishiguro + + * config.h: add XCALLOC() + diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..a2c8722 --- /dev/null +++ b/INSTALL @@ -0,0 +1,181 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..72a09dc --- /dev/null +++ b/Makefile.am @@ -0,0 +1,16 @@ +## Process this file with automake to produce Makefile.in. + +SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @VTYSH@ doc + +EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS vtysh/Makefile.in \ + vtysh/Makefile.am update-autotools + +dist-hook: + mkdir $(distdir)/tools + cp -p $(srcdir)/tools/*.pl $(distdir)/tools + cp -p $(srcdir)/tools/*.el $(distdir)/tools + cp -p $(srcdir)/tools/*.cgi $(distdir)/tools + mkdir $(distdir)/init + mkdir $(distdir)/init/redhat + cp -p $(srcdir)/init/redhat/*.init $(distdir)/init/redhat + cp -p $(srcdir)/init/redhat/zebra.* $(distdir)/init/redhat diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..d39fb51 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,460 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CPP = @CPP@ +CURSES = @CURSES@ +DEPDIR = @DEPDIR@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ +INCLUDES = @INCLUDES@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LIBPAM = @LIBPAM@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ + +SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @VTYSH@ doc + +EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS vtysh/Makefile.in \ + vtysh/Makefile.am update-autotools + +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = + +RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \ + uninstall-info-recursive all-recursive install-data-recursive \ + install-exec-recursive installdirs-recursive install-recursive \ + uninstall-recursive check-recursive installcheck-recursive +DIST_COMMON = README AUTHORS COPYING COPYING.LIB ChangeLog INSTALL \ + Makefile.am Makefile.in NEWS TODO aclocal.m4 config.guess \ + config.h.in config.sub configure configure.ac depcomp \ + install-sh missing mkinstalldirs +DIST_SUBDIRS = $(SUBDIRS) +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: + +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe) + +$(top_builddir)/config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck +$(srcdir)/configure: $(srcdir)/configure.ac $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +$(ACLOCAL_M4): configure.ac + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h + +$(srcdir)/config.h.in: $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOHEADER) + touch $(srcdir)/config.h.in + +distclean-hdr: + -rm -f config.h stamp-h1 +uninstall-info-am: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = . +distdir = $(PACKAGE)-$(VERSION) + +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } + +GZIP_ENV = --best +distcleancheck_listfiles = find . -type f -print + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + $(mkinstalldirs) $(distdir)/vtysh + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" \ + distdir=../$(distdir)/$$subdir \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="${top_distdir}" distdir="$(distdir)" \ + dist-hook + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist dist-all: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + $(am__remove_distdir) + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf - + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/=inst && pwd` \ + && cd $(distdir)/=build \ + && ../configure --srcdir=.. --prefix=$$dc_install_base \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && (test `find $$dc_install_base -type f -print | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + find $$dc_install_base -type f -print ; \ + exit 1; } >&2 ) \ + && $(MAKE) $(AM_MAKEFLAGS) dist-gzip \ + && rm -f $(distdir).tar.gz \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @echo "$(distdir).tar.gz is ready for distribution" | \ + sed 'h;s/./=/g;p;x;p;x' +distcleancheck: distclean + if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile config.h +installdirs: installdirs-recursive +installdirs-am: + +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) +distclean-am: clean-am distclean-generic distclean-hdr distclean-tags + +dvi: dvi-recursive + +dvi-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf autom4te.cache +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +uninstall-am: uninstall-info-am + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) GTAGS all all-am check check-am clean \ + clean-generic clean-recursive dist dist-all dist-gzip distcheck \ + distclean distclean-generic distclean-hdr distclean-recursive \ + distclean-tags distcleancheck distdir dvi dvi-am dvi-recursive \ + info info-am info-recursive install install-am install-data \ + install-data-am install-data-recursive install-exec \ + install-exec-am install-exec-recursive install-info \ + install-info-am install-info-recursive install-man \ + install-recursive install-strip installcheck installcheck-am \ + installdirs installdirs-am installdirs-recursive \ + maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-generic \ + mostlyclean-recursive tags tags-recursive uninstall \ + uninstall-am uninstall-info-am uninstall-info-recursive \ + uninstall-recursive + + +dist-hook: + mkdir $(distdir)/tools + cp -p $(srcdir)/tools/*.pl $(distdir)/tools + cp -p $(srcdir)/tools/*.el $(distdir)/tools + cp -p $(srcdir)/tools/*.cgi $(distdir)/tools + mkdir $(distdir)/init + mkdir $(distdir)/init/redhat + cp -p $(srcdir)/init/redhat/*.init $(distdir)/init/redhat + cp -p $(srcdir)/init/redhat/zebra.* $(distdir)/init/redhat +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..65ef352 --- /dev/null +++ b/NEWS @@ -0,0 +1,2423 @@ +GNU Zebra is not yet released, so this NEWS is about beta version. + +* Changes in zebra-0.95 + +* Changes in zebra + +** IRDP support is added. + +* Changes in ripd + +** Set receive UDP socket buffer to large value. + +* Changes in ospfd + +** Fix problem of OpenBSD-3.4 IP header length treatment. + +* Changes in ospf6d + +** Area support is added. + +* Changes in bgpd + +** Old commands are removed + +"show ipv6 summary" +"show ipv6 mbgp summary" + +** New ospf6d implementation is introduced. This is rewrite of whole + ospf6d code to make it far much better than old code. + +* Changes in vtysh + +** Many bugs and problems are fixed. All of user of vtysh should + update to zebra-0.95. + +* Changes in zebra-0.94 + +* Changes in zebra + +** Do not listen other process's netlink message. + +* Changes in bgpd + +** "bgp log-neighbor-changes" is added. + +** "set ip next-hop peer-address" is added. + +** Community delete bug is fixed. + +** Fix bug of router-id display + +** Option parameter length bug is fixed. + +* Chages in ospfd + +** Point-to-Multipoint support. + +** OSPF MD5 authentication bug is fixed. + +** OSPF NSSA bug is fixed. + +** NSM event schedule bug is fixed. + +** Update Opaque LSA patch. + +** When write queue becomes empty stop write timer. + +* Changes in ospf6d + +** Update to the latest Ohara's code. + +** DR election bug is fixed. + +** Update link-local address on interface creation + +* Changes in vtysh + +** Update for IPv6 handling + +** Make all protocol DEFUN/ALIAS consistent + +* Changes in lib + +** Fix route-map problem + +** Fix vty bug cause daemon crash. + +* Changes in zebra-0.93 + +* Changes in bgpd + +** Configuration is changed to new format. + +* Changes in ospfd + +** Crush bugs which reported on Zebra ML is fixed. + +** Opaque LSA and TE LSA support is added by KDD R&D Laboratories, + Inc. + +* Chages in ospf6d + +** Many bugs are fixed. + +* Changes in zebra-0.92a + +* Changes in bgpd + +** Fix "^$" community list bug. + +** Below command's Address Family specific configurations are added + + nexthop-self + route-reflector-client + route-server-client + soft-reconfiguration inbound + +* Changes in zebra + +** Treat kernel type routes as EGP routes. + +* Changes in zebra-0.92 + +** Overall security is improved. Default umask is 0077. + +* Changes in ripd + +** If output interface is in simple password authentication mode, +substruct one from rtemax. + +* Changes in bgpd + +** IPv4 multicast and IPv6 unicast configuration is changed to so +called new config. All of AFI and SAFI specific configuration is +moved to "address-family" node. When you have many IPv6 only +configuration, you will see many "no neighbor X:X::X:X activate" line +in your configuration to disable IPv4 unicast NLRI exchange. In that +case please use "no bgp default ipv4-unicast" command to suppress the +output. Until zebra-0.93, old config is still left for compatibility. + +Old config +========== +router bgp 7675 + bgp router-id 10.0.0.1 + redistribute connected + network 192.168.0.0/24 + neighbor 10.0.0.2 remote-as 7675 + ipv6 bgp network 3ffe:506::/33 + ipv6 bgp network 3ffe:1800:e800::/40 + ipv6 bgp aggregate-address 3ffe:506::/32 + ipv6 bgp redistribute connected + ipv6 bgp neighbor 3ffe:506:1000::2 remote-as 1 + +New config +========== +router bgp 7675 + bgp router-id 10.0.0.1 + network 192.168.0.0/24 + redistribute connected + neighbor 10.0.0.2 remote-as 7675 + neighbor 3ffe:506:1000::2 remote-as 1 + no neighbor 3ffe:506:1000::2 activate +! + address-family ipv6 + network 3ffe:506::/33 + network 3ffe:1800:e800::/40 + aggregate-address 3ffe:506::/32 + redistribute connected + neighbor 3ffe:506:1000::2 activate + exit-address-family + +* Changes in ospfd + +** Internal interface treatment is changed. Now ospfd can handle +multiple IP address for an interface. + +** Redistribution of loopback interface's address works fine. + +* Changes in zebra-0.91 + +** --enable-oldrib configure option is removed. + +** HAVE_IF_PSEUDO part is removed. Same feature is now supported by +default. + +* Changes in ripd + +** When redistributed route is withdrawn, perform poisoned reverse. + +* Changes in zebra + +** When interface's address is removed, kernel route pointing out to +the address is removed. + +** IPv6 RIB is now based upon new RIB code. + +** zebra can handle same connected route to one interface. + +** New command for interface address. Currently this commands are +only supported on GNU/Linux with netlink interface. + +"ip address A.B.C.D secondary" +"ip address A.B.C.D label LABEL" + +* Changes in bgpd + +** BGP flap dampening bugs are fixed. + +** BGP non-blocking TCP connection bug is fixed. + +** "show ip bgp summary" shows AS path and community entry number. + +** New commands have been added. + "show ip bgp cidr-only" + "show ip bgp ipv4 (unicast|multicast) cidr-only" + "show ip bgp A.B.C.D/M longer-prefixes" + "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes" + "show ipv6 bgp X:X::X:X/M longer-prefixes" + "show ipv6 mbgp X:X::X:X/M longer-prefixes" + +** IPv6 IBGP nexthop change is monitored. + +** Unknown transitive attribute is passed with partial flag bit on. + +* Changes in ospfd + +** Fix bug of LSA MaxAge flood. + +** Fix bug of NSSA codes. + +* Changes in zebra-0.90 + +** From this beta release, --enable-unixdomain and --enable-newrib +becomes default. So both options are removed from configure.in. To +revert old behavior please specify below option. + +--enable-tcp-zebra # TCP/IP socket is used for protocol daemon and zebra. +--enable-oldrib # Turn on old RIB implementation. + +Old RIB implementation will be removed in zebra-0.91. + +** From this beta release --enable-multipath is supported. This +option is only effective on GNU/Linux kernel with +CONFIG_IP_ADVANCED_ROUTER and CONFIG_IP_ROUTE_MULTIPATH is set. + +--enable-multipath=ARG # ARG must be digit. When ARG is 0 unlimit multipath number. + +** From this release we do not include guile files. + +* Changes in lib + +** newlist.[ch] is merged with linklist.[ch]. + +** Now Zebra works on MacOS X public beta. + +** Access-list can have remark. "access-list WORD remark LINE" define +remark for specified access-list. + +** Key of key-chain is sorted by it's idetifier value. + +** prefix-list rule is slightly changed. The rule of "len <= ge-value +<= le-value" is changed to "len < ge-value <= le-value". + +** According to above prefix-list rule change, add automatic +conversion function of an old rule. ex.) 10.0.0.0/8 ge 8 -> 10.0.0.0/8 +le 32 + +** SMUX can handle SNMP trap. + +** In our event library, event thread is executed before any other +thread like timer, read and write event. + +** Robust method for writing configuration file and recover from +backing up config file. + +** Display "end" at the end of configuration. + +** Fix memory leak in vtysh_read(). + +** Fix memroy leak about access-list and prefix-list name. + +* Changes in zebra + +** UNIX domain socket server of zebra protocol is added. + +** Fix PointoPoint interface network bug. The destination network +should be installed into routing table instead of local network. + +** Metric value is reflected to kernel routing table. + +** "show ip route" display uptime of RIP,OSPF,BGP routes. + +** New RIB implementation is added. + +Now we have enhanced RIB (routing information base) implementation in +zebra. New RIB has many new features and fixed some bugs which exist +in old RIB code. + +*** Static route with distance value + + Static route can be specified with administrative distance. The + distance value 255 means it is not installed into the kernel. + Default value of distance for static route is 1. + + ip route A.B.C.D/M A.B.C.D <1-255> + ip route A.B.C.D/M IFNAME <1-255> + + If the least distance value's route's nexthop are unreachable, + select the least distance value route which has reachable nexthop is + selected. + + ip route 0.0.0.0/0 10.0.0.1 + ip route 0.0.0.0/0 11.0.0.1 2 + + In this case, when 10.0.0.1 is unreachable and 11.0.0.1 is + reachable. The route with nexthop 11.0.0.1 will be installed into + forwarding table. + + zebra> show ip route + S>* 0.0.0.0/0 [2/0] via 11.0.0.1 + S 0.0.0.0/0 [1/0] via 10.0.0.1 inactive + + If the nexthop is unreachable "inactive" is displayed. You can + specify any string to IFNAME. There is no need of the interface is + there when you configure the route. + + ip route 1.1.1.1/32 ppp0 + + When ppp0 comes up, the route is installed properly. + +*** Multiple nexthop routes for one prefix + + Multiple nexthop routes can be specified for one prefix. Even the + kernel support only one nexthop for one prefix user can configure + multiple nexthop. + + When you configure routes like below, prefix 10.0.0.1 has three + nexthop. + + ip route 10.0.0.1/32 10.0.0.2 + ip route 10.0.0.1/32 10.0.0.3 + ip route 10.0.0.1/32 eth0 + + If there is no route to 10.0.0.2 and 10.0.0.3. And interface eth0 + is reachable, then the last route is installed into the kernel. + + zebra> show ip route + S> 10.0.0.1/32 [1/0] via 10.0.0.2 inactive + via 10.0.0.3 inactive + * is directly connected, eth0 + + '*' means this nexthop is installed into the kernel. + +*** Multipath (more than one nexthop for one prefix) can be installed into the kernel. + + When the kernel support multipath, zebra can install multipath + routes into the kernel. Before doing that please make it sure that + setting --enable-multipath=ARG to configure script. ARG must be digit + value. When specify 0 to ARG, there is no limitation of the number + of the multipath. Currently only GNU/Linux with netlink interface is + supported. + + ip route 10.0.0.1/32 10.0.0.2 + ip route 10.0.0.1/32 10.0.0.3 + ip route 10.0.0.1/32 eth0 + + zebra> show ip route + S>* 10.0.0.1/32 [1/0] via 10.0.0.2 + * via 10.0.0.3 + is directly connected, eth0 + +*** Kernel message delete installed route. + + After zebra install static or dynamic route into the kernel. + + R>* 0.0.0.0/0 [120/3] via 10.0.0.1 + + If you delete this route outside zebra, old zebra does not reinstall + route again. Now the route is re-processed and properly reinstall the + static or dynamic route into the kernel. + +** GNU/Linux netlink socket handling is improved to fix race condition +between kernel message and user command responce. + +* Changes in bgpd + +** Add show neighbor's routes command. + + "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes" + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes" + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes" + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes" + +** BGP passive peer support problem is fixed. + +** Redistributed IGP nexthop is passed to BGP nexthop. + +** On multiaccess media, if the nexthop is reachable nexthop is passed +as it is. + +** Remove zebra-0.88 compatibility commands. + + "match ip prefix-list WORD" + "match ipv6 prefix-list WORD" + + Instead of above please use below commands. + + "match ip address prefix-list WORD" + "match ipv6 address prefix-list WORD" + +** Fix bug of holdtimer is not reset when bgp cleared. + +** "show ip bgp summary" display peer establish/drop count. + +** Change "match ip next-hop" argument from IP address to access-list +name. + +** When "bgp enforce-first-as" is enabled, check EBGP peer's update +has it's AS number in the first AS number in AS sequence. + +** New route-map command "set community-delete COMMUNITY-LIST" is +added. Community matched the CoMMUNITY-LIST is removed from the +community. + +** BGP-MIB implementation is finished. + +** When BGP connection comes from unconfigured IP address, close +socket immediately. + +** Do not compare router ID when the routes comes from EBGP peer. +When originator ID is same, take shorter cluster-list route. If +cluster-list is same take smaller IP address neighbor's route. + +** Add "bgp bestpath as-path ignore" command. When this option is +set, do not concider AS path length when route selection. + +** Add "bgp bestpath compare-routerid". When this option is set, +compare router ID when the routes comes from EBGP peer. + +** Add "bgp deterministic-med" process. + +** BGP flap dampening feature is added. + +** When IBGP nexthop is changed, it is reflected to RIB. + +** Change "neighbor route-refresh" command to "neighbor capability +route-refresh". + +* Changes in ripd + +** Change "match ip next-hop" argument from IP address to access-list +name. + +** "no ip rip (send|receive)" command accept version number argument. + +** Memory leak related classfull network generation is fixed. + +** When a route is in garbage collection process (invalid with metric +16) and a router receives the same route with valid metric then route +was not installed into zebra rib, but only into ripd rib. Moreover , +it will never get into zebra rib, because ripd wrongly assumes it's +already there. + +* Change in ospfd + +** Fix bug of refreshing default route. + +** --enable-nssa turn on undergoing NSSA feature. + +** Fix bug of Hello packet's option is not properly set when interface +comes up. + +** Reduce unconditional logging. + +** Add nexthop to OSPF path only when it is not there. + +** When there is no DR on network (suppose you have only one router +with interface priority 0). It's router LSA does not contain the link +information about this network. + +** When you change a priority of interface from/to 0 +ISM_NeighborChange event should be scheduled in order to elect new +DR/BDR on the network. + +** When we add some LSA into retransmit list we need to check whether +the present old LSA in retransmit list is not more recent than the new +one. + +** In states Loading and Full the slave must resend its last Database +Description packet in response to duplicate Database Description +packets received from the master. For this reason the slave must wait +RouterDeadInterval seconds before freeing the last Database +Description packet. Reception of a Database Description packet from +the master after this interval will generate a SeqNumberMismatch +neighbor event. RFC2328 Section 10.8 + +** Virtual link can not configured in stub area. + +** Clear a ls_upd_queue queue of the interface when interface goes +down. + +** "no router ospf" unregister redistribution requests from zebra. + +** New command for virtual-link configuration is added. + + "area A.B.C.D virtual-link A.B.C.D" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535>" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> authentication-key AUTH_KEY" + "area A.B.C.D virtual-link A.B.C.D authentication-key AUTH_KEY" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> message-digest-key <1-255> md5 KEY" + "area A.B.C.D virtual-link A.B.C.D message-digest-key <1-255> md5 KEY" + +** Clear cryptographic sequence number when neighbor status is changed +to NSM down. + +** Make Summary LSA's origination and refreshment as same as other +type of LSA. + +** New OSPF pakcet read method. Now maximum packet length may be 65535 +bytes (maximum IP packet length). + +** Checking the age of the found LSA and if the LSA is MAXAGE we +should call refresh instead of originate. + +** Install multipath information to zebra. + +** Fix socket descriptor leak when system call failed. + +* Changes in ospf6d + +** Whole functionality has been rewritten as new code. new command +"show ipv6 ospf6 spf node", "show ipv6 ospf6 spf tree", "show ipv6 +ospf6 spf table" has been added. + +** Change to do not send garbage route whose nexthop is not linklocal +address. + +** "redistribute ospf6" was generated in "router ospf6" in config +file. It is fixed. + +** LSDB sync bug is fixed. + +** Fix bug of using unavailable route. + +* Changes in vtysh + +** route-map and access-list configuration is merged into one +configuration. + +** /usr/local/etc/Zebra.conf is integrated configuration file. "write +memory" in vtysh will write whole configuration to this file. + +** When -b option is specified to vtysh, vtysh read +/usr/local/etc/Zebra.conf file then pass the confuguration to proper +protocol daemon. So make all protocol daemon's configuration file +empty then invoke all daemon. After that vtysh -b will setup saved +configuration. + +zebrastart.sh +============= +/usr/local/sbin/zebra -d +/usr/local/sbin/ripd -d +/usr/local/sbin/ospfd -d +/usr/local/sbin/bgpd -d +/usr/local/bin/vtysh -b + +* Changes in zebra-0.89 + +* Changes in lib + +** distribute-list can set all interface's access-list and prefix-list +configuration. + +* Changes in ripd + +** "show ip protocols" display proper distribute-list settings and +distance settings. + +** When metric infinity route received withdraw the route from kernel +immediately it used to be wait garbage collection. + +** key-chain can be used for simple password authentication. + +** RIPv2 MIB getnext interface bug is fixed. + +* Changes in vtysh + +** --with-libpam enable PAM authentication for vtysh. + +** Now vtysh read vtysh.conf. This file should be +${SYSCONFDIR}/etc/vtysh.conf for security reason. Usually it is +/usr/local/etc/vtysh.conf. + +** "username WORD nopassword" command is added to vtysh. + +* Chagees in ospfd + +** NBMA interface support is added. + +** OSPF area is sorted by area ID. + +** New implementation of OSPF refreesh. + +** OSPF-MIB read function is partly added. + +* Changes in bgpd + +** When the peering is done by ebgp-multihop, nexthop is looked up +like IBGP routes. + +** "show ip mbgp" commands are changed to "show ip bgp ipv4 +multicast". + +** New terminal commands are added. + "show ip bgp ipv4 (unicast|multicast) filter-list WORD" + "show ip bgp ipv4 (unicast|multicast) community" + "show ip bgp ipv4 (unicast|multicast) community-list WORD" + "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match" + +** MBGP soft-reconfiguration command is added. + "clear ip bgp x.x.x.x ipv4 (unicast|multicast) in" + "clear ip bgp x.x.x.x ipv4 (unicast|multicast) out" + "clear ip bgp x.x.x.x ipv4 (unicast|multicast) soft" + "clear ip bgp <1-65535> ipv4 (unicast|multicast) in" + "clear ip bgp <1-65535> ipv4 (unicast|multicast) out" + "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft" + "clear ip bgp * ipv4 (unicast|multicast) in" + "clear ip bgp * ipv4 (unicast|multicast) out" + "clear ip bgp * ipv4 (unicast|multicast) soft" + +** MED related commands are added. + "bgp deterministic-med" + "bgp bestpath med confed" + "bgp bestpath med missing-as-worst" + +** "bgp default local-preference" command is added. + +** BGP confederation peer's routes are passed to zebra like IBGP route. + +** Community match command is added. + "show ip bgp community " + "show ip bgp community exact-match" + +** EBGP multihop route treatment bug is fixed. Now nexthop is +resolved by IGP routes. + +** Some commands are added to show routes by filter-list and community +value. + "show ip bgp ipv4 (unicast|multicast) filter-list WORD" + "show ip bgp ipv4 (unicast|multicast) community" + "show ip bgp ipv4 (unicast|multicast) community-list WORD" + "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match" + +* Changes in zebra + +** zebra read interface's address information using getifaddrs() when +it is available. + +** Reflect IPv6 interface's address change to protocol daemons. + +* Changes in zebra-0.88 + +* Changes in lib + +** "exact-match" option is added to "access-list" and "ipv6 +access-list" command. If this option is specified, the prefix and +prefix length is compared as exact match mode. + +* Changes in zebra + +** New Zebra message ZEBRA_REDISTRIBUTE_DEFAULT_ADD and +ZEBRA_REDISTRIBUTE_DEFAULT_DELTE are added. + +** Default administrative distance value is changed. + + Old New +------------------------------------------ +system 10 0 +kernel 20 0 +connected 30 0 +static 40 1 +rip 50 120 +ripng 50 120 +ospf 60 110 +ospf6 49 110 +bgp 70 200(iBGP) 20(eBGP) +------------------------------------------ + +** Distance value can be passed from protocol daemon to zebra. + +** "show ip route" shows [metric/distance] value pair. + +** Zebra Protocol is changed to support multi-path route and distance +value. + +* Changes in ospfd + +** "default-information originate [always]" command is added. + +** "default-metric <0-16777214>" command is added. + +** "show ip ospf database" command is integrated. LS-ID and AdvRouter can + be specifed. The commands are + + show ip ospf database TYPE LS-ID + show ip ospf database TYPE LS-ID ADV-ROUTER + show ip ospf database TYPE LS-ID self-originate + show ip ospf database TYPE self-originate + +** route-map support for `redistribute' command are added. + Supported `match' statements are + + match interface + match ip address + match next-hop + + Supported `set' statements are + + set metric + set metric-type + +** Pass OSPF metric value to zebra daemon. + +* Changes in ripd + +** When specified route-map does not exist, it means all deny. + +** "default-metric <1-16>" command is added. + +** "offset-list ACCESS-LIST-NAME <0-16>" and "offset-list +ACCESS-LIST-NAME <0-16> IFNAME" commands are added. + +** "redistribute ROUTE-TYPE metric <0-16>" command is added. + +** "default-information originate" command is added. + +** "ip split-horizon" and "no ip split-horizon" is added to interface +configuration. + +** "no router rip" command is added. + +** "ip rip authentication mode (md5|text)" is added to interface +configuration. + +** "ip rip authentication key-chain KEY-CHAIN" is added to interface +configuration. + +** Pass RIP metric value to zebra daemon. + +** Distance manipulation functions are added. + +* Changes in bgpd + +** Fix bug of next hop treatment for MPLS-VPN route exchange. + +** BGP peer MIB is updated. + +** Aggregated route has origin IGP, atomic-aggregate and proper +aggregator attribute. + +** Suppressed route now installed into BGP table. It is only +suppressed from announcement. + +** BGP router-id is properly set after "no router bgp ASN" and "router +bgp ASN". + +** Add check for nexthop is accessible or not for IBGP routes. + +** Add cehck for nexthop is on connected or not for EBGP routes. + +** "dump bgp route" command is changed to "dump bgp route-mrt" for +generating MRT compatible dump output. + +** Soft reconfiguration inbound and outbound is supported. + +** Route refresh feature is supported. + +* Changes in vtysh + +** VTY shell is now included into the distribution. + +* Changes in zebra-0.87 + +* Changes in lib + +** "show startup-config" command is added. + +** "show history" command is added. + +** Memory statistics command is changed. New command + + show memory all + show memory lib + show memory rip + show memory ospf + show memory bgp + +are added. + +** Filters can be removed only specify it's name. New command + + no access-list NAME + no ip community-list NAME + no ip as-path access-list NAME + no route-map NAME + +are added. + +** At any node, user can view/save user configuration. + + write terminal + write file + wirte memory + +are added to every node in default. + +** LCD completion is added. For example both "ip" and "ipv6" command +are exist, "i" then press TAB will be expanded to "ip". + +* Changes in bgpd + +** "show ip bgp" family shows total number of prefixes. + +** "no bgp default ipv4-unicast" command is added. + +** Extended Communities support is added. + +** "no neighbor PEER send-community extended" command is added. + +** MPLS-VPN PE-RR support is added. + + New address family vpnv4 unicast is introduced. + + ! + address-family vpnv4 unicast + neighobr PEER activate + network A.B.C.D rd RD tag TAG + exit-address-family + ! + + To make it route-reflector, please configure it under normal router +bgp ASN. + + ! + router bgp 7675 + no bgp default ipv4-unicast + bgp router-id 10.0.0.100 + bgp cluster-id 10.0.0.100 + neighbor 10.0.0.1 remote-as 65535 + neighbor 10.0.0.1 route-reflector-client + neighbor 10.0.0.2 remote-as 65535 + neighbor 10.0.0.2 route-reflector-client + neighbor 10.0.0.3 remote-as 65535 + neighbor 10.0.0.3 route-reflector-client + ! + address-family vpnv4 unicast + neighbor 10.0.0.1 activate + neighbor 10.0.0.2 activate + neighbor 10.0.0.3 activate + exit-address-family + ! + +* Changes in ospfd + +** Many many bugs are fixed. + +* Changes in ripd + +** Better interface up/down event handle. + +* Changes in zebra + +** Better interface up/down event handle. + +* Changes in zebra-0.86 + +* Changes in lib + +** Fix bug of exec-timeout command which may cause crush. + +** Multiple same policy for "access-list", "ip prefix-list, "as-path +access-list", "ip community-list" is not duplicated. + +** It used to be "ip prefix-list A.B.C.D/M" match routes which mask >= +M. Now default behavior is exact match so it only match routes which +mask == M. + +* Changes in bgpd + +** "match ip address prefix-list" is added to route-map. + +** A route without local preference is evaluated as 100 local preference. + +** Select smaller router-id route when other values are same. + +** Compare MED only both routes comes from same neighboring AS. + +** "bgp always-compare-med" command is added. + +** Now MED value is passed to IBGP peer. + +** When neighbor's filter is configured with non-existent access-list, +as-path access-list, ip prefix-list, route-map. The behavior is +changed from all permit to all deny. + +* Changes in ospfd + +** Fix bug of external route tag byte order. + +** OSPF Neighbor deletion bug which cause crush is fixed. + +** Some route calculation bug are fixed. + +** Add sanity check with router routing table. + +** Fix bug of memory leak about linklist. + +** Fix bug of 1-WayReceived in NSM. + +** Take care of BIGENDIAN architecture. + +** Fix bug of NSM state flapping between ExStart and Exchange. + +** Fix bug of Network-LSA originated in stub network. + +** Fix bug of MS flag unset. + +** Add to schedule router_lsa origination when the interface cost +changes. + +** Increment LS age by configured interface transmit_delay. + +** distribute-list is reimplemented. + +** Fix bug of refresh never occurs. + +** Fix bug of summary-LSAs reorigination. Correctly copy +OSPF_LSA_APPROVED flag to new LSA. when summary-LSA is reoriginatd. + +** Fix bug of re-origination when a neighbor disappears. + +** Fix bug of segmentation fault with DD retransmission. + +** Fix network-LSA re-origination problem. + +** Fix problem of remaining withdrawn routes on zebra. + +* Changes in ripd + +** Do not leave from multicast group when interface goes down bug is +fixed. + +* Changes in zebra + +** Remove client structure when client dies. + +** Take care static route when interface goes up/down. + +* Changes in zebra-0.85 + +* Changes in bgpd + +** "transparent-nexthop" and "transparenet-as" commands are added. + +** Route reflector's originator-id bug is fixed. + +* Changes in ospfd + +** Fix bug of OSPF LSA memory leak. + +** Fix bug of OSPF external route memory leak. + +** AS-external-LSA origination bug was fixed. + +** LS request treatment is completely rewritten. Now performance is +drastically improved. + +* Changes in ripd + +** RIPv1 update is done by class-full manner. + +* Changes in zebra-0.84b + +* Changes in lib + +** Fix bug of inet_pton return value handling + +* Changes in bgpd + +** Fix bug of BGP-4+ link-local address nexthop check for IBGP peer. + +** Don't allocate whole buffer for displaying "show ip bgp". Now it +consume only one screen size memory. + +* Changes in ripd + +** Fix debug output string. + +** Add RIP peer handling. RIP peer are shown by "show ip protocols". + +* Changes in zebra-0.84a + +* Changes in bgpd + +** Fix serious bug of BGP-4+ peering under IPv6 link-local address. + Due to the bug BGP-4+ peering may not be established. + +* Changes in zebra-0.84 + +* Changes in lib + +** IPv6 address and prefix parser is added to VTY by Toshiaki Takada + . DEFUN string is "X:X::X:X" for IPv6 address, + "X:X::X:X/M" for IPv6 prefix. You can use it like this. + + DEFUN (func, cmd, "neighbor (A.B.C.D|X:X::X:X) remote-as <1-65535>") + +** VTY configuration is locked during configuration. This is for + avoiding unconditional crush from two terminals modify the + configuration at the same time. "who" command shows which termnal + lock the configuration. VTY which has '*' character at the head of + line is locking the configuration. + +** Old logging functions are removed. Functions like + log_open,log_close,openlog are deleted. Instead of that please use + zlog_* functions. zvlog_* used in ospf6d are deleted also. + +** "terminal monitor" command is added. "no terminal monitor" is for + disabling. This command simply display logging information to the + VTY. + +** dropline.[ch] files are deleted. + +* Changes in bgpd + +** BGP neighbor configuration are sorted by it's IP address. + +** BGP peer configuration and actual peer is separated. This is + preparation for Route Server support. + +** "no neighbor PEER" command is added. You can delete neighbor + without specifying AS number. + +** "no neighbor ebgp-multihop" command is added. + +** "no neighbor port PORT" command is added. + +** To conform RFC1771, "neighbor PEER send-community" is default + behavior. If you want to disable sending community attribute, + please specify "no neighbor PEER send-community" to the peer. + +** "neighbor maximum-prefix NUMBER" command is added. + +** Multi-protocol extention NLRI is proceeded only when the peer is + configured proper Address Family and Subsequent Address Family. If + not, those NLRI are simply ignored. + +** Aggregate-address support is improved. Currently below commands + works. + + "aggregate-address" + "aggregate-address summary-only" + "no aggregate-address" + "no aggregate-address summary-only" + + "ipv6 bgp aggregate-address" + "ipv6 bgp aggregate-address summary-only" + "no ipv6 bgp aggregate-address" + "no ipv6 bgp aggregate-address summary-only" + +** redistribute route-map bug is fixed. + +** MBGP support becomes default. "configure" option --enable-mbgp is + removed. + +** New command "neighbor PEER timers connect <1-65535>" is added. + +** New command "neighbor PEER override-capability" is added. + +** New command "show ip bgp neighbor A.B.C.D advertised-route" is added. + +** New command "show ip bgp neighbor A.B.C.D routes" is added. To use + this command, you have to configure neighbor with + "neighbor A.B.C.D soft-reconfiguration inbound" beforehand. + + +* Changes in zebra-0.83 + +* bgpd + +** Serious bug fix about fetching global and link-local address at the +same time. Due to this bug, corrupted IPv6 prefix is generated. If +you uses bgpd for BGP-4+ please update to this version. The bug is +introduced in zebra-0.82. + +** When bgpd send Notify message, don't use thread manager. It is now +send to neighbor immediately. + +* Changes in zebra-0.82 + +** Solaris 2.6 support is added by Michael Handler +. + +** MBGP support is added by Robert Olsson . +Please specify --enable-mbgp to configure script. This option will be +removed in the future and MBGP support will be default. + +* Changes in zebra + +** When interface goes down, withdraw connected routes from routing +table. When interface goes up, restore the routes to the routing +table. + +** `show interface' show interface's statistics on Linux and BSD with +routing socket. + +** Now zebra can get MTU value on BSDI/OS. + +* Changes in bgpd + +** Add capability option support based upon +draft-ietf-idr-bgp4-cap-neg-04.txt. + +** Add `show ipv6 bgp prefix-list' command. + +** Check self AS appeared in received routes. + +** redistribute route-map support is added. + +** BGP packet dump feature compatible with MRT. + +* Changes in ripd + +** Fix bug of `timers basic' command's argument format. + +* Changes in ripngd + +** Calculate max RTE using interface's MTU value. + +* Changes in ospfd + +** Some correction to LSU processing. + +** Add check for lsa->refresh_list. + +* Changes in ospf6d + +** Many debug feature is added. + +* Changes in zebra-0.81 + +** SNMP support is disabled in default.--enable-snmp option is added +to configure script. + +* Changes in bgpd + +** Fix FSM bug which introduced in zebra-0.80. + +* Changes in zebra-0.80 + +* access-list + + New access-list name space `ipv6 access-list' is added. At the same + time, `access-list' statemant only accepts IPv4 prefix. Please be + careful if you use IPv6 filtering. You will need to change your + configuration. For IPv6 filtering please use `ipv6 access-list'. + + As of zebra-0.7x, user can use `access-list' for both IPv4 and IPv6 + filtering. + + ! zebra-0.7x + access-list DML-net permit 203.181.89.0/24 + access-list DML-net permit 3ffe:506::0/32 + access-list DML-net deny any + ! + + Above configuration is not valid for zebra-08x. Please add `ipv6' + before 'access-list' when you configure IPv6 filtering. + + ! zebra-0.8x + access-list DML-net permit 203.181.89.0/24 + access-list DML-net deny any + ! + ipv6 access-list DML-net permit 3ffe:506::0/32 + ipv6 access-list DML-net deny any + ! + +* prefix-list + + And also new prefix-list name space `ipv6 prefix-list' is added. It + is the same as the change of `access-list'. `ip prefix-list' now only + accept IPv4 prefix. It was source of confusion that `ip prefix-list' + can be used both IPv4 and IPv6 filtering. Now name space is separated + to clear the meaning of the filter. + + If you use `ip prefix-list' for IPv6 filtering, please change the + stetement. + + ! zebra-0.7x + ip prefix-list 6bone-filter seq 5 permit 3ffe::/17 le 24 ge 24 + ip prefix-list 6bone-filter seq 10 permit 3ffe:8000::/17 le 28 ge 28 + ip prefix-list 6bone-filter seq 12 deny 3ffe::/16 + ip prefix-list 6bone-filter seq 15 permit 2000::/3 le 16 ge 16 + ip prefix-list 6bone-filter seq 20 permit 2001::/16 le 35 ge 35 + ip prefix-list 6bone-filter seq 30 deny any + ! + + Now user can explicitly configure it as IPv6 prefix-list. + + ! zebra-0.8x + ipv6 prefix-list 6bone-filter seq 5 permit 3ffe::/17 le 24 ge 24 + ipv6 prefix-list 6bone-filter seq 10 permit 3ffe:8000::/17 le 28 ge 28 + ipv6 prefix-list 6bone-filter seq 12 deny 3ffe::/16 + ipv6 prefix-list 6bone-filter seq 15 permit 2000::/3 le 16 ge 16 + ipv6 prefix-list 6bone-filter seq 20 permit 2001::/16 le 35 ge 35 + ipv6 prefix-list 6bone-filter seq 30 deny any + ! + +* RIP configuration + + If you want to filter only default route (0.0.0.0/0) and permit other + routes, it was hard to do that. Now `ip prefix-list' can be used for + RIP route filtering. + + New statement: + + `distribute-list prefix PLIST_NAME (in|out) IFNAME' + + is added to ripd. So you can configure on eth0 interface accept all + routes other than default routes. + + ! + router rip + distribute-list prefix filter-default in eth0 + ! + ip prefix-list filter-default deny 0.0.0.0/0 le 0 + ip prefix-list filter-default permit any + ! + +* RIPng configuration + + Same change is done for ripngd. You can use `ipv6 prefix-list' for + filtering. + + ! + router ripng + distribute-list prefix filter-default in eth0 + ! + ipv6 prefix-list filter-default deny ::/0 le 0 + ipv6 prefix-list filter-default permit any + ! + +* BGP configuration + + So far, Multiprotocol Extensions for BGP-4 (RFC2283) configuration is + done with traditional IPv4 peering statement like blow. + + ! + router bgp 7675 + neighbor 3ffe:506::1 remote-as 2500 + neighbor 3ffe:506::1 prefix-list 6bone-filter out + ! + + For separating configuration IPv4 and IPv6, and for retaining Cisco + configuration compatibility, now IPv6 configuration is done by IPv6 + specific statement. IPv6 BGP configuration is done by statement which + start from `ipv6 bgp'. + + ! + router bgp 7675 + ! + ipv6 bgp neighbor 3ffe:506::1 remote-as 2500 + ipv6 bgp neighbor 3ffe:506::1 prefix-list 6bone-filter out + ! + + At the same time some IPv6 specific commands are deleted from IPv4 + configuration. + + o redistribute ripng + o redistribute ospf6 + o neighbor PEER version BGP_VERSION + o neighbor PEER interface IFNAME + + Those commands are only accepted as like below. + + o ipv6 bgp redistribute ripng + o ipv6 bgp redistribute ospf6 + o ipv6 bgp neighbor PEER version BGP_VERSION + o ipv6 bgp neighbor PEER interface IFNAME + + And below new commands are added. + + o ipv6 bgp network IPV6_PREFIX + o ipv6 bgp redistribute static + o ipv6 bgp redistribute connected + o ipv6 bgp neighbor PEER remote-as <1-65535> [passive] + o ipv6 bgp neighbor PEER ebgp-multihop [TTL] + o ipv6 bgp neighbor PEER description DESCRIPTION + o ipv6 bgp neighbor PEER shutdown + o ipv6 bgp neighbor PEER route-reflector-client + o ipv6 bgp neighbor PEER update-source IFNAME + o ipv6 bgp neighbor PEER next-hop-self + o ipv6 bgp neighbor PEER timers holdtime <0-65535> + o ipv6 bgp neighbor PEER timers keepalive <0-65535> + o ipv6 bgp neighbor PEER send-community + o ipv6 bgp neighbor PEER weight <0-65535> + o ipv6 bgp neighbor PEER default-originate + o ipv6 bgp neighbor PEER filter-list FILTER_LIST_NAME (in|out) + o ipv6 bgp neighbor PEER prefix-list PREFIX_LIST_NAME (in|out) + o ipv6 bgp neighbor PEER distribute-list AS_LIST_NAME (in|out) + o ipv6 bgp neighbor PEER route-map ROUTE_MAP_NAME (in|out) + + And some utility commands are introduced. + + o clear ipv6 bgp [PEER] + o show ipv6 bgp neighbors [PEER] + o show ipv6 bgp summary + + I hope these changes are easy to understand for current Zebra users... + +* To restrict connection to VTY interface. + + It used to be both IPv4 and IPv6 filter can be specified with one + access-list. Then the access-list can be appried to VTY interface + with `access-class' stetement in `line vty' node. Below is example in + zebra-0.7x. + + ! + access-list local-only permit 127.0.0.1/32 + access-list local-only permit ::1/128 + access-list local-only deny any + ! + line vty + access-class local-only + ! + + Now IPv4 and IPv6 filter have each name space. It is not possible to + specify IPv4 and IPv6 filter with one access-list. For setting IPv6 + access-list in `line vty', `ipv6 access-class' statement is + introduced. Let me show the configuration in zebra-0.8x. + + ! + access-list local-only permit 127.0.0.1/32 + access-list local-only deny any + ! + ipv6 access-list local-only permit ::1/128 + ipv6 access-list local-only dny any + ! + line vty + access-class local-only + ipv6 access-class local-only + ! + +* route-map + + New IPv6 related route-map match commands are added. + + o match ipv6 address + o match ipv6 next-hop + + Please change your configuration if you use IP match statement for + IPv6 route. + + zebra-0.7x config + ================= + ! + access-list all permit any + ! + route-map set-nexthop permit 10 + match ip address all + set ipv6 next-hop global 3ffe:506::1 + set ipv6 next-hop local fe80::cbb5:591a + ! + + zebra-0.8x config + ================= + ! + ipv6 access-list all permit any + ! + route-map set-nexthop permit 10 + match ipv6 address all + set ipv6 next-hop global 3ffe:506::1 + set ipv6 next-hop local fe80::cbb5:591a + ! + +* zebra connection + + Protocol daemon such as ripd, bgpd, ospfd will reconnect zebra daemon + when the connection fail. Those daemons try to connect zebra every 10 + seconds first three trial, then the interval changed to 60 seconds. + After all, if ten connections are fail, protocol daemon give up the + connection to the zebra daemon. + +* SNMP support (is not yet finished) + + Zebra uses SMUX protocol (RFC1227) for making communication with SNMP + agent. Currently lib/smux.c can be compiled only with ucd-snmp-4.0.1 + and http://ucd-snmp.ucdavis.edu/patches/012.patch. It can not be + compiled with ucd-snmp-3.6.2. + + After applying the patch to ucd-snmp-4.0.1, please configure it with + SMUX module. + + % configure --with-mib-modules=smux + + After compile & install ucd-snmp-4.0.1, you will need to configure + smuxpeer. I'm now using below configuration. + + /usr/local/share/snmp/snmpd.conf + ================================ + smuxpeer 1.3.6.1.6.3.1 test + + Above 1.3.6.1.6.3.1 and test is temporary configuration which is hard + coded in lib/smux.c. Yes, I know it is bad, I'll change it ASAP. + +* HUP signal treatment + + From zebra-0.80, ripd will reload it's configuration file when ripd + receives HUP signal. Other daemon such as bgpd, ospfd will support + HUP signal treatment soon. + +* Changes in zebra-0.79 + +* Changes in zebra + +** Broadcast address setting on Linux box bug is fixed. + +** Protocol daemon can install connected IPv6 route into the kernel. + +** Now zebra can handle blackhole route. + +* Changes in ripd + +** Add route-map feature for RIP protocol. + +** In case of RIP version 2 routing table entry has IPv4 address and +netmask pair which host part bit is on, ignore the entry. + +* Changes in ripngd + +** Change CMSG_DATA cast from (u_char *) to (int *). (u_char *) does +not work for NetBSD-currnet on SparcStation 10. + +* Changes in ospfd + +** MaxAge LSA treatment is added. + +** ABR/ASBR functionality is added. + +** Virtual Link funtionality is added. + +** ABR behaviors IBM/Cisco/Shortcut is added. + +* Changes in ospf6d + +** Enclosed KAME specific part with #ifdef #endif + +* Changes in zebra-0.78 + +* Changes in lib + +** SNMP support is started. + +** Now Zebra can work on BSD/OS 4.X. + +** Now Zebra can compiled on vanilla OpenBSD 2.5 but not yet working correcltly. + +* Changes in zebra + +** Interface index detection using ioctl() bug is fixed. + +** Interface information protocol is changed. Now interface +addition/deletion and interface's address addition/deletion is +separated. + +* Changes in bgpd + +** BGP hold timer bug is fixed. + +** BGP keepavlie timer becomes configurable. + +* Changes in ripd + +** When making reply to rip's REQUEST message, fill in +RIP_METRIC_INFINITY with network byte order using htonl (). + +** Pass host byte order address to IN_CLASSC and IN_CLASSB macro. + +* Changes in ospfd + +** LSA flooding works. + +** Fix bug of DD processing. + +** Fix bug of originating router-LSA bug is fixed. + +** LSA structure is changed to support LSA aging. + +* Changes in ospf6d + +** `ip6' statement in configuration is changed to `ipv6'. + +* Changes in zebra-0.77 + +* Changes in lib + +** SIGUSR1 reopen logging file. + +** route-map is extended to support multi-protocol routing +information. + +** When compiling under GNU libc 2.1 environment don't use inet6-apps. + +* Changes in zebra + +** Basic IPv6 router advertisement codes added. It is not yet usable. + +** Fix IPv6 route addition/deletion bug is fixed. + +** `show ip route A.B.C.D' works + +* Changes in bgpd + +** When invalid unfeasible routes length comes, bgpd send notify then +continue to process the packet. Now bgpd stop parsing invalid packet +then return to main loop. + +** BGP-4+ withdrawn routes parse bug is fixed. + +** When BGP-4+ information passed to non shared network's peer, trim +link-local next-hop information. + +** `no redistribute ROUTE_TYPE' withdraw installed routes from BGP +routing information. + +** `show ipv6 route IPV6ADDR' command added. + +** BGP start timer has jitter. + +** Holdtimer configuration bug is fixed. Now configuration does not +show unconfigured hold time value. + +* Changes in ripngd + +** Now update timer (default 30 seconds) has +/- 50% jitter value. + +** Add timers basic command. + +** `network' configuration is dynamically reflected. + +** `timers basic ' added. + +* Changes in ripd + +** Reconstruct almost codes. + +** `network' configuration is dynamically reflected. + +** RIP timers now conforms to RFC2453. So user can configure update, +timeout, garbage timer. + +** `timers basic ' works. + +* Changes in ospfd + +** Bug of originating network LSA is fixed. + +** `no router ospf' core dump bug is fixed. + +* Changes in ospf6d + +** Redistribute route works. + +* Changes in zebra-0.76 + +* Changes in lib + +** configure.in Linux IPv6 detection problem is fixed. + +** Include SERVICES file to the distribution + +** Update zebra.texi to zebra-0.76. + +* Changes in zebra-0.75 + +* Changes in lib + +** `termnal length 0' bug is fixed. + +* Changes in zebra + +** When zebra starts up, sweep all zebra installed routes. If -k or +--keep_kernel option is specified to zebra dameon. This function is +not performed. + +* Changes in ripngd + +** Aggreagte address command supported. In router ripngd, +`aggregate-address IPV6PREFIX' works. + +* Changes in bgpd + +** Input route-map's bug which cause segmentation violation is fixed. + +** route-map method improved. + +** BGP-4+ nexthop detection improved. + +** BGP-4+ route re-selection bug is fixed. + +** BGP-4+ iBGP route's nexthop calculation works. + +** After connection Established `show ip bgp neighbor' display BGP TCP +connection's source and destination address. + +** In case of BGP-4+ `show ip bgp neighbor' display BGP-4+ global and +local nexthop which used for originated route. This address will be +used when `next-hop-self'. + +* Changes in ospfd + +** Fix bug of DR election. + +** Set IP precedence field with IPTOS_PREC_INTERNET_CONTROL. + +** Schedule NeighborChange event if NSM status change. + +** Never include a neighbor in Hello packet, when the neighbor goes +down. + +* Changes in zebra-0.74 + +* Changes in lib + +** Now `terminal length 0' means no line output control. + +** `line LINES' command deleted. Instead of this please use `terminal +length <0-512>'. + +** `terminal length <0-512>' is each vty specific configuration so it +can not be configured in the configuration file. If you want to +configure system wide line control, please use `service +terminal-length <0-512>'. This configuration affects to the all vty +interface. + +* Changes in zebra + +** Installation of IPv6 route bug is fixed. + +* Changes in bgpd + +** Very serious bug of bgp_stop () is fixed. When multiple route to +the same destination exist, bgpd try to announce the information to +stopped peer. Then add orphan write thread is added. This cause +many strange behavior of bgpd. + +** Router-id parsing bug is fixed. + +** With BGP-4+ nexthop installation was done with global address but +it should be link-local address. This bug is fixed now. + +** When incoming route-map prepend AS, old AS path remained. Now bgpd +free old AS path. + +** `neighbor PEER weight <0-65535>' command added. + +* Changes in ripngd + +** Almost codes are rewritten to conform to RFC2080. + +* Changes in ospfd + +** SPF calculation timer is added. Currently it is set to 30 seconds. + +** SPF calculation works now. + +** OSPF routing table codes are added. + +** OSPF's internal routes installed into the kernel routing table. + +** Now `ospfd' works as non-area, non-external route support OSPF +router. + +** Call of log_rotate() is removed. + +* Changes in ospf6d + +** LSA data structure is changed. + +** Call of log_rotate() is removed. + +* Changes in zebra-0.73 + +* Changes in lib + +** `config terminal' is changed to `configure terminal'. + +** `terminal length <0-512>' command is added. + +** Variable length argument was specified by `...'. Now all strings +started with character `.' is variable length argument. + +* Changes in zebra + +** Internal route (such as iBGP, internal OSPF route) handling works +correctly. + +** In interface node, `ipv6 address' and `no ipv6 address' works. + +** Interface's address remain after `no ip address' bug is fixed. + +** Host route such as IPv4 with /32 mask and IPv6 with /128 mask +didn't set RTF_GATEWAY even it has gateway. This bug if fixed now. + +* Changes in bgpd + +** `match as-path' argument is used to be specify AS PATH value itself +directly (e.g. ^$). But it is changed to specify `ip as-apth +access-list' name. + +** iBGP route handle works without getting error from the kernel. + +** `set aggregator as AS A.B.C.D' command is added to route-map. + +** `set atomic-aggregate' command is added to bgpd's routemap. + +** Announcement of atomic aggregate attribute and aggregator attribute +works. + +** `update-source' bug is fixed. + +** When a route learned from eBGP is announced to iBGP, local +preference was set to zero. But now it set to +DEFAULT_LOCAL_PREF(100). + +* Changes in ripd + +** RIPv1 route filter bug is fixed. + +** Some memory leak is fixed. + +* Changes in ospfd + +** Fix bug of DR Election. + +** Fix bug of adjacency forming. + +* Changes in ospf6d + +** Clean up logging message. + +** Reflect routing information to zebra daemon. + +* Changes in zebra-0.72 + +* Changes in lib + +** When getsockname return IPv4 mapped IPv6 address. Convert it to +IPv4 address. + +* Changes in bgpd + +** Change route-map's next-hop related settings. + +set ip nexthop -> set ip next-hop +set ipv6 nexthop global -> set ipv6 next-hop global +set ipv6 nexthop local -> set ipv6 next-hop local + +** Add `next-hop-self' command. + +* Changes in ospfd + +** Fix bug of multiple `network area' directive crashes. + +* Changes in zebra-0.71 + +* Changes in lib + +** `log syslog' command is added. + +** Use getaddrinfo function to bind IPv4/IPv6 server socket. + +** `no banner motd' will suppress motd output when user connect to VTY. + +** Bind `quit' command to major nodes. + +* Changes in zebra + +** Point-to-point link address handling bug is fixed. + +* Changes in bgpd + +** AS path validity check is added. If malformed AS path is received +NOTIFY Malformed AS path is send to the peer. + +** Use getaddrinfo function to bind IPv4/IPv6 server socket. + +* Changes in ripd + +** Connected network announcement bug is fixed. + +** `broadcast' command is deleted. + +** `network' command is added. + +** `neighbor' command is added. + +** `redistribute' command is added. + +** `timers basic' command is added. + +** `route' command is added. + +* Changes in ripngd + +** Fix metric calculation bug. + +* Changes in ospfd + +** Check sum bug is fixed. + +* Chanegs in ospf6d + +** Routing table code is rewritten. + +* Changes in zebra-0.70 + +* Changes in zebra + +** Critical routing information base calculation bug check is fixed. + +** zebra ipv4 message is extended to support external/internal route +flavor. + +** Now if internal route doesn't has direct connected nexthop, then +nexthop is calculated by looking up IGP routing table. + +* Changes in bgpd + +** `neighbor PEER update-source IFNAME' command added as ALIAS to +`neighbor PEER interface IFNAME'. + +* Changes in ospfd + +** DD null pointer bug is fixed. + +* Changes in zebra-0.69 + +* Changes in zebra + +** zebra redistirbution supports dynamic notification of the route +change. If you add static route while running zebra, it will be +reflected to other protocol daemon which set `redistribute static'. + +** If static route installation is failed due to the error. The +static route is not added to the configuration and zebra routing +table. + +** zebra sets forwarding flag to on when it starts up. + +** `no ip forwarding' turn off IPv4 forwarding. + +** `no ipv6 forwarding' turn off IPv6 forwarding. + +** Change `show ipforward' command to `show ip forwarding'. + +** Change `show ipv6forward' command to `show ipv6 forwarding'. + +** `ip route A.B.C.D/M INTERFACE' works. So you can set `ip route +10.0.0.0/8 eth0'. + +* Changes in bgpd + +** `neighbor PEER send-community' command is added. If the option is +set, bgpd will send community attribute to the peer. + +** When a BGP route has no-export community attribute and +send-community is set to the peer, the route is not announced to the +peer. + +* Changes in ripngd + +** When ripngd terminates, delete all installed route. + +** `redistribute static', `redistribute connected' works. + +** Change `debug ripng event' to `debug ripng events'. + +** Change `show debug ripng' to `show debugging ripng'. + +** Bug of static route deletion is fixed. + +* Changes in ospfd + +** LS request and LS update can be send and received. + +* Changes in zebra-0.68 + +* Changes in lib + +** DEFUN() is extended to support (a|b|c) statement. + +** Input buffer overflow bug is fixed. + +* Changes in bgpd + +** `ip community-list' is added. + +** set community and match community is added to route-map statement. + +** aggregate-address A.B.C.D/M partly works. Now it works only +summary-only mode. + +* Changes in zebra + +** IPv6 network address delete bug is fixed. + +* Changes in ospfd + +** DR election bug fixed. + +** Now Database Description can be send or received. + +** Neighbor State Machine goes to Full state. + +* Changes in ospf6d + +** router zebra related bug is fixed. + +* Changes in zebra-0.67 + +* Changes in lib + +** `service password-encryption' is added for encrypted password. + +* Changes in bgpd + +** `set as-path prepend ASPATH' is added to route-map command. + +** `set weight WEIGHT' is added to route-map command. + +** `no set ipv6 nexthop global' and `no set ipv6 nexthop local' +command is added to route-map. + +** `neighbor IP_ADDR version BGP_VERSION' command's BGP_VERSION +argument changed. + +Old New +===================== +bgp4 4 +bgp4+ 4+ +bgp4+-draft-00 4- +===================== + +If you want to peer with old draft version of BGP-4+, please configure +like below: + +router bgp ASN + neighbor PEER version 4- + +** Some AS path isn't correctly compared during route selection. Now +it is fixed. + +* Changes in ospfd + +** `router zebra' is default behavior. + +* Changes in ospf6d + +** `router zebra' is default behavior. + +* Changes in zebra-0.66 + +* Changes in zebra + +** When other daemon such as gated install routes into the kernel then +zebra blocks. This is only occur with netlink socket. Now socket is +set as NONBLOCKING and problem is fixed. Reported and fixed by +Patrick Koppen + +* Changes in bgpd + +** Now `router zebra' is not needed to insert BGP routes into the +kernel. It is default behavior. If you don't want to install the BGP +routes to the kernel, please configure like below: + +! +router zebra + no redistribute bgp +! + +** redistribute connected works. + +** redistribute static now filter local loopback routes and link local +network. + +* Changes in ripd + +** Some network check is added. Patch is done by Carlos Alberto +Barcenilla + +* Changes in ripngd + +** Sometimes ripngd install wrong nexthop into the kernel. This bug +is fixed now. + +** Now `router zebra' is not needed to insert RIPng routes into the +kernel. It is default behavior. If you don't want to install the BGP +routes to the kernel, please configure like below: + +! +router zebra + no redistribute ripng +! + +* Changes in zebra-0.65 + +* Changes in lib + +** `C-c' changes current node to ENABLE_NODE. Previously it doesn't. + +** In ENABLE_NODE, `exit' command close vty connection. + +** `service advanced-vty' enable advanced vty function. If this +service is specified one can directly connect to ENABLE_NODE when +enable password is not set. + +** `lines LINES' command is added by Stephen R. van den Berg +. + +* Changes in zebra + +** Basic Linux policy based routing table support is added by Stephen +R. van den Berg . + +* Changes in bgpd + +** route-map command is improved: + `match ip next-hop': New command. + `match metric': New command. + `set metric': Doc fixed. + `set local-preference': DEFUN added. + +* Changes in ripd + +** Check of announced network is added. Now multicast address is +filtered. Reported by Carlos Alberto Barcenilla + + +** Check of network 127 is added. Reported by Carlos Alberto +Barcenilla + +* Changes in ripngd + +** Aging route bug is fixed. + +** `router zebra' semantics changed. ripngd automatically connect to +zebra. + +* Changes in ospfd + +** `no router ospf' works. + +* Changes in ospf6d + +** Bug fix about network vertex. + +* Changes in zebra-0.64.1. + +This is bug fix release. + +* Changes in lib + +** Add check of sin6_scope_id in struct sockaddr_in6. For compilation +on implementation which doesn't have sin6_scope_id. Reported by Wim +Biemolt . + +* Changes in zebra + +** Fix bug of display BGP routes as "O" instead of "B". Reported by +"William F. Maton" and Dave Hartzell +. + +* Changes in bgpd + +** `no network IPV6_NETWORK' statement and `no neighbor IP_ADDR timers +holdtime [TIMER]' statement doesn't work. Reported by Georg Hitsch +. Now both statement work. + +* Changes in ospfd + +** Last interface is not updated by ospf_if_update(). Reported by +Dave Hartzell . + +* Changes in ospf6d + +** Byte order of ifid is changed. Due to this change, this code will +not work with previous version, sorry. + +** Fix `show ip route' route type mismatch. + +** Fix bug of no network IPV6_NETWORK. + +** Important bug fix about intra-area-prefix-lsa. + +* Changes in zebra-0.64. + +* Changes in lib + +** prefix-list based filtering routine is added. Currently used in +bgpd but it will be in other daemons. + +* Changes in bgpd + +** `no router bgp' works. But network statement is not cleared. This +should be fixed in next beta. + +** Route reflector related statement is added. + + router bgp ASN + bgp cluster-id a.b.c.d + neighbor a.b.c.d route-reflector-client + + is added. + +** Prefix list based filtering is added. + + router bgp ASN + neighbor a.b.c.d prefix-list PREFIX_LIST_NAME + +** Prefix list based routing display works. + + show ip bgp prefix-list PREFIX_LIST_NAME + +* Changes in ripd + +** Fix route metric check bug. Reported from Mr. Carlos Alberto +Barcenilla. + +* Changes in ospf6d + +** There are many changes. If you have interested in ospf6d please +visit ospf6d/README file. + +* Changes in zebra-0.63 first beta package. + +* Changes in lib + +** `copy running-config stgartup-config' command is added. + +** prefix length check bug is fixed. Thanks Marlos Barcenilla +. + +* Changes in ospfd + +** DR and BDR election works. + +** OSPF Hello simple authentication works. + +* Changes in ospf6d + +** Now ospf6d can be compiled on both Linux and *BSD system. + +* Changes in zebra-19990420 snapshot + +** `make dist' at top directory works now. + +* Changes in lib + +** VTY has now access-class to restrict remote connection. +Implemented by Alex Bligh . + +! +line vty + access-class ACCESS-LIST-NAME +! + +** `show version' command added. Implemented by Carlos Alberto +Barcenilla + +* Changes in zebra + +** `ip address' command on *BSD bug is fixed. + +** `no ip address' works now for IPv4 address. + +** Now `write terminal' display `ip address' configuration. + +* Changes in bgpd + +** Redistribute static works now. Please run both zebra and bgpd. +bgpd.conf should be like this: + +! +router zebra +! +router bgp ASN + redisitribute static +! + +* Changes in guile + +** configure --enable-guile turns on zebra-guile build. + +** (router-bgp ASN) allocates real bgp structre. + +* Changes in zebra-19990416 snapshot + +** Set version to 0.60 for preparation of beta release. + +** New directory guile is added for linking with guile interpreter. + +* Changes in zebra + +** On GNU/Linux Kernel 2.2.x (with netlink support), zebra detects +asynchronous routing updates. *BSD support is not yet finished. + +* Changes in bgpd + +** `show ip bgp regexp ASPATH_REGEX' uses CISCO like regular expression +instead of RPSL like regular expression. I'm planing to provide RPSL +like regular expression with `show ip bgp rpsl' or something. + +* Changes in lib + +** Press '?' at variable mandatory argument, vty prints nothing. Now +vty outputs description about the argument. Fixed by Alex Bligh + + +** buffer.c has some ugly bugs. Due to the bug, vty interface hangs +when large output date exists. This bug is fixed. Reported by Alex +Bligh . + +* Changes in ospfd + +** DR and BDR information is shown by `show ip ospf interface' command. + +* Changes in zebra-19990408 snapshot + +* Changes in bgpd + +** Old BGP-4+ specification (described in old draft) treatment bug is +fixed. It seems that mrtd uses this format as default. So if you +have problem peering with mrtd and want to use old draft format please +use version statement like this. + +neighbor PEER_ADDRESS remote-as ASN +neighbor PEER_ADDRESS version bgp4+-draft-00 + +** When AS path is epmty (routes generated by bgpd), SEGV is occur +when announce the routes to eBGP peer. Reported by +kad@gibson.skif.net. + +** ip as-path access-list command is added. + +** neighbor PEER_ADDRESS filter-list AS_LIST [in|out] command is added. + +** neighbor PEER_ADDRESS timers holdtimer TIMER command is added. + +* Changes in all daemons + +** With KAME stack, terminal interface is now bind AF_INET socket +instead of AF_INET6 one. + +* Changes in zebra-19990403 snapshot + +* Changes in bgpd + +** When bgpd has 'router zebra', bgpd automatically select it's router +ID as most highest interface's IP Address. + +** When AS path is empty (in case of iBGP), it doesn't include any AS +segment. This change is for announcement to gated under iBGP. + +* Changes in ospfd + +** OSPF hello packet send/receive works. + +* Changes in ospf6d + +** Yasuhiro Ohara's ospf6d codes is imported. It is under development +and can't be compiled on any platform. + +* Changes in zebra-19990327 snapshot + +* Changes in bgpd + +** When BGP-4+ connection is done by IPv6 link-local address. One +have to specify interface index for the connection. So I've added +interface statement to the neighbor commmand. Please specify +interface name for getting interface index like below. This statement +only works on GNU/Linux. I'll support BSD ASAP. + +router bgp 7675 + neighbor fe80::200:f8ff:fe01:5fd3 remote-as 2500 + neighbor fe80::200:f8ff:fe01:5fd3 interface sit3 + +** For disable BGP peering `shutdown' command is added. + +router bgp 7675 + neighbor 10.0.0.1 shutdown + +** `description' command is added to neighbor statement. + +router bgp 7675 + neighbor 10.0.0.1 description peering with Norway. + +** `show ip bgp regexp AS-REGEXP' works again. + +show ip bgp regexp AS7675 + +will show routes which include AS7675. + +** When a route which is made from `network' statement is send to +neighbor. Set it's nexthop to self. So 10.0.0.0/8 is announced to +the peer A with source address 192.168.1.1. The routes nexthop is set +to 192.168.1.1. + +* Changes in zebra + +** In zebra/rtread_sysctl.c, function rtm_read() may overrun allocated +buffer when the address family is not supported and the length is big +(i.e link address). Reported Achim Patzner . + +* Changes in ospfd + +** Now ospfd receive OSPF packet. + +* Changes in zebra-19990319 snapshot + +* Changes in configuration and libraries + +** User can disable IPv6 feature and/or pthread feature by configure + option. + + To disable IPv6: configure --disable-ipv6 + To disable pthread: configure --disable-pthread + +** User can disable specified daemon by configure option. + + Don't make zebra: configure --disable-zebra + Don't make bgpd: configure --disable-bgpd + Don't make ripd: configure --disable-ripd + Don't make ripngd: configure --disable-ripngd + Don't make ospfd: configure --disable-ospfd + Don't make ospf6d: configure --disable-ospf6d + +** Sample configuration files are installed as 600 file flag. + Suggested by Jeroen Ruigrok/Asmodai . + +** syslog logging feature is added by Peter Galbavy + + +** Inclusion of standard header files is reworked by Peter Galbavy + + +** Change description from GNU/Linux 2.1.X to GNU/Linux 2.2.X + +** If daemon function exists in standard C library use it. + +** To generate configure script we upgrade autoconf to 2.13. To +generate Makefile.in we upgrade automake to 1.4. + +** doc/texinfo.tex is added to distribution. + +** Update ports/pkg/DESCR description. + +** Update doc/zebra.texi. + +** logfile FILENAME statement deleted. Instead of that please use log +file FILENAME. + +* Changes in zebra + +* Changes in bgpd + +** Communication between zebra and bgpd works now. So if there is + `router zebra' line in bgpd.conf, selected route is installed + into kernel routing table. + +** Delete all routes which inserted by bgpd when bgpd dies. If you +want to retain routes even bgpd dies please specify [-r|--retain] +option to bgpd. + +** BGP announcement code is reworked. Now bgpd announce selected + routes to other peer. + +** All output bgp packet is buffered. It's written to the socket when + it gets ready. + +** Output route-map works now. You can specify output route-map by: + + neighbor IP_ADDR route-map ROUTE_MAP_NAME out + +** New route-map command added. + + set ip nexthop IP_ADDR + set ipv6 nexthop global IP_ADDR + +** Fix bug about unlock of the route_node structure. + +** BGP-4+ support is added. bgpd can listen and speak BGP-4+ packet +specified in RFC2283. You can view IPv6 bgp table by: `show ipv6 bgp'. + +** Meny packet overflow check is added. + +* Changes in ripd + +* Changes in ripngd + +* Changes in ospfd + +** ospfd work is started by Toshiaki Takada . Now +several files are included in ospfd directory. + +** ospf6d codes are merged from Yasuhiro Ohara 's +ospfd work. Now codes are located in ospf6d directory. + + +Local variables: +mode: outline +paragraph-separate: "[ ]*$" +end: diff --git a/README b/README new file mode 100644 index 0000000..72bccfc --- /dev/null +++ b/README @@ -0,0 +1,12 @@ +GNU Zebra is free software that manages various IPv4 and IPv6 routing +protocols. + +Currently GNU Zebra supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, +RIPv2, and RIPng. + +See the file INSTALL for building and installation instructions. + +See the file REPORTING-BUGS to report bugs. + +GNU Zebra is free software. See the file COPYING for copying conditions. + diff --git a/REPORTING-BUGS b/REPORTING-BUGS new file mode 100644 index 0000000..d6b23dd --- /dev/null +++ b/REPORTING-BUGS @@ -0,0 +1,28 @@ +This file describes the procedure for reporting Zebra bugs. +You are not obliged to follow this format , but it would be +great help for Zebra developers if you report a bug as described +below. + +Send your report to bug-zebra@gnu.org mailing list. + +Please supply the following information: +1. Your zebra version or if it is CVS version then the date you did checkout. +Always try to report the bugs on the current CVS version. +2. Zebra daemons you run e.g. bgpd or ripd, your OS full name, +any specific options you compiled zebra with. +3. Problem description. Copy and paste relative zebra commands and their +output to describe your network setup e.g. "zebra>show ip route". +Please, also give your simple network layout and output of relative OS commands +(e.g. ifconfig). +4. All zebra configuration files you use. If you don't want to publish +your network numbers change 2 middle bytes in IPv4 address to be XXX e.g. +192.XXX.XXX.32/24. Similar could be done with IPv6. +5. If any zebra daemon core dumped, please, supply stack trace using +the following commands: host> gdb exec_file core_file , (gdb) bt . +6. Run all zebra daemons with full debugging on (see documentation on debugging) and +send _only_ part of logs which are relative to your problem. +7. If the problem is difficult to reproduce please send a shell script to +reproduce it. +8. Patches, workarounds, fixes are always welcome. + +Thank You. diff --git a/SERVICES b/SERVICES new file mode 100644 index 0000000..41d4b94 --- /dev/null +++ b/SERVICES @@ -0,0 +1,17 @@ +# As long as this software is in alpha testing it is not yet included +# in /etc/services files. This means that you may need to add the following +# lines into your /etc/services file on your hosts. +# +# --- Please add this to your /etc/services --- + +# +# GNU Zebra services +# + +zebrasrv 2600/tcp +zebra 2601/tcp +ripd 2602/tcp +ripng 2603/tcp +ospfd 2604/tcp +bgpd 2605/tcp +ospf6d 2606/tcp diff --git a/TODO b/TODO new file mode 100644 index 0000000..beb64a4 --- /dev/null +++ b/TODO @@ -0,0 +1,32 @@ + + Zebra TODO list + 2004/07/20 + +zebra: + +o Pointopoint address configuration. +o Multiple (alias) address configuration for the interface when kernel + support it [just starting]. + +bgpd: + +o HUP signal support (reload configuration file). +o BGP multi-path extension + +ripd: + +o Multipath support. + +ospfd: + +o Rewrite the incremental RT update code. +o Demand circuits. +o Multiple instances. +o OSPF MIB [SNMP get is amost finished]. +o HUP signal treatment. + +ospf6d: + +o Documentation. +-- +Kunihiro Ishiguro diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..d78e9d0 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,836 @@ +# aclocal.m4 generated automatically by aclocal 1.6.3 -*- Autoconf -*- + +# Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Do all the work for Automake. -*- Autoconf -*- + +# This macro actually does too much some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 8 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +AC_PREREQ([2.52]) + +# Autoconf 2.50 wants to disallow AM_ names. We explicitly allow +# the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl + AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], [AC_PACKAGE_TARNAME])dnl + AC_SUBST([VERSION], [AC_PACKAGE_VERSION])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_MISSING_PROG(AMTAR, tar) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl + +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_][CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_][CC], + defn([AC_PROG_][CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_][CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_][CXX], + defn([AC_PROG_][CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + +# Copyright 2002 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION],[am__api_version="1.6"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.6.3])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright 2001, 2002 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 2 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# +# Check to make sure that the build environment is sane. +# + +# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 3 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# -*- Autoconf -*- + + +# Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 3 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# AM_AUX_DIR_EXPAND + +# Copyright 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +# Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50]) + +AC_DEFUN([AM_AUX_DIR_EXPAND], [ +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. + +# Copyright 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# AM_PROG_INSTALL_STRIP + +# Copyright 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# serial 4 -*- Autoconf -*- + +# Copyright 1999, 2000, 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + echo '#include "conftest.h"' > conftest.c + echo 'int i;' > conftest.h + echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=conftest.c object=conftest.o \ + depfile=conftest.Po tmpdepfile=conftest.TPo \ + $SHELL ./depcomp $depcc -c conftest.c -o conftest.o >/dev/null 2>&1 && + grep conftest.h conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[rm -f .deps 2>/dev/null +mkdir .deps 2>/dev/null +if test -d .deps; then + DEPDIR=.deps +else + # MS-DOS does not allow filenames that begin with a dot. + DEPDIR=_deps +fi +rmdir .deps 2>/dev/null +AC_SUBST([DEPDIR]) +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking Speeds up one-time builds + --enable-dependency-tracking Do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +#serial 2 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + grep '^DEP_FILES *= *[[^ @%:@]]' < "$mf" > /dev/null || continue + # Extract the definition of DEP_FILES from the Makefile without + # running `make'. + DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"` + test -z "$DEPDIR" && continue + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n -e '/^U = / s///p' < "$mf"` + test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" + # We invoke sed twice because it is the simplest approach to + # changing $(DEPDIR) to its actual value in the expansion. + for file in `sed -n -e ' + /^DEP_FILES = .*\\\\$/ { + s/^DEP_FILES = // + :loop + s/\\\\$// + p + n + /\\\\$/ b loop + p + } + /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright 2001 Free Software Foundation, Inc. -*- Autoconf -*- + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 2 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +doit: + @echo done +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | fgrep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST(am__include) +AC_SUBST(am__quote) +AC_MSG_RESULT($_am_result) +rm -f confinc confmf +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright 1997, 2000, 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 5 + +AC_PREREQ(2.52) + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([conditional \"$1\" was never defined. +Usually this means the macro was only invoked conditionally.]) +fi])]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. -*- Autoconf -*- + +# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +AC_PREREQ([2.52]) + +# serial 6 + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. We must strip everything past the first ":", +# and everything past the last "/". + +# _AM_DIRNAME(PATH) +# ----------------- +# Like AS_DIRNAME, only do it during macro expansion +AC_DEFUN([_AM_DIRNAME], + [m4_if(regexp([$1], [^.*[^/]//*[^/][^/]*/*$]), -1, + m4_if(regexp([$1], [^//\([^/]\|$\)]), -1, + m4_if(regexp([$1], [^/.*]), -1, + [.], + patsubst([$1], [^\(/\).*], [\1])), + patsubst([$1], [^\(//\)\([^/].*\|$\)], [\1])), + patsubst([$1], [^\(.*[^/]\)//*[^/][^/]*/*$], [\1]))[]dnl +])# _AM_DIRNAME + + +# The stamp files are numbered to have different names. +# We could number them on a directory basis, but that's additional +# complications, let's have a unique counter. +m4_define([_AM_STAMP_Count], [0]) + + +# _AM_STAMP(HEADER) +# ----------------- +# The name of the stamp file for HEADER. +AC_DEFUN([_AM_STAMP], +[m4_define([_AM_STAMP_Count], m4_incr(_AM_STAMP_Count))dnl +AS_ESCAPE(_AM_DIRNAME(patsubst([$1], + [:.*])))/stamp-h[]_AM_STAMP_Count]) + + +# _AM_CONFIG_HEADER(HEADER[:SOURCES], COMMANDS, INIT-COMMANDS) +# ------------------------------------------------------------ +# We used to try to get a real timestamp in stamp-h. But the fear is that +# that will cause unnecessary cvs conflicts. +AC_DEFUN([_AM_CONFIG_HEADER], +[# Add the stamp file to the list of files AC keeps track of, +# along with our hook. +AC_CONFIG_HEADERS([$1], + [# update the timestamp +echo 'timestamp for $1' >"_AM_STAMP([$1])" +$2], + [$3]) +])# _AM_CONFIG_HEADER + + +# AM_CONFIG_HEADER(HEADER[:SOURCES]..., COMMANDS, INIT-COMMANDS) +# -------------------------------------------------------------- +AC_DEFUN([AM_CONFIG_HEADER], +[AC_FOREACH([_AM_File], [$1], [_AM_CONFIG_HEADER(_AM_File, [$2], [$3])]) +])# AM_CONFIG_HEADER + diff --git a/bgpd/BGP4-MIB.txt b/bgpd/BGP4-MIB.txt new file mode 100644 index 0000000..c911316 --- /dev/null +++ b/bgpd/BGP4-MIB.txt @@ -0,0 +1,929 @@ + BGP4-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, + IpAddress, Integer32, Counter32, Gauge32, mib-2 + FROM SNMPv2-SMI + MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP + FROM SNMPv2-CONF; + + bgp MODULE-IDENTITY + LAST-UPDATED "9902100000Z" + ORGANIZATION "IETF IDR Working Group" + CONTACT-INFO "E-mail: idr@merit.net + + Susan Hares (Editor) + Merit Network + 4251 Plymouth Road + Suite C + Ann Arbor, MI 48105-2785 + Tel: +1 734 936 2095 + Fax: +1 734 647 3185 + E-mail: skh@merit.edu + + Jeff Johnson (Editor) + RedBack Networks, Inc. + 1389 Moffett Park Drive + Sunnyvale, CA 94089-1134 + Tel: +1 408 548 3516 + Fax: +1 408 548 3599 + E-mail: jeff@redback.com" + DESCRIPTION + "The MIB module for BGP-4." + REVISION "9902100000Z" + DESCRIPTION + "Corrected duplicate OBJECT IDENTIFIER + assignment in the conformance information." + REVISION "9601080000Z" + DESCRIPTION + "1) Fixed the definitions of the traps to + make them equivalent to their initial + definition in RFC 1269. + 2) Added compliance and conformance info." + ::= { mib-2 15 } + + bgpVersion OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..255)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Vector of supported BGP protocol version + numbers. Each peer negotiates the version + from this vector. Versions are identified + via the string of bits contained within this + object. The first octet contains bits 0 to + 7, the second octet contains bits 8 to 15, + and so on, with the most significant bit + referring to the lowest bit number in the + octet (e.g., the MSB of the first octet + refers to bit 0). If a bit, i, is present + and set, then the version (i+1) of the BGP + is supported." + ::= { bgp 1 } + + bgpLocalAs OBJECT-TYPE + SYNTAX INTEGER (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The local autonomous system number." + ::= { bgp 2 } + + + + -- BGP Peer table. This table contains, one entry per BGP + -- peer, information about the BGP peer. + + bgpPeerTable OBJECT-TYPE + SYNTAX SEQUENCE OF BgpPeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "BGP peer table. This table contains, + one entry per BGP peer, information about the + connections with BGP peers." + ::= { bgp 3 } + + bgpPeerEntry OBJECT-TYPE + SYNTAX BgpPeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Entry containing information about the + connection with a BGP peer." + INDEX { bgpPeerRemoteAddr } + ::= { bgpPeerTable 1 } + + BgpPeerEntry ::= SEQUENCE { + bgpPeerIdentifier + IpAddress, + bgpPeerState + INTEGER, + bgpPeerAdminStatus + INTEGER, + bgpPeerNegotiatedVersion + Integer32, + bgpPeerLocalAddr + IpAddress, + bgpPeerLocalPort + INTEGER, + bgpPeerRemoteAddr + IpAddress, + bgpPeerRemotePort + INTEGER, + bgpPeerRemoteAs + INTEGER, + bgpPeerInUpdates + Counter32, + bgpPeerOutUpdates + Counter32, + bgpPeerInTotalMessages + Counter32, + bgpPeerOutTotalMessages + Counter32, + bgpPeerLastError + OCTET STRING, + bgpPeerFsmEstablishedTransitions + Counter32, + bgpPeerFsmEstablishedTime + Gauge32, + bgpPeerConnectRetryInterval + INTEGER, + bgpPeerHoldTime + INTEGER, + bgpPeerKeepAlive + INTEGER, + bgpPeerHoldTimeConfigured + INTEGER, + bgpPeerKeepAliveConfigured + INTEGER, + bgpPeerMinASOriginationInterval + INTEGER, + bgpPeerMinRouteAdvertisementInterval + INTEGER, + bgpPeerInUpdateElapsedTime + Gauge32 + } + + bgpPeerIdentifier OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The BGP Identifier of this entry's BGP peer." + ::= { bgpPeerEntry 1 } + + bgpPeerState OBJECT-TYPE + SYNTAX INTEGER { + idle(1), + connect(2), + active(3), + opensent(4), + openconfirm(5), + established(6) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The BGP peer connection state." + ::= { bgpPeerEntry 2 } + + bgpPeerAdminStatus OBJECT-TYPE + SYNTAX INTEGER { + stop(1), + start(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The desired state of the BGP connection. A + transition from 'stop' to 'start' will cause + the BGP Start Event to be generated. A + transition from 'start' to 'stop' will cause + the BGP Stop Event to be generated. This + parameter can be used to restart BGP peer + connections. Care should be used in providing + write access to this object without adequate + authentication." + ::= { bgpPeerEntry 3 } + + bgpPeerNegotiatedVersion OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The negotiated version of BGP running between + the two peers." + ::= { bgpPeerEntry 4 } + + bgpPeerLocalAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The local IP address of this entry's BGP + connection." + ::= { bgpPeerEntry 5 } + + bgpPeerLocalPort OBJECT-TYPE + SYNTAX INTEGER (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The local port for the TCP connection between + the BGP peers." + ::= { bgpPeerEntry 6 } + + bgpPeerRemoteAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The remote IP address of this entry's BGP + peer." + ::= { bgpPeerEntry 7 } + + bgpPeerRemotePort OBJECT-TYPE + SYNTAX INTEGER (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The remote port for the TCP connection between + the BGP peers. Note that the objects + bgpPeerLocalAddr, bgpPeerLocalPort, + bgpPeerRemoteAddr and bgpPeerRemotePort + provide the appropriate reference to the + standard MIB TCP connection table." + ::= { bgpPeerEntry 8 } + + bgpPeerRemoteAs OBJECT-TYPE + SYNTAX INTEGER (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The remote autonomous system number." + ::= { bgpPeerEntry 9 } + + bgpPeerInUpdates OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of BGP UPDATE messages received on + this connection. This object should be + initialized to zero (0) when the connection is + established." + ::= { bgpPeerEntry 10 } + + bgpPeerOutUpdates OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of BGP UPDATE messages transmitted + on this connection. This object should be + initialized to zero (0) when the connection is + established." + ::= { bgpPeerEntry 11 } + + bgpPeerInTotalMessages OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of messages received from the + remote peer on this connection. This object + should be initialized to zero when the + connection is established." + ::= { bgpPeerEntry 12 } + + bgpPeerOutTotalMessages OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of messages transmitted to + the remote peer on this connection. This object + should be initialized to zero when the + connection is established." + ::= { bgpPeerEntry 13 } + + bgpPeerLastError OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (2)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The last error code and subcode seen by this + peer on this connection. If no error has + occurred, this field is zero. Otherwise, the + first byte of this two byte OCTET STRING + contains the error code, and the second byte + contains the subcode." + ::= { bgpPeerEntry 14 } + + bgpPeerFsmEstablishedTransitions OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of times the BGP FSM + transitioned into the established state." + ::= { bgpPeerEntry 15 } + + bgpPeerFsmEstablishedTime OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This timer indicates how long (in seconds) this + peer has been in the Established state or how long + since this peer was last in the Established state. + It is set to zero when a new peer is configured or + the router is booted." + ::= { bgpPeerEntry 16 } + + bgpPeerConnectRetryInterval OBJECT-TYPE + SYNTAX INTEGER (1..65535) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Time interval in seconds for the ConnectRetry + timer. The suggested value for this timer is + 120 seconds." + ::= { bgpPeerEntry 17 } + + bgpPeerHoldTime OBJECT-TYPE + SYNTAX INTEGER ( 0 | 3..65535 ) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Time interval in seconds for the Hold Timer + established with the peer. The value of this + object is calculated by this BGP speaker by + using the smaller of the value in + bgpPeerHoldTimeConfigured and the Hold Time + received in the OPEN message. This value + must be at lease three seconds if it is not + zero (0) in which case the Hold Timer has + not been established with the peer, or, the + value of bgpPeerHoldTimeConfigured is zero (0)." + ::= { bgpPeerEntry 18 } + + bgpPeerKeepAlive OBJECT-TYPE + SYNTAX INTEGER ( 0 | 1..21845 ) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Time interval in seconds for the KeepAlive + timer established with the peer. The value of + this object is calculated by this BGP speaker + such that, when compared with bgpPeerHoldTime, + it has the same proportion as what + bgpPeerKeepAliveConfigured has when compared + with bgpPeerHoldTimeConfigured. If the value + of this object is zero (0), it indicates that + the KeepAlive timer has not been established + with the peer, or, the value of + bgpPeerKeepAliveConfigured is zero (0)." + ::= { bgpPeerEntry 19 } + + bgpPeerHoldTimeConfigured OBJECT-TYPE + SYNTAX INTEGER ( 0 | 3..65535 ) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Time interval in seconds for the Hold Time + configured for this BGP speaker with this peer. + This value is placed in an OPEN message sent to + this peer by this BGP speaker, and is compared + with the Hold Time field in an OPEN message + received from the peer when determining the Hold + Time (bgpPeerHoldTime) with the peer. This value + must not be less than three seconds if it is not + zero (0) in which case the Hold Time is NOT to be + established with the peer. The suggested value for + this timer is 90 seconds." + ::= { bgpPeerEntry 20 } + + bgpPeerKeepAliveConfigured OBJECT-TYPE + SYNTAX INTEGER ( 0 | 1..21845 ) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Time interval in seconds for the KeepAlive timer + configured for this BGP speaker with this peer. + The value of this object will only determine the + KEEPALIVE messages' frequency relative to the value + specified in bgpPeerHoldTimeConfigured; the actual + time interval for the KEEPALIVE messages is + indicated by bgpPeerKeepAlive. A reasonable + maximum value for this timer would be configured to + be one third of that of bgpPeerHoldTimeConfigured. + If the value of this object is zero (0), no + periodical KEEPALIVE messages are sent to the peer + after the BGP connection has been established. The + suggested value for this timer is 30 seconds." + ::= { bgpPeerEntry 21 } + + bgpPeerMinASOriginationInterval OBJECT-TYPE + SYNTAX INTEGER (1..65535) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Time interval in seconds for the + MinASOriginationInterval timer. + The suggested value for this timer is 15 seconds." + ::= { bgpPeerEntry 22 } + + bgpPeerMinRouteAdvertisementInterval OBJECT-TYPE + SYNTAX INTEGER (1..65535) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Time interval in seconds for the + MinRouteAdvertisementInterval timer. + The suggested value for this timer is 30 seconds." + ::= { bgpPeerEntry 23 } + + bgpPeerInUpdateElapsedTime OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Elapsed time in seconds since the last BGP + UPDATE message was received from the peer. + Each time bgpPeerInUpdates is incremented, + the value of this object is set to zero (0)." + ::= { bgpPeerEntry 24 } + + + + bgpIdentifier OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The BGP Identifier of local system." + ::= { bgp 4 } + + + + -- Received Path Attribute Table. This table contains, + -- one entry per path to a network, path attributes + -- received from all peers running BGP version 3 or less. + -- This table is obsolete, having been replaced in + -- functionality with the bgp4PathAttrTable. + + bgpRcvdPathAttrTable OBJECT-TYPE + SYNTAX SEQUENCE OF BgpPathAttrEntry + MAX-ACCESS not-accessible + STATUS obsolete + DESCRIPTION + "The BGP Received Path Attribute Table contains + information about paths to destination networks + received from all peers running BGP version 3 or + less." + ::= { bgp 5 } + + bgpPathAttrEntry OBJECT-TYPE + SYNTAX BgpPathAttrEntry + MAX-ACCESS not-accessible + STATUS obsolete + DESCRIPTION + "Information about a path to a network." + INDEX { bgpPathAttrDestNetwork, + bgpPathAttrPeer } + ::= { bgpRcvdPathAttrTable 1 } + + BgpPathAttrEntry ::= SEQUENCE { + bgpPathAttrPeer + IpAddress, + bgpPathAttrDestNetwork + IpAddress, + bgpPathAttrOrigin + INTEGER, + bgpPathAttrASPath + OCTET STRING, + bgpPathAttrNextHop + IpAddress, + bgpPathAttrInterASMetric + Integer32 + } + + bgpPathAttrPeer OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The IP address of the peer where the path + information was learned." + ::= { bgpPathAttrEntry 1 } + + bgpPathAttrDestNetwork OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The address of the destination network." + ::= { bgpPathAttrEntry 2 } + + bgpPathAttrOrigin OBJECT-TYPE + SYNTAX INTEGER { + igp(1),-- networks are interior + egp(2),-- networks learned via EGP + incomplete(3) -- undetermined + } + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The ultimate origin of the path information." + ::= { bgpPathAttrEntry 3 } + + bgpPathAttrASPath OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (2..255)) + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The set of ASs that must be traversed to reach + the network. This object is probably best + represented as SEQUENCE OF INTEGER. For SMI + compatibility, though, it is represented as + OCTET STRING. Each AS is represented as a pair + of octets according to the following algorithm: + + first-byte-of-pair = ASNumber / 256; + second-byte-of-pair = ASNumber & 255;" + ::= { bgpPathAttrEntry 4 } + + bgpPathAttrNextHop OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The address of the border router that should + be used for the destination network." + ::= { bgpPathAttrEntry 5 } + + bgpPathAttrInterASMetric OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The optional inter-AS metric. If this + attribute has not been provided for this route, + the value for this object is 0." + ::= { bgpPathAttrEntry 6 } + + + + -- BGP-4 Received Path Attribute Table. This table contains, + -- one entry per path to a network, path attributes + -- received from all peers running BGP-4. + + bgp4PathAttrTable OBJECT-TYPE + SYNTAX SEQUENCE OF Bgp4PathAttrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The BGP-4 Received Path Attribute Table contains + information about paths to destination networks + received from all BGP4 peers." + ::= { bgp 6 } + + bgp4PathAttrEntry OBJECT-TYPE + SYNTAX Bgp4PathAttrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information about a path to a network." + INDEX { bgp4PathAttrIpAddrPrefix, + bgp4PathAttrIpAddrPrefixLen, + bgp4PathAttrPeer } + ::= { bgp4PathAttrTable 1 } + + Bgp4PathAttrEntry ::= SEQUENCE { + bgp4PathAttrPeer + IpAddress, + bgp4PathAttrIpAddrPrefixLen + INTEGER, + bgp4PathAttrIpAddrPrefix + IpAddress, + bgp4PathAttrOrigin + INTEGER, + bgp4PathAttrASPathSegment + OCTET STRING, + bgp4PathAttrNextHop + IpAddress, + bgp4PathAttrMultiExitDisc + INTEGER, + bgp4PathAttrLocalPref + INTEGER, + bgp4PathAttrAtomicAggregate + INTEGER, + bgp4PathAttrAggregatorAS + INTEGER, + bgp4PathAttrAggregatorAddr + IpAddress, + bgp4PathAttrCalcLocalPref + INTEGER, + bgp4PathAttrBest + INTEGER, + bgp4PathAttrUnknown + OCTET STRING + } + + bgp4PathAttrPeer OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of the peer where the path + information was learned." + ::= { bgp4PathAttrEntry 1 } + bgp4PathAttrIpAddrPrefixLen OBJECT-TYPE + SYNTAX INTEGER (0..32) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Length in bits of the IP address prefix in the + Network Layer Reachability Information field." + ::= { bgp4PathAttrEntry 2 } + + bgp4PathAttrIpAddrPrefix OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "An IP address prefix in the Network Layer + Reachability Information field. This object + is an IP address containing the prefix with + length specified by bgp4PathAttrIpAddrPrefixLen. + Any bits beyond the length specified by + bgp4PathAttrIpAddrPrefixLen are zeroed." + ::= { bgp4PathAttrEntry 3 } + + bgp4PathAttrOrigin OBJECT-TYPE + SYNTAX INTEGER { + igp(1),-- networks are interior + egp(2),-- networks learned via EGP + incomplete(3) -- undetermined + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The ultimate origin of the path information." + ::= { bgp4PathAttrEntry 4 } + + bgp4PathAttrASPathSegment OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (2..255)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The sequence of AS path segments. Each AS + path segment is represented by a triple + . + + The type is a 1-octet field which has two + possible values: + 1 AS_SET: unordered set of ASs a + route in the UPDATE message + has traversed + 2 AS_SEQUENCE: ordered set of ASs + a route in the UPDATE message + has traversed. + + The length is a 1-octet field containing the + number of ASs in the value field. + + The value field contains one or more AS + numbers, each AS is represented in the octet + string as a pair of octets according to the + following algorithm: + + first-byte-of-pair = ASNumber / 256; + second-byte-of-pair = ASNumber & 255;" + ::= { bgp4PathAttrEntry 5 } + + bgp4PathAttrNextHop OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The address of the border router that should + be used for the destination network." + ::= { bgp4PathAttrEntry 6 } + + bgp4PathAttrMultiExitDisc OBJECT-TYPE + SYNTAX INTEGER (-1..2147483647) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This metric is used to discriminate between + multiple exit points to an adjacent autonomous + system. A value of -1 indicates the absence of + this attribute." + ::= { bgp4PathAttrEntry 7 } + + bgp4PathAttrLocalPref OBJECT-TYPE + SYNTAX INTEGER (-1..2147483647) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The originating BGP4 speaker's degree of + preference for an advertised route. A value of + -1 indicates the absence of this attribute." + ::= { bgp4PathAttrEntry 8 } + + bgp4PathAttrAtomicAggregate OBJECT-TYPE + SYNTAX INTEGER { + lessSpecificRrouteNotSelected(1), + lessSpecificRouteSelected(2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Whether or not a system has selected + a less specific route without selecting a + more specific route." + ::= { bgp4PathAttrEntry 9 } + + bgp4PathAttrAggregatorAS OBJECT-TYPE + SYNTAX INTEGER (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The AS number of the last BGP4 speaker that + performed route aggregation. A value of zero (0) + indicates the absence of this attribute." + ::= { bgp4PathAttrEntry 10 } + + bgp4PathAttrAggregatorAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of the last BGP4 speaker that + performed route aggregation. A value of + 0.0.0.0 indicates the absence of this attribute." + ::= { bgp4PathAttrEntry 11 } + + bgp4PathAttrCalcLocalPref OBJECT-TYPE + SYNTAX INTEGER (-1..2147483647) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The degree of preference calculated by the + receiving BGP4 speaker for an advertised route. + A value of -1 indicates the absence of this + attribute." + ::= { bgp4PathAttrEntry 12 } + + bgp4PathAttrBest OBJECT-TYPE + SYNTAX INTEGER { + false(1),-- not chosen as best route + true(2) -- chosen as best route + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "An indication of whether or not this route + was chosen as the best BGP4 route." + ::= { bgp4PathAttrEntry 13 } + + bgp4PathAttrUnknown OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(0..255)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "One or more path attributes not understood + by this BGP4 speaker. Size zero (0) indicates + the absence of such attribute(s). Octets + beyond the maximum size, if any, are not + recorded by this object." + ::= { bgp4PathAttrEntry 14 } + + + -- Traps. + + -- note that in RFC 1657, bgpTraps was incorrectly + -- assigned a value of { bgp 7 }, and each of the + -- traps had the bgpPeerRemoteAddr object inappropriately + -- removed from their OBJECTS clause. The following + -- definitions restore the semantics of the traps as + -- they were initially defined in RFC 1269. + + -- { bgp 7 } is unused + + bgpTraps OBJECT IDENTIFIER ::= { bgp 0 } + + bgpEstablished NOTIFICATION-TYPE + OBJECTS { bgpPeerRemoteAddr, + bgpPeerLastError, + bgpPeerState } + STATUS current + DESCRIPTION + "The BGP Established event is generated when + the BGP FSM enters the ESTABLISHED state." + ::= { bgpTraps 1 } + + bgpBackwardTransition NOTIFICATION-TYPE + OBJECTS { bgpPeerRemoteAddr, + bgpPeerLastError, + bgpPeerState } + STATUS current + DESCRIPTION + "The BGPBackwardTransition Event is generated + when the BGP FSM moves from a higher numbered + state to a lower numbered state." + ::= { bgpTraps 2 } + + -- conformance information + + bgpMIBConformance OBJECT IDENTIFIER ::= { bgp 8 } + bgpMIBCompliances OBJECT IDENTIFIER ::= { bgpMIBConformance 1 } + bgpMIBGroups OBJECT IDENTIFIER ::= { bgpMIBConformance 2 } + + -- compliance statements + + bgpMIBCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for entities which + implement the BGP4 mib." + MODULE -- this module + MANDATORY-GROUPS { bgp4MIBGlobalsGroup, + bgp4MIBPeerGroup, + bgp4MIBPathAttrGroup, + bgp4MIBNotificationGroup } + ::= { bgpMIBCompliances 1 } + + -- units of conformance + + bgp4MIBGlobalsGroup OBJECT-GROUP + OBJECTS { bgpVersion, + bgpLocalAs, + bgpIdentifier } + STATUS current + DESCRIPTION + "A collection of objects providing information + on global BGP state." + ::= { bgpMIBGroups 1 } + + bgp4MIBPeerGroup OBJECT-GROUP + OBJECTS { bgpPeerIdentifier, + bgpPeerState, + bgpPeerAdminStatus, + bgpPeerNegotiatedVersion, + bgpPeerLocalAddr, + bgpPeerLocalPort, + bgpPeerRemoteAddr, + bgpPeerRemotePort, + bgpPeerRemoteAs, + bgpPeerInUpdates, + bgpPeerOutUpdates, + bgpPeerInTotalMessages, + bgpPeerOutTotalMessages, + bgpPeerLastError, + bgpPeerFsmEstablishedTransitions, + bgpPeerFsmEstablishedTime, + bgpPeerConnectRetryInterval, + bgpPeerHoldTime, + bgpPeerKeepAlive, + bgpPeerHoldTimeConfigured, + bgpPeerKeepAliveConfigured, + bgpPeerMinASOriginationInterval, + bgpPeerMinRouteAdvertisementInterval, + bgpPeerInUpdateElapsedTime } + STATUS current + DESCRIPTION + "A collection of objects for managing + BGP peers." + ::= { bgpMIBGroups 2 } + + bgp4MIBRcvdPathAttrGroup OBJECT-GROUP + OBJECTS { bgpPathAttrPeer, + bgpPathAttrDestNetwork, + bgpPathAttrOrigin, + bgpPathAttrASPath, + bgpPathAttrNextHop, + bgpPathAttrInterASMetric } + STATUS obsolete + DESCRIPTION + "A collection of objects for managing BGP + path entries. + + This conformance group is obsolete, + replaced by bgp4MIBPathAttrGroup." + ::= { bgpMIBGroups 3 } + + bgp4MIBPathAttrGroup OBJECT-GROUP + OBJECTS { bgp4PathAttrPeer, + bgp4PathAttrIpAddrPrefixLen, + bgp4PathAttrIpAddrPrefix, + bgp4PathAttrOrigin, + bgp4PathAttrASPathSegment, + bgp4PathAttrNextHop, + bgp4PathAttrMultiExitDisc, + bgp4PathAttrLocalPref, + bgp4PathAttrAtomicAggregate, + bgp4PathAttrAggregatorAS, + bgp4PathAttrAggregatorAddr, + bgp4PathAttrCalcLocalPref, + bgp4PathAttrBest, + bgp4PathAttrUnknown } + STATUS current + DESCRIPTION + "A collection of objects for managing + BGP path entries." + ::= { bgpMIBGroups 4 } + + bgp4MIBNotificationGroup NOTIFICATION-GROUP + NOTIFICATIONS { bgpEstablished, + bgpBackwardTransition } + STATUS current + DESCRIPTION + "A collection of notifications for signaling + changes in BGP peer relationships." + ::= { bgpMIBGroups 5 } + + END diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog new file mode 100644 index 0000000..f155d78 --- /dev/null +++ b/bgpd/ChangeLog @@ -0,0 +1,2604 @@ +2005-08-05 Akihiro Mizutani + + *** BGPd version 0.95 build 26 *** + : bgpd.h, bgp_packet.c + * Does not display keepalive message in "debug bgp" command. + +2005-01-17 Akihiro Mizutani + + *** BGPd version 0.95 build 25 *** + : bgpd.h, bgp_snmp.c + * Fix bug of snmp(connect timer was removed). + +2005-01-07 Akihiro Mizutani + + *** BGPd version 0.95 build 24 *** + : bgpd.[ch], bgp_vty.c + * cleanup peer-group. + * neighbor timers connect commands are removed. + +2004-12-29 Akihiro Mizutani + + *** BGPd version 0.95 build 23 *** + : bgpd.[ch], bgp_vty.c + * Fix bug of network/redistribute config display. + +2004-12-29 Akihiro Mizutani + + *** BGPd version 0.95 build 22 *** + : bgpd.[ch], bgp_vty.c, bgp_route.c, bgp_routemap.c + * Configuration display was divided for every address-family. + * neighbor weight command was supported for every address-family. + * set weight value was changed in route-map. + +2004-12-28 Akihiro Mizutani + + *** BGPd version 0.95 build 21 *** + : bgpd.[ch] + * Fix bug of bgp_delete(). + +2004-12-28 Akihiro Mizutani + + *** BGPd version 0.95 build 20 *** + : bgpd.[ch], bgp_vty.c, bgp_fsm.c + * peer_group_active() was changed to peer_group_member(). + * Fix bug of exit-address-family command. + * The connection timer was set to 120 seconds when a neighbor restarted + under the environment of graceful restart. + +2004-12-14 Akihiro Mizutani + + *** BGPd version 0.95 build 19 *** + : bgpd.h, bgp_ecommunity.[ch], bgp_routemap.c + * The extcommunity display of route-map was corrected. + * Fix memory leak of set extcommunity of route-map. + * route-map "set extcommunity cost igp" command was added. + +2004-12-11 Yasuhiro Ohara + + * bgp_route.c: moreline support & line counting for more is fixed. + +2004-11-12 Akihiro Mizutani + + *** BGPd version 0.95 build 18 *** + : bgpd.[ch], bgp_clist.c, bgp_debug.c, bgp_ecommunity.[ch], bgp_route.c, bgp_vty.c + * bgp cost community was supported. but can not set it yet. + +2004-10-08 Akihiro Mizutani + + *** BGPd version 0.95 build 17 *** + : bgpd.[ch] + * Fix bug of "neighbor transport connection-mode" commands. + +2004-09-17 Akihiro Mizutani + + *** BGPd version 0.95 build 16 *** + : bgpd.h, bgp_fsm.c + * Fix bug of peer_down_str[]. + +2004-09-10 Akihiro Mizutani + + *** BGPd version 0.95 build 15 *** + : bgpd.[ch], bgp_route.c, bgp_fsm.[ch], bgp_packet.c, bgp_attr.c + * routeadv timer was separated per afi/safi. + +2004-09-10 Akihiro Mizutani + + *** BGPd version 0.95 build 14 *** + : bgpd.h, bgp_route.c + * Fix bug of bgp_clear_route. + +2004-09-09 Akihiro Mizutani + + *** BGPd version 0.95 build 13 *** + : bgpd.[ch], bgp_vty.c, bgp_packet.c, bgp_fsm.c + * "neighbor transparent-as" command was deleted. + * "neighbor transparent-nexthop" command was deleted. + * "neighbor passive" command was changed. + New command is "neighbor transport connection-mode (passive|active)". + +2004-08-02 Akihiro Mizutani + + *** BGPd version 0.95 build 12 *** + : bgpd.h, bgp_routemap.c + * route-map "match ip route-source" command was added. + +2004-07-29 Akihiro Mizutani + + *** BGPd version 0.95 build 11 *** + : bgpd.h, bgp_packet.c + * previous TCP session closed, and the new one retained. + (when the Graceful Restart Capability has been received from the peer) + +2004-07-27 Akihiro Mizutani + + *** BGPd version 0.95 build 10 *** + : bgpd.h, bgp_route.c + * Fix typo in "show bgp community-list (<1-500>|WORD) exact-match" command. + +2004-07-23 Akihiro Mizutani + + *** BGPd version 0.95 build 9 *** + : bgpd.[ch], bgp_vty.c, bgp_open.c, bgp_fsm.c + * "bgp graceful-restart stalepath-time" command was added. + * deleted all the stale routes when following commands executed. + - "clear ip bgp neighbor" + - "neighbor shutdown" + - "no neighbor" + +2004-07-21 Akihiro Mizutani + + *** BGPd version 0.95 build 8 *** + : bgpd.h, bgp_clist.[ch], bgp_route.c, bgp_routemap.c, bgp_vty.c + * cleanup community-list. + +2004-07-20 Akihiro Mizutani + + *** BGPd version 0.95 build 7 *** + : bgpd.h, bgp_packet.c + * stale routes ignore end-of-rib check. + +2004-07-20 Akihiro Mizutani + + *** BGPd version 0.95 build 6 *** + : bgpd.h, bgp_packet.c, bgp_tcpsig.c + * The compile error was corrected. + * sending updates to other neighbor is deferred until end-of-rib is received from neighbor. + +2004-07-20 Akihiro Mizutani + + *** BGPd version 0.95 build 5 *** + : bgp_main.c, bgpd.[ch], bgp_vty.c, bgp_attr.c, bgp_route.c, bgp_zebra.c + * bgpd version was displayed in starting log. + * graceful restart timer was stopped in peer_delete(). + * "bgp enforce-first-as" command was enabled by default. + * "enforce-multihop" command was deleted. New command is "disable-connected-check". + +2004-07-20 Akihiro Mizutani + + *** BGPd version 0.95 build 4 *** + : bgp_tcpsig.c + * The compile error was corrected. + +2004-07-18 Hiroki Nakano + + *** BGPd version 0.95 build 3 *** + : bgpd.[ch], bgp_vty.c, bgp_network.[ch], bgp_tcpsig.[ch] + * TCP MD5 for OpenBSD was supported. + +2004-07-16 Akihiro Mizutani + + *** BGPd version 0.95 build 2 *** + : bgpd.h, bgp_route.[ch], bgp_vty.c, bgp_packet.c, bgp_fsm.c, bgp_open.c + * graceful restart of receiver was supported. + +2004-07-14 Akihiro Mizutani + + *** BGPd version 0.95 build 1 *** + : bgpd.[ch], bgp_vty.[ch], bgp_packet.c, bgp_route.c + * "show version bgpd" command was added. + * "bgp graceful-restart" command was added. + * The number of BGP message was displayed individually in "show ip bgp neighbor" command. + * Sending End-of-RIB to neighbor when graceful-restart capability was received. + * End-of-RIB received check was changed. + +2004-07-06 Akihiro Mizutani + + * bgpd.[ch], bgp_fsm.c: Change FSM. + Old FSM: Idle(init start timer)->Connect + New FSM: Idle->Active(active delay timer)->Connect + +2004-06-14 Akihiro Mizutani + + * bgp_route.[ch]: Add BGP_INFO_STALE flag. + +2004-06-14 Akihiro Mizutani + + * bgpd.[ch], bgp_vty.c, bgp_open.c, bgp_packet.c, bgp_attr.c, bgp_snmp.c + : Remove "neighbor version 4-" comamnds. + Remove "neighbor capability route-refresh" commands. + +2004-05-20 Akihiro Mizutani + + * bgpd.[ch], bgp_vty.c, bgp_route.c + : BGP Restart Session After Maximum-Prefix Limit feature support. + +2004-05-17 Akihiro Mizutani + + * bgpd.h, bgp_open.[ch], bgp_debug.c, bgp_vty.[ch], bgp_fsm.c + : Graceful restart capability display. + +2004-05-12 Akihiro Mizutani + + * bgpd.[ch], bgp_network.[ch], bgp_fsm.c, bgp_vty.c + : Linux TCP MD5 (RFC2385) support. + +2004-05-09 Akihiro Mizutani + + * bgp_debug.c: Add notification to bgp log-neighbor-changes. + +2004-02-15 Akihiro Mizutani + + * bgp_ecommunity.c: Transit ecommunity support. + +2004-02-12 Akihiro Mizutani + + * bgp_ecommunity.c: Fix for unknown community crush. + +2003-12-29 Akihiro Mizutani + + * bgp_routemap.c (set_ip_nexthop_bgp): Make "set ip next-hop + peer-address" work. + +2003-01-09 Akihiro Mizutani + + * bgp_routemap.c: Add match extcommunity command. + +2002-10-23 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_init): Extend hash size from default to + 32767. + (aspath_key_make): Use unsigned shoft for making hash. Suggested + by: Marc Evans + +2002-08-19 Kunihiro Ishiguro + + * bgp_clist.c (community_entry_free): Fix memory leak of standard + extcommunity-list config string. + +2002-08-19 Akihiro Mizutani + + * bgp_route.c (route_vty_out_detail): Fix bug of router-id display + when multiple instance is used. + +2002-08-18 Akihiro Mizutani + + * bgpd.c: Make "default-originate" and "maximum-prefix" commands + available in peer-group configuration. + +2002-08-13 Akihiro Mizutani + + * bgp_packet.c (bgp_open_send): Put Opt Parm Len 0 when last + capability packet cause error or dont-capability-negotiate option + is specified. + +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2001-10-28 Kunihiro Ishiguro + + * bgpd.c (bgp_vty_init): Translate update commands are removed. + +2001-10-10 Kunihiro Ishiguro + + * bgp_route.c (bgp_static_set): Add workaround for BGP static + route announcement when there is no zebra running. + +2001-10-08 Kunihiro Ishiguro + + * bgpd.c (neighbor_remote_as_unicast): Remove "remote-as nlri + unicast multicast" commands. + +2001-09-14 Akihiro Mizutani + + * bgp_open.c: When we receive capability route-refresh, we should + check we send the capability not we receive the capability. + + * bgp_route.c (bgp_network_mask_natural_route_map): network + statement route-map is added. + +2001-08-31 Kunihiro Ishiguro + + * bgp_advertise.c (bgp_advertise_intern): attr must be interned + before looking up hash table. + +2001-08-30 Kunihiro Ishiguro + + * bgpd.h (struct peer): BGP filter is moved from peer_conf to + peer. + +2001-08-28 Kunihiro Ishiguro + + * bgp_nexthop.c (bnc_nexthop_free): Fix next pointer bug. + Suggested by: "Hong-Sung Kim" . + +2001-08-26 Kunihiro Ishiguro + + * bgp_table.c (bgp_node_create): Clearn memory before use it. + +2001-08-24 Kunihiro Ishiguro + + * Change to use bgp_table.[ch]. + +2001-08-23 Kunihiro Ishiguro + + * bgpd.c (bgp_init): Add "transparent-as" and + "transparent-nexthop" for old version compatibility. + +2001-08-23 Akihiro Mizutani + + * bgpd.h (struct peer): default-originate route-map is added. + + * bgp_route.c: When self originated route is advertised with + attrubute-unchanged, nexthop was not properly set. This bug is + fixed. + +2001-08-22 Akihiro Mizutani + + * bgpd.c (neighbor_attr_unchanged): transparent-as and + transparent-next-hop commands are restructured. Instead of + current transparent-* commands, attribute-unchanged command is + introduced. + + neighbor A.B.C.D attribute-unchanged [as-path|next-hop|med] + + (neighbor_default_originate): "default-originate" configuration + announce default route even 0.0.0.0/0 does not exists in BGP RIB. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-19 Akihiro Mizutani + + * bgpd.c: AF specific soft-reconfiguration inbound commands are + added. + +2001-08-17 Kunihiro Ishiguro + + * bgp_route.c (bgp_show_callback): Do not do community NULL check. + + * bgp_community.c (community_cmp): Add check for commnunity NULL + check. + + * bgp_routemap.c (route_match_community): Do not check comunity is + NULL. It may match to community-list "^$". + + * bgp_community.c (community_match): Add check for community is + NULL case. + +2001-08-17 Akihiro Mizutani + + * bgpd.c: AF specific route-reflector-client and + route-server-client configuration are added. + +2001-08-17 Rick Payne + + * bgp_clist.c (community_match_regexp): Check special ^$ case. + +2001-08-17 Akihiro Mizutani + + * bgp_clist.c (community_list_match): Fix bug of community list + permit and deny check. + +2001-08-16 Akihiro Mizutani + + * bgp_mplsvpn.c (bgp_mplsvpn_init): Add AF specific "nexthop-self" + command. + +2001-08-15 Akihiro Mizutani + + * bgpd.h (PEER_FLAG_SEND_COMMUNITY): Per AF based configuration + flag is introduced. + + * bgp_mplsvpn.c (bgp_mplsvpn_init): VPNv4 filtering is added. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-13 Kunihiro Ishiguro + + * bgpd.c (bgp_delete): "no router bgp" free static, aggregate, rib + table properly. + +2001-08-12 Kunihiro Ishiguro + + * bgp_route.c (bgp_node_safi): Return SAFI of current node. + (bgp_config_write_network_vpnv4): VPNv4 static configuration + display. + +2001-08-11 Kunihiro Ishiguro + + * bgpd.c (no_bgp_ipv4_multicast_route_map): Add IPv4 multicast + node filter commands. + +2001-08-11 Kunihiro Ishiguro + + * bgpd.h (PEER_FLAG_IGNORE_LINK_LOCAL_NEXTHOP): Add + "ignore-link-local-nexthop" flag for ignore link-local nexthop for + IPv6. + +2001-08-07 Kunihiro Ishiguro + + * bgpd.c (address_family_ipv4_multicast): "address-family ipv4 + multicast" is added. + (address_family_ipv6_unicast): "address-family ipv6 unicast" is + added. + +2001-08-07 Akihiro Mizutani + + * bgp_route.c (bgp_process): Use flag instead of as_selected + memeber in struct bgp_info. + + * bgp_route.h (struct bgp_info): Remove as_selected memeber from + struct bgp_info. + +2001-07-31 Kunihiro Ishiguro + + * bgp_route.c (bgp_announce_check): Enclose sending time AS loop + check code with #ifdef BGP_SEND_ASPATH_CHECK. + +2001-07-29 Kunihiro Ishiguro + + * bgp_packet.c (bgp_withdraw_send): Simplify address family check. + + * bgpd.h (BGP_INFO_HOLDDOWN): Introduce new macro to check BGP + information is alive or not. + + * bgp_community.c: Use community_val_get() on all OS. + +2001-07-24 Kunihiro Ishiguro + + * bgp_route.c (bgp_announce_check): Simplify set next-hop self + check. + +2001-07-24 Akihiro Mizutani + + * bgp_route.c (bgp_announce_check): To route server clients, we + announce AS path, MED and nexthop transparently. + +2001-06-21 Kunihiro Ishiguro + + * bgp_routemap.c (route_set_atomic_aggregate_free): Do not call + XFREE. No memory is allocated in + route_set_atomic_aggregate_compile(). + +2001-06-21 Kunihiro Ishiguro + + * bgp_routemap.c (bgp_route_map_init): `match nlri` and `set nlri` + are replaced by `address-family ipv4` and `address-family vpnvr'. + +2001-06-19 Kunihiro Ishiguro + + * bgp_route.c (bgp_withdraw): Add check for BGP_PEER_CONFED. + Reported by Rick Payne . + +2001-06-17 Kunihiro Ishiguro + + * bgp_zebra.c (bgp_zebra_announce): When global IPv6 nexthop is + empty, use socket's remote address for the nexthop. + +2001-06-04 Kunihiro Ishiguro + + * bgpd.c (peer_delete): Fix memory leak. Reported by Yosi Yarchi + + +2001-06-01 Kunihiro Ishiguro + + * bgpd.c (bgp_delete): Fix memory leak. Reported by Yosi Yarchi + + +2001-05-27 Kunihiro Ishiguro + + * bgp_route.c (bgp_route_clear_with_afi_vpnv4): Use next instead + of ri->next. + + * bgp_packet.c (bgp_withdraw_send): MPLS/VPN withdraw takes effect + when HAVE_IPV6 is not defined. + +2001-03-07 "Akihiro Mizutani" + + * bgpd.c (peer_timers_set): Adjust keepalive timer to fit less + than holdtime / 3. + (bgp_confederation_peers_unset): Only set peer->local_as when + confederation is enabled. + (bgp_timers): Add "timers bgp <0-65535> <0-65535>" command. + + * bgp_route.c (bgp_announce_check): Set med of redistributed route + when it is announced to EBGP peer. + +2001-03-06 "Akihiro Mizutani" + + * bgp_nexthop.c (bgp_scan_ipv4): bgp_scan() call bgp_process() for + all prefixes. + +2001-03-06 Kunihiro Ishiguro + + * bgp_attr.c (bgp_attr_origin): When bgpd send NOTIFICATION with + erroneous attribute (type, length and value), it does include + attribute flags field. + +2001-02-21 "Akihiro Mizutani" + + * bgp_route.c (bgp_announce_check): The route reflector is not + allowed to modify the attributes of the reflected IBGP routes. + +2001-02-20 "Akihiro Mizutani" + + * bgp_route.c (bgp_info_cmp): During path seleciton, BGP + confederation peer is treated as same as IBGP peer. + +2001-02-19 Kunihiro Ishiguro + + * bgp_route.c (bgp_redistribute_add): Initialize attr_new with + attr. Call aspath_unintern when return from this function. + +2001-02-19 "Akihiro Mizutani" + + * bgpd.c (bgp_router_id_set): Reset BGP peer when router-id is + changed. + +2001-02-18 "Akihiro Mizutani" + + * bgp_packet.c (bgp_open_receive): When user configure holdtimer, + do not refrect the value to current session. + +2001-02-16 Kunihiro Ishiguro + + * bgp_route.c (bgp_aggregate_delete): Set BGP_INFO_ATTR_CHANGE to + suppress route withdraw. + + * bgp_damp.c (bgp_damp_init): Fix bug of flap dampening. + +2001-02-16 "Akihiro Mizutani" + + * bgp_aspath.c (aspath_make_str_count): Use ',' for separator for + AS_SET and AS_CONFED_SET. + +2001-02-15 Kunihiro Ishiguro + + * bgp_route.c (bgp_process): Do not consider suppress route. + + * bgp_aspath.c (aspath_aggregate_as_set_add): Reset asset when + aspath->data is realloced. + +2001-02-15 "Akihiro Mizutani" + + * bgp_attr.c (bgp_attr_aggregate_intern): Do not set atomic + aggregate when using as-set. + +2001-02-14 "Akihiro Mizutani" + + * bgpd.c (bgp_confederation_peers_unset): Set peer's local-as + correctly. + + * bgp_route.c (bgp_update): Just ignore AS path loop for + confederation peer. + +2001-02-10 Kunihiro Ishiguro + + * bgp_route.c (bgp_aggregate_set): Add as_set argument. + (bgp_aggregate_unset): Remove summary_only argument. + (aggregate_address_as_set): New commands. + "aggregate-address A.B.C.D/M as-set" + "no aggregate-address A.B.C.D/M as-set" + +2001-02-08 "Akihiro Mizutani" + + * bgp_route.c (bgp_announce_check): Do not modify nexthop when the + route is passed by route reflector. + +2001-02-08 Kunihiro Ishiguro + + * bgp_route.c: "no bgp dampening" with argument. + (bgp_announce_check): Do not modify nexthop when the route is + passed by route reflector. + +2001-02-07 "Akihiro Mizutani" + + * bgpd.c (neighbor_passive): Change "neighbor NEIGHBOR remote-as + ASN passive" to "neighbor NEIGHBOR passive". + (bgp_announce_check): Check well-known community attribute even + when "no neighbor send-community" is set. + +2001-02-03 Kunihiro Ishiguro + + * bgp_fsm.c (bgp_establish): Do not send keepalive at established + time when keepalive timer is configured as zero. + +2001-02-01 Kunihiro Ishiguro + + * bgp_attr.c (bgp_attr_check): When peer is IBGP peer, local + preference is well-known attribute. + +2001-01-30 Kunihiro Ishiguro + + * zebra-0.91 is released. + + * bgp_attr.h (struct attr): Comment out DPA value. + (struct attr): Change refcnt type from int to unsinged long. + + * bgp_attr.c (attrhash_key_make): Likewise. + (attrhash_cmp): Likewise. + (bgp_attr_dpa): Likewise. + +2001-01-30 "Akihiro Mizutani" + + * bgp_route.c (bgp_info_cmp): Make route selection completely same + as Cisco's. + +2001-01-30 Kunihiro Ishiguro + + * bgp_attr.h (BGP_ATTR_FLAG_OPTIONAL): Rename old ATTR_FLAG_* to + BGP_ATTR_FLAG_* to clarify meenings. + +2001-01-30 "Akihiro Mizutani" + + * bgp_route.c (route_vty_out): Display argument to suppress same + prefix information display. + (route_vty_out_route): Don't display mask information for + classfull network. + +2001-01-30 Kunihiro Ishiguro + + * bgp_attr.h (SET_BITMAP): Simple bitmapping macros. + + * bgp_attr.c (bgp_attr_parse): Use bitmap for attribute type + check. + +2001-01-29 Kunihiro Ishiguro + + * bgp_attr.c (bgp_mp_reach_parse): Enclose loggin with BGP_DEBUG. + (bgp_attr_parse): Comment out well-known attribute check. + +2001-01-28 Kunihiro Ishiguro + + * bgp_route.c (bgp_static_unset): Link-local IPv6 address can't be + used for network advertisement. + (nlri_parse): When link-local IPv6 address NLRI comes from + remote-peer, log the information then simply ignore it. + + * bgp_zebra.c (zebra_read_ipv6): Link-local IPv6 address is not + redistributed. + + * bgp_route.c (bgp_update): Check IPv6 global nexthop + reachability. + +2001-01-26 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Check nexthop points local address or + not. + (bgp_static_update_vpnv4): Set valid flag. + + * bgp_attr.c (bgp_attr_parse): Duplicate attribute check. + (bgp_attr_parse): Well-known attribute check. + + * bgp_open.c (bgp_auth_parse): Authentication is not yet supported. + + * bgp_packet.c (bgp_valid_marker): Check marker is synchronized. + + * bgpd.c (clear_bgp): Send NOTIFICATION Cease when SEND_CEASE is + defined. + + * bgp_snmp.c (bgp4PathAttrTable): Fix compile error. + +2001-01-24 Kunihiro Ishiguro + + * bgpd.c (bgp_network_import_check): New command for IGP network + check. + +2001-01-23 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_scan): Run bgp_process when IGP metric is + changed. Call bgp_process once for each node. + +2001-01-23 "Akihiro Mizutani" + + * bgp_route.c (bgp_info_cmp): Add IGP metric comparison. + +2001-01-23 Kunihiro Ishiguro + + * bgp_route.c (bgp_info_cmp): Add IGP metric comparison. + + * bgp_nexthop.c (bgp_nexthop_lookup): Set IGP metric for valid + IBGP route. + +2001-01-23 "Akihiro Mizutani" + + * bgp_route.c (show_ip_bgp_prefix_longer): Add new commands. + "show ip bgp A.B.C.D/M longer-prefixes" + "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes" + "show ipv6 bgp X:X::X:X/M longer-prefixes" + "show ipv6 mbgp X:X::X:X/M longer-prefixes" + +2001-01-20 "Akihiro Mizutani" + + * bgp_route.c (show_ip_bgp_cidr_only): Add new commands. + "show ip bgp cidr-only" + "show ip bgp ipv4 (unicast|multicast) cidr-only" + +2001-01-18 "Akihiro Mizutani" + + * bgp_route.c (bgp_update): AS path lookup check is done in + bgp_update() not in attr_parse(). + +2001-01-18 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Call bgp_aggregate_decrement() just + before bgp_attr_unintern(). + +2001-01-17 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Now intern is performed very last part + of the BGP packet update procedure. + +2001-01-17 "Akihiro Mizutani" + + * bgp_route.c (bgp_update): When implicit withdraw occur, reuse + existing bgp_info structure. + +2001-01-17 Kunihiro Ishiguro + + * bgp_route.c (bgp_aggregate_decrement): Fix bug of aggregate + address matching method. + (bgp_update): + + * bgp_nexthop.c (bgp_nexthop_onlink): Separate EBGP nexthop onlink + check and IBGP nexthop route check. + +2001-01-16 "Akihiro Mizutani" + + * bgp_route.h (BGP_INFO_ATRR_CHANGED): Added for track attribute + change. + +2001-01-16 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info): Remove selected flag. Use + BGP_INFO_SELECTED for flags instead. + (struct bgp_info): Remove valid flag. Use BGP_INFO_VALID for + flags instead. + (struct bgp_info): Add igpmetric for IBGP route nexthop IGP + metric. + (struct bgp_info_tab): Struct bgp_info_tag is integrated into + struct bgp_info. + (BGP_INFO_ATRR_CHANGED): Added for track attribute change. + + * bgp_community.c (community_val_get): gcc-2.95 on + sparc-sun-solaris cause crush. This function is for avoid the + crush. + +2001-01-15 Kunihiro Ishiguro + + * bgp_packet.c (bgp_open_receive): Translated peer's packet_size + clear bug is fixed. + +2001-01-14 "Akihiro Mizutani" + + * bgp_packet.c (bgp_open_receive): Return notification with + supported version number. + +2001-01-13 Kunihiro Ishiguro + + * bgpd.c (bgp_show_summary): Display AS path and community + entries. Suggested by: "Matt Ranney" . + + * bgp_packet.c (bgp_read_packet): Fix bug of unblocking BGP socket + read. When BGP packet read is partial, we must get size and type + from packet again. + +2001-01-12 "Akihiro Mizutani" + + * bgp_route.c (bgp_update): Do not unset BGP_INFO_HISTORY flag. + (bgp_update): When there is a history entry increment route count. + (bgp_damp_set): Check BGP_CONFIG_DAMPENING flag. + + * bgp_damp.c (bgp_damp_withdraw): Set status to + BGP_DAMP_DISCONTINUE. + +2001-01-11 Kunihiro Ishiguro + + * bgp_attr.c (bgp_mp_reach_parse): Fix warning code when second + IPv6 nexthop is not link-local addresss. + +2001-01-11 "Akihiro Mizutani" + + * bgp_damp.c (bgp_config_write_damp): Smart flap dampening + configuration display. + (bgp_damp_info_print): Display elapsed time from flap started. + + * bgp_damp.h (struct bgp_damp_info): Add flap start time. + + * bgpd.c (peer_create): Set last read time. + (bgp_show_peer): Display last read time. + (bgp_show_summary): Use BGP_CONFIG_DAMPENING flag to check + configuration. + + * bgpd.h (BGP_CONFIG_DAMPENING): Add new configuration option. + (struct peer): Add last read time member. + (BGP_VERSION_MP_4): Remove obsolete definition. + +2001-01-10 Kunihiro Ishiguro + + * bgp_nexthop.c: Remove OLD_RIB codes. + + * bgp_route.c (bgp_process): Likewise. + + * zebra-0.90 is released. + + * bgp_route.h (BGP_INFO_HISTORY): Remove damped member from struct + bgp_info. Instead of that use BGP_INFO_DAMPED flag. + (struct bgp_info): Remove invalid member from struct bgp_info. + Instead of that use BGP_INFO_HISTORY flag. + +2001-01-10 "Akihiro Mizutani" + + * bgp_damp.c (bgp_damp_info_print): New function to display + dampening status. + (DEFAULT_HARF_LIFE): Define default value. + (DEFAULT_REUSE): Likewise. + (DEFAULT_SUPPRESS): Likewise. + (bgp_config_write_damp): When config value is same as default + value, simply display "bgp dampening" to configuration. + + * bgp_damp.h (struct bgp_damp_info): Add flap member. + + * bgp_route.h (struct bgp_info): Added for BGP flap dampening + history status. + +2001-01-10 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_connected_add): Point-to-point connected + address is properly handled. + (bgp_connected_delete): Likewise. + + * bgp_route.c (bgp_route_init): Turn off BGP Flap dampening code + until it works fine. + +2001-01-09 Kunihiro Ishiguro + + * bgpd.c (bgp_show_summary): Add BGP_VERSION_MP_4 case. + + * bgp_route.c (bgp_update): When this is not damped route, clear + ri pointer. + +2001-01-09 Kunihiro Ishiguro + + * bgp_main.c: Add "-n" no_kernel option to not install route to + kernel. Suggested by: "Matt Ranney" + +2001-01-09 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_connected_add): Revert point-to-point + connected route patch. Reported by ruud@ruud.org (Ruud de Rooij) + + * bgp_damp.c (bgp_config_write_damp): Add configuration display + function. + + * bgp_route.c (bgp_info_free): Set NULL to BGP dampening + information when BGP info structure is freed. + (bgp_info_cmp): Check damped flag. + (bgp_announce_check): Damped route is not announced. + +2001-01-09 "Akihiro Mizutani" + + * bgpd.c (neighbor_capability_route_refresh): Change "neighbor + route-refresh" command to "neighbor capability route-refresh". + (clear_bgp_soft_in): Change soft-reconfig method. + + clear ip bgp soft in + -------------------------------------- + Try stored cache first then route-refresh + + clear ip bgp in + --------------------------------- + Try route-refresh first then try to use stored cache + +2001-01-09 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_connected_add): Check point-to-point + connected route. Reported by ruud@ruud.org (Ruud de Rooij) + +2001-01-08 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_nexthop_lookup): When IBGP nexthop is + changed, refresh it. + +2001-01-04 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info_tag): Add as_selected to + bgp_info_tag. + +2001-01-03 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info_tag): Add damped and bgp_damp_info + member for BGP flap dampening. + + * bgp_damp.c: New file is added. + + * bgp_damp.h: Likewise. + +2001-01-01 Kunihiro Ishiguro + + * bgpd.h (BGP_VTYSH_PATH): Change "/tmp/bgpd" to "/tmp/.bgpd". + +2000-12-29 Kunihiro Ishiguro + + * bgp_nexthop.c (zlookup_connect): Change to use UNIX domain + socket for zebra communication. + +2000-12-29 Akihiro Mizutani + + * bgp_route.c (bgp_process): Fix "bgp deterministic-med" process. + +2000-12-27 Akihiro Mizutani + + * bgp_route.c (bgp_process): Add "bgp deterministic-med" process. + +2000-12-25 Akihiro Mizutani + + * bgp_route.c (bgp_info_cmp): Use ntohl comparing router ID. + +2000-12-18 Akihiro Mizutani + + * bgp_route.c (bgp_info_cmp): When over three same prefix exit, + withdrawing best prefix perform router ID comparison. + +2000-12-15 Akihiro Mizutani + + * bgp_route.c (bgp_info_cmp): Do not compare router ID when the + routes comes from EBGP peer. When originator ID is same, take + shorter cluster-list route. If cluster-list is same take smaller + IP address neighbor's route. + + * bgpd.c (bgp_bestpath_aspath_ignore): Add "bgp bestpath as-path + ignore" command. When this option is set, do not concider AS path + length when route selection. + (bgp_bestpath_compare_router_id): Add "bgp bestpath + compare-routerid". When this option is set, compare router ID + when the routes comes from EBGP peer. + +2000-12-15 Akihiro Mizutani + + * bgp_route.c (bgp_info_cmp): Compare originator ID when it is + available. + +2000-12-14 Akihiro Mizutani + + * bgp_packet.c (bgp_notify_receive): Disply received Notify data + information. + +2000-12-14 Kunihiro Ishiguro + + * bgp_filter.c (as_filter_free): Use MTYPE_AS_FILTER_STR to make + it sure the memory is freed. + + * bgp_route.c (route_vty_out_detail): Do not use AF_INET6 outside + HAVE_IPV6. + +2000-12-08 Akihiro Mizutani + + * bgp_packet.c (bgp_notify_send_with_data): Store BGP notification + data part. + + * bgp_network.c (bgp_accept): When BGP connection comes from + unconfigured IP address, close socket immediately. + + * bgpd.c: Fix some display format. + +2000-11-29 Kunihiro Ishiguro + + * bgp_packet.c (bgp_keepalive_send): Delete duplicate + bgp_packet_set_size () call. + +2000-11-28 Kunihiro Ishiguro + + * bgp_packet.c (bgp_read_packet): Remove debug codes. + +2000-11-27 Kunihiro Ishiguro + + * bgp_snmp.c (write_bgpPeerTable): Add SNMP set method routine. + + * bgp_fsm.c (bgp_stop): Use fsm_change_status to change peer's + status. + (bgp_establish): Likewise. + +2000-11-26 Akihiro Mizutani + + * bgp_open.c: Fix error messages. + +2000-11-25 Kunihiro Ishiguro + + * bgp_fsm.c (bgp_establish): Call BGP trap when the peer is + established. + (bgp_stop): Call BGP trap when the peer is dropped. + +2000-11-24 Kunihiro Ishiguro + + * bgp_snmp.c (bgp4PathAttrTable): Return BGP path attribute table. + + * bgpd.h (struct peer): Add update_time for track last update + received time. + + * bgp_packet.c (bgp_notify_receive): Preserv notify code and sub + code in any case. + + * bgp_snmp.c (bgpPeerTable): Return remote router ID instead of + peering IP address. + (bgpPeerTable): Return actual BGP version number. + +2000-11-22 Akihiro Mizutani + + * bgp_debug.c (bgp_notify_print): Notify data length display bug + is fixed. + +2000-11-16 Kunihiro Ishiguro + + * bgp_nexthop.c (zlookup_connect): When UNIX domain connection to + zebra is enabled, use the method. + +2000-11-16 Akihiro Mizutani + + * bgpd.c: Revise debug message output. + +2000-11-15 Akihiro Mizutani + + * bgp_clist.c (ip_community_list): Fix bug of string comparison. + +2000-11-14 Akihiro Mizutani + + * bgp_community.c (community_match): Fix bug of memcmp return + value check. + +2000-11-07 Kunihiro Ishiguro + + * bgp_clist.c (community_list_match_exact): Add check for + entry->style is COMMUNITY_LIST. + (community_match_regexp): Apply new com_nthval macro. + +2000-11-07 Rick Payne + + * bgp_routemap.c (route_set_community_delete): "set + community-delete COMMUNITY-LIST" is added. + + * bgp_community.c (community_del_val): Delete one community. + (community_delete): Delete all community included in list. + (community_match): Fix bug of matching community value. + + * bgp_clist.c (community_entry_free): Free community regular + expression. + (community_entry_make): Default style is COMMUNITY_LIST. + (community_entry_lookup): Make it sure style is COMMUNITY_LIST. + (community_entry_regexp_lookup): New function for community + regular expression lookup. + (community_match_regexp): New function. + (community_delete_regexp): New function. + (community_list_delete_entries): New function. + (community_list_match): Add COMMUNITY_REGEXP treatment. + (community_list_match_exact): Likewise. + (config_write_community): Write community list according to + entry->style. + +2000-11-07 Rick Payne + + * bgp_attr.c (bgp_attr_aspath): AS path first AS check. + + * bgp_clist.c (struct community_entry): Add style, regexp, reg to + community_entry. + +2000-11-06 Rick Payne + + * bgp_aspath.c (aspath_firstas_check): AS path first AS check. + + * bgpd.c (bgp_enforce_first_as): New command "bgp + enforce-first-as". + + * bgpd.h (BGP_CONFIG_ENFORCE_FIRST_AS): Add new flag. + +2000-11-06 Kunihiro Ishiguro + + * bgp_community.c (community_compare): Copy byte stream data to + actual value instead of using type casting hack. + (community_add_val): Likewise. + (community_uniq_sort): Likewise. + (community_print): Likewise. + (community_print_vty): Likewise. + (community_include): Use memcmp to compare community value. + + * bgp_community.h (com_lastval): com_lastval and com_nthval macro + return pointer. + +2000-11-06 Akihiro Mizutani + + * bgpd.h (struct peer): Add established and dropped member for + count peering up/down statistics. + + * bgpd.c (bgp_show_peer): Display peering up/down statistics. + + * bgp_fsm.c (bgp_establish): Increment established count. + (bgp_stop): Increment dropped count. + + * bgp_packet.c (bgp_notify_receive): Increament notify count. + +2000-11-1 Akihiro Mizutani + + * bgp_fsm.c: Fix bug of holdtimer is not reset when bgp cleared. + +2000-10-31 Kunihiro Ishiguro + + * bgpd.h: Static bit flag is set by (1 << DIGIT). + +2000-10-24 Akihiro Mizutani + + * bgp_ecommunity.c (ecommunity_dup): Extended community display + format fix. + +2000-10-24 Arkadiusz Miskiewicz + + * bgp_network.c (bgp_serv_sock_addrinfo): Use gai_strerror. + (bgp_serv_sock_addrinfo): Check address family. + +2000-10-23 Jochen Friedrich + + * bgp_snmp.c: bgp_oid and bgpd_oid are used in smux_open after it + is registered. So those variables must be static. + +2000-10-23 Akihiro Mizutani + + * bgp_routemap.c (route_match_ip_next_hop): Change "match ip + next-hop" argument from IP address to access-list name. + Remove zebra-0.88 compatibility commands. + "match ip prefix-list WORD" + "match ipv6 prefix-list WORD" + +2000-10-23 Kunihiro Ishiguro + + * bgp_routemap.c (route_match_ipv6_next_hop_compile): Fix bug of + passing the pointer to the pointer of struct in6_addr instead of + the pointer of struct in6_addr in "match ipv6 next-hop" command. + + * bgp_route.c (bgp_announce_check): Enclose IPv6 part with + HAVE_IPV6. + +2000-10-20 Jasper Wallace + + * bgp_snmp.c (bgpPeerTable): ntohs missing bug is fixed. Change + to use linklist.c. Define COUNTER32 as ASN_COUNTER. + +2000-10-18 Kunihiro Ishiguro + + * bgp_route.c (bgp_announce_check): attr->nexthop empty check + should be done by attr->nexthop.s_addr instead of strcmp. + +2000-10-18 Akihiro Mizutani + + * bgp_zebra.c (zebra_read_ipv4): Pass nexthop value to + bgp_redistribute_add(). + + * bgp_nexthop.c (bgp_multiaccess_check_v4): New function for + checking IPv4 multiaccess nexthop. + + * bgp_route.c (bgp_announce_check): In case of the nexthop is + reachable on multiaccess media, do not change nexthop. + (bgp_redistribute_add): Set nexthop when the value is passed. + +2000-10-17 Kunihiro Ishiguro + + * bgp_fsm.c (bgp_timer_set): If peer is passive mode, do not set + connect timer. + (bgp_start): If the peer is passive mode, force to move to Active + mode. + +2000-10-17 Horms + + * bgp_debug.c (debug_bgp_fsm): Fix typo. + +2000-10-17 Akihiro Mizutani + + * bgp_route.c: "show ipv6 bgp" route display improvement. + +2000-10-03 Kunihiro Ishiguro + + * bgp_route.c (neighbor_routes): Allocate sockunion for callback + function. + (bgp_show_neighbor_route): Remove static declaration for union + sockunion. + + * bgpd.c (peer_update_source_set): Clean previously allocated + memory before allocate new one. + +2000-10-03 Akihiro Mizutani + + * bgp_route.c (neighbor_routes): Add show neighbor's routes + command. + "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes" + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes" + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes" + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes" + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-10-02 Akihiro Mizutani + + * bgpd.c: "bgp deterministic-med" command is added. + +2000-10-02 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_connected_add): Apply mask for connected + route addition and deletion. + +2000-09-29 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_cmp_left): Skip confederation AS segment + when comparing leftmost AS number. + +2000-09-29 Akihiro Mizutani + + * bgpd.c (peer_route_reflector): Route reflector can be set for + IBGP peer. + (bgp_distribute_set): Fix bug of string check for (in|out). + (bgp_show_summary): Display total neighbor count. + +2000-09-28 Akihiro Mizutani + + * bgp_attr.c (bgp_packet_attribute): Only add cluster_list and + originator for clinet to client routes. + (bgp_packet_attribute): Add new cluster_list to the beginning of + existing cluster_list. + (bgp_packet_attribute): Fix bug of originator is rewritten even + when originator is already set. + +2000-09-27 Kunihiro Ishiguro + + * bgpd.c (bgp_client_to_client_reflection): Add new command. + "no bgp client-to-client reflection" + "bgp client-to-client reflection" + + * bgpd.h (BGP_CONFIG_NO_CLIENT_TO_CLIENT): Add new definition. + +2000-09-26 Kunihiro Ishiguro + + * bgp_packet.c (bgp_read): Make BGP packet read to non-blocking + read. + (bgp_read_packet): Likewise. + (bgp_read_packet): When errono is EAGAIN, try to read it again. + + * bgp_fsm.c (bgp_stop): Clear packet size and read buffer. + +2000-09-26 Akihiro Mizutani + + * bgp_routemap.c: Configuration of prefix-list match is shown as + "match ip address prefix-list ". Old configuration "match + ip prefix-list " is left for compatibilitty. + +2000-09-25 Akihiro Mizutani + + * bgpd.h (BGP_CONFIG_MED_MISSING_AS_WORST): Changed from + BGP_CONFIG_MISSING_AS_WORST. + + * bgpd.c (bgp_bestpath_med): Change missing-as-worst syntax. + Old "bgp bestpath missing-as-worst" + New "bgp bestpath med missing-as-worst" + +2000-09-24 Akihiro Mizutani + + * bgp_route.c: Compare MED properly in case of CONFED-IBGP. + +2000-09-21 steve@Watt.COM (Steve Watt) + + * bgp_debug.h: Do not declare debug variables conf_bgp_debug_* and + term_bgp_debug_*. + + * bgp_debug.c: Declare variables here. + +2000-09-21 Akihiro Mizutani + + * bgpd.c: MBGP soft-reconfiguration command is added. + clear ip bgp x.x.x.x ipv4 (unicast|multicast) in + clear ip bgp x.x.x.x ipv4 (unicast|multicast) out + clear ip bgp x.x.x.x ipv4 (unicast|multicast) soft + clear ip bgp <1-65535> ipv4 (unicast|multicast) in + clear ip bgp <1-65535> ipv4 (unicast|multicast) out + clear ip bgp <1-65535> ipv4 (unicast|multicast) soft + clear ip bgp * ipv4 (unicast|multicast) in + clear ip bgp * ipv4 (unicast|multicast) out + clear ip bgp * ipv4 (unicast|multicast) soft + + Change "clear ip bgp vpnv4 x.x.x.x soft" command to + "clear ip bgp x.x.x.x vpnv4 unicast soft". + + "bgp bestpath med confed" command is added. + + * bgpd.h (BGP_CONFIG_MED_CONFED): Add New definition. + +2000-09-18 Rick Payne + + * bgpd.c (bgp_show_peer): Fix misplaced #endif. + +2000-09-12 Akihiro Mizutani + + * bgpd.c (bgp_default_local_preference): Add "bgp default + local-preference" command. + + * bgp_nexthop.c (no_bgp_scan_time): Add "no bgp scan-time" + command. + +2000-09-10 Kunihiro Ishiguro + + * bgp_zebra.c (bgp_zebra_announce): BGP confederation peer's routes + are passed to zebra like IBGP route. + +2000-09-10 Akihiro Mizutani + + * bgpd.c (bgp_config_write_peer): Make it consistent passive + configuration. + + * bgp_route.c: Community match command is added. + "show ip bgp community " + "show ip bgp community exact-match" + +2000-09-08 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_nexthop_lookup): ebgp-multihop routes are + treated as IBGP routes. + +2000-09-08 Akihiro Mizutani + + * bgp_route.c (bgp_show_route): When local-AS community route is + selected, display "not advertised outside local AS" to "show ip + route A.B.C.D" output. + (show_ip_bgp_ipv4_filter_list): Add below four commands. + "show ip bgp ipv4 (unicast|multicast) filter-list WORD" + "show ip bgp ipv4 (unicast|multicast) community" + "show ip bgp ipv4 (unicast|multicast) community-list WORD" + "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match" + + * bgp_clist.c (community_list_match_exact): Community exact match + function. + +2000-09-07 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Add peer's ttl check. + + * bgpd.h (struct peer): Structure member refresh is renamed to + refresh_adv. + + * bgpd.c (clear_bgp_soft_in): Check PEER_FLAG_ROUTE_REFRESH flag + when soft reconfiguration is performed. + + * bgp_zebra.c (bgp_zebra_announce): When the peer is EBGP and + ebgp-multiphop is set, set ZEBRA_FLAG_INTERNAL for nexthop lookup. + + * bgp_route.h (struct bgp_info_tag): Add valid flag. + +2000-08-25 Akihiro Mizutani + + * bgpd.c: Add AS base BGP soft reconfiguration. + + * bgp_route.c: When no-advertise or no-export route is selected, + "show ip bgp" display "not advertised to EBGP peer" or "not + advertised to any peer" message. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + + * bgp_dump.c (dump_bgp_routes): Change "dump bgp routes" to "dump + bgp route-mrt" to support MRT specific dump format. + + * bgpd.c (bgp_init): "clear ip bgp vpnv4 soft {in,out}" command is + added. + + * bgp_route.c (bgp_update): Currently nexthop check is only works + for IPv4. + +2000-08-17 Akihiro Mizutani + + * bgpd. (clear_ip_bgp_all_soft): Add "clear ip bgp * soft" for + both inbound and outbound soft reconfiguration. + +2000-08-17 Kunihiro Ishiguro + + * bgpd.c (clear_ip_bgp_peer_soft_out): Add soft-reconfiguration + outbound. + (peer_new): Set route-refresh flag. + +2000-08-16 Akihiro Mizutani + + * bgpd.c: "no bgp router-id A.B.C.D" alias is added. "no bgp + cluster-id A.B.C.D" alias is added. " bgp cluster-id + <1-4294967295>" alias is added. "clear ip bgp * soft in" command + is added. "clear ip bgp A.B.C.D in" alias is added. "clear ip + bgp * in" alias is added. + +2000-08-16 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Add soft_reconfig flag. When the flag + is set do not install the route into Adj-RIBs-In. + (bgp_update): Perform implicit withdraw before filtering of the + route. + + * bgp_packet.c (bgp_read): draft-ietf-idr-bgp-route-refresh-01.txt + capability code and BGP message can be accepted. + + * bgp_open.c (bgp_capability_parse): Likewise. + + * bgp_route.c (bgp_refresh_table): New function for route refresh. + (bgp_refresh_rib): Likewise. + + * bgpd.c (bgp_show_peer): Display route refresh status. + + * bgp_route.c (bgp_aggregate_add): Add check for the route + validness. + (bgp_aggregate_delete): Likewise. + +2000-08-15 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_scan): Care for aggregate route when the + route become inaccessible. + +2000-08-15 Akihiro Mizutani + + * bgp_route.c (show_ip_bgp_prefix): "show ip bgp A.B.C.D/M" + command is added. + +2000-08-15 Kunihiro Ishiguro + + * bgp_zebra.c (bgp_interface_up): Register connected route. + (bgp_interface_down): Unregister connected route. + +2000-08-14 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info): Add distance to the structure. + + * bgp_route.c (bgp_aggregate_increment): Aggregate route only + match to smaller prefixlen route not match same prefixlen route. + (bgp_aggregate_decrement): Likewise. + (bgp_aggregate_add): Likewise. + (bgp_aggregate_delete): Likewise. + (bgp_network_backdoor): Add backdoor network configuration. + + * bgpd.h (struct bgp ): Add distance_{ebgp,ibgp,local} for store + configuration distance value. + + * bgp_route.c (bgp_update): Filter EBGP route which has non + connected nexthop. + + * bgp_attr.c (bgp_attr_aggregate_intern): New function for + aggregate route. Set origin to IGP. Set atomic aggregate flag. + Set aggregator AS and address. + (bgp_attr_aggregate_intern): Check BGP_CONFIG_CONFEDERATION when + filling aggregator_as. + + * bgp_route.c (bgp_process): Delete suppress check for install + suppressed route into local routing table. + (bgp_aggregate_increment): Use bgp_attr_aggregate_intern() instead + of bgp_attr_default_intern (). + (bgp_aggregate_add): Likewise. + + * bgpd.c (bgp_get): Call bgp_if_update_all() after BGP instance is + created. This is for avoid 0.0.0.0 router-id. + +2000-08-13 Akihiro Mizutani + + * bgp_route.c (route_vty_out_detail): Display "valid" when the + route is valied. Display "aggregated" when the route is + aggregated. "Advertisements suppressed by an aggregate" is + displayed when the route is suppressed. + (bgp_info_cmp): Prefer EBGP than Confed-EBGP. + +2000-08-10 Akihiro Mizutani + + * bgp_route.c (route_vty_out_detail): Display format change. + +2000-08-06 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Only AFI_IP nexthop check is enabled. + + * bgpd.c (bgp_delete): Delete static route before delete peer + configuration. + +2000-08-02 Kunihiro Ishiguro + + * bgpd.c: Include bgpd/bgp_nexthop.h. + +2000-07-31 Akihiro Mizutani + + * bgpd.c (bgp_show_summary): "show ip bgp summary" shows own BGP + identifier. And status is changed like below. + + State/Pref -> State/PfxRcd + Shutdown -> Idle (Admin) + PrefixOvflw -> Idle (PfxCt) + + * bgp_route.c (route_vty_out): Show internal route as "i". + +2000-07-13 Jim Bowen + + * bgp_snmp.c: Add BGP peer MIB implementation. + +2000-07-12 Akihiro Mizutani + + * bgpd.c (bgp_show_peer): Fix typo. + +2000-07-11 Akihiro Mizutani + + * bgp_routemap.c: Add commands for deleting set without argument. + +2000-07-03 Akihiro Mizutani + + * bgp_zebra.c: Fix redistribute help strings. + +2000-07-01 Kunihiro Ishiguro + + * bgp_route.c (bgp_show): When bgpd works as vtysh server send all + output to vty at once. + +2000-06-13 Kunihiro Ishiguro + + * bgp_mplsvpn.c (no_vpnv4_network): "no network A.B.C.D/M rd WORD + tag WORD" command is added. + + * bgp_ecommunity.c (ecommunity_vty_out): New function added. + +2000-06-12 Kunihiro Ishiguro + + * bgp_route.c (bgp_show): Fix total number of prefix count bug. + + * bgpd.c (bgp_show_peer): Display VPNv4 unicast configuration and + negotiation result in "show ip bgp neighbors". + +2000-06-12 Akihiro Mizutani + + * bgpd.c: Fix help strings. + + * bgpd.h: Likewise. + +2000-06-11 Kunihiro Ishiguro + + * bgp_route.c (bgp_aggregate_unset): Fix bug of checking rn->info + instead of rn. Reported by Akihiro Mizutani . + + * bgp_mplsvpn.c (vpnv4_network): For testing purpose, "network + A.B.C.D rd RD" is added to address-family vpnv4 unicast node. + + * bgp_route.c (bgp_static_set): Set safi to p.safi. + +2000-06-10 Kunihiro Ishiguro + + * bgp_route.c (bgp_show_prefix_list): Change to use bgp_show(). + (bgp_show_regexp): Change to use bgp_show(). + (show_adj_route): Change to display header. + + * bgpd.c (clear_bgp): Set peer->v_start to default value when peer + is cleared manually. + + * bgp_route.c (bgp_show_route): New function which display + specific BGP route. Divided from bgp_show(). + (bgp_static_delete): Delete all static route. + +2000-06-09 NOGUCHI Kay + + * bgp_route.c (show_ipv6_bgp): "show ipv6 bgp" is broken with + invalid privious fix. Now show_ipv6_bgp and show_ipv6_bgp_route + take care of "show ipv6 bgp [X:X::X:X]". Same change for "show ip + mbgp" and "show ipv6 mbgp". + +2000-06-07 Akihiro Mizutani + + * bgp_route.c: Fix help strings and command arguments. + +2000-06-06 Kunihiro Ishiguro + + * bgp_ecommunity.c: Include prefix.h + +2000-06-05 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info_tag): New structure to hold tag + value. + + * bgp_route.c (bgp_adj_set): table NULL check is added. + (bgp_adj_unset): Likewise. + (bgp_adj_lookup): Likewise. + (bgp_adj_clear): Likewise. + (route_vty_out): Add SAFI check for nexthop display. + (bgp_withdraw): Add SAFI check for withdraw route. + + * Remove all #ifdef MPLS_VPN then include it as default. + + * bgpd.c: Temporary disable peer-group command until the + implementation is completed. + + * bgp_routemap.c (bgp_route_map_init): Install + route_metric_match_cmd. + (route_match_metric_compile): MED value compile using strtoul. + +2000-06-05 Akihiro Mizutani + + * bgp_filter.c: Fix help strings. Change REGEXP to LINE. Change + NAME to WORD. + + * Change command argument to more comprehensive. + + METRIC -> <0-4294967295> + WEIGHT -> <0-4294967295> + LOCAL_PREF -> <0-4294967295> + IP_ADDR -> A.B.C.D + AS -> <1-65535> + AS-PATH-NAME -> WORD + ACCESS_LIST -> WORD + PREFIX_LIST -> WORD + COMMUNITY -> AA:NN + EXT_COMMUNITY -> ASN:nn_or_IP-address:nn + IPv6_ADDR -> X:X::X:X + + * bgp_clist.c: Fix help strings. + +2000-06-03 Kunihiro Ishiguro + + * bgpd.c (peer_active): Add new function for check the peer is + active or not. + (neighbor_activate): New command "neighbor PEER activate" and "no + neighbor PEER activate" are added. + + * bgp_packet.c: Include bgpd/bgp_mplsvpn.h. + +2000-06-02 Akihiro Mizutani + + * bgp_clist.c: Fix commuity-list help strings. + + * bgp_routemap.c: Fix "set community" help strings. Add #define + SET_STR. Use (unicast|multicast) argument for "set nlri" command. + +2000-06-01 Kunihiro Ishiguro + + * bgp_routemap.c (route_set_community_none_cmd): "set community + none" command is added to route-map. + +2000-06-01 Akihiro Mizutani + + * bgp_debug.c: Change "show debug" to "show debugging". Now "show + debugging" is not used in VIEW_NODE. + +2000-05-30 Kunihiro Ishiguro + + * bgp_fsm.c (bgp_timer_set): Add check for shutdown flag. This + fix unconditional BGP connection. + + * bgpd.c (peer_shutdown): Replace peer_shutdown() with + peer_change_flag_with_reset(). + +2000-05-26 Kunihiro Ishiguro + + * bgpd.c (no_bgp_default_ipv4_unicast): Add "no bgp default + ipv4-unicast" command. + + * bgpd.h (BGP_CONFIG_NO_DEFAULT_IPV4): Add new definition. + + * bgp_filter.c (as_list_delete): Free all AS filter. + + * bgp_clist.c (community_list_delete): Free all community entry. + + * bgp_filter.c (no_ip_as_path_all): New DEFUN for "no ip as-path + access-list NAME". + + * bgp_clist.c (no_ip_community_list_all): New DEFUN for "no ip + community-list NAME". + +2000-05-19 Kunihiro Ishiguro + + * bgp_route.c (ipv6_mbgp_neighbor_routes): Change "show ip bgp PEER + routes" to "show ip bgp PEER received-routes" + +2000-05-14 Kunihiro Ishiguro + + * bgp_ecommunity.c (ecommunity_parse): New file for Extended + Communities attribute. + * bgp_ecommunity.h: Likewise. + +2000-05-11 Kunihiro Ishiguro + + * bgp_mplsvpn.h: New file for MPLS-VPN. + * bgp_mplsvpn.c: Likewise. + + * bgpd.c (bgp_delete): Fix bug of "no router bgp" crush. + +2000-05-10 Kunihiro Ishiguro + + * bgpd.c (bgp_bestpath_missing_as_worst): Add "bgp bestpath + missing-as-worst". + +2000-05-08 Kunihiro Ishiguro + + * bgp_routemap.c (match_community): Clarify help of "match + community". + +2000-05-02 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_cmp_left): Remove debug code. + +2000-04-27 Kunihiro Ishiguro + + * bgp_route.c (bgp_info_cmp): Compare MED only both routes comes + from same neighboring AS. + + * bgp_aspath.c (aspath_cmp_left): Compare leftmost AS value. + + * bgp_route.c (bgp_info_cmp): Fix misused htonl() to ntohl(). + +2000-04-26 Kunihiro Ishiguro + + * bgp_route.c (bgp_output_filter): When distribute-list's + corresponding access-list does not exist, filter all routes. + (bgp_input_filter): Likewise. + +2000-04-19 Kunihiro Ishiguro + + * bgp_attr.c (bgp_packet_attribute): Propagate MED to IBGP peer. + + * bgp_route.c (bgp_info_cmp): Add evaluation of local preference. + +2000-04-18 Kunihiro Ishiguro + + * bgpd.c (bgp_distribute_update): Add struct access_list * + argument. + +2000-04-17 Kunihiro Ishiguro + + * bgp_clist.c (community_list_dup_check): Add duplicate insertion + check. + + * bgp_filter.c (as_list_dup_check): Add duplicate insertion check. + + * bgp_route.c (bgp_show): Fix undeclared write variable. + +2000-04-13 Kunihiro Ishiguro + + * bgp_routemap.c: Add "match ip address prefix-list". + +2000-03-29 Rick Payne + + * bgp_aspath.c (aspath_strip_confed): Fix realloc problem. + +2000-03-16 Kunihiro Ishiguro + + * bgp_fsm.c (bgp_reconnect): Connect retry timer is expired when + the peer status is Connect. + +2000-03-03 Kunihiro Ishiguro + + * Fix bug of rewritten originator-id. + +2000-01-27 Rick Payne + + * bgp_aspath.c (aspath_delimiter_char): New function. Instead of + directly referencing array, search proper AS path delimiter. + (aspath_strip_confed): Strip the confederation stuff from the + front of an AS path. + (aspath_add_left_confed): New function for adding specified AS to + the leftmost AS_CONFED_SEQUENCE. + + * bgp_aspath.h: Change AS_CONFED_SEQUENCE and AS_CONFED_SET value + to Cisco compatible. + + * bgpd.c (bgp_confederation_id_set): Confederation configuration. + (bgp_confederation_id_unset): Likewise. + (bgp_confederation_peers_check): Likewise. + (bgp_confederation_peers_add): Likewise. + (bgp_confederation_peers_remove): Likewise. + (bgp_confederation_peers_set): Likewise. + (bgp_confederation_peers_unset): Likewise. + (bgp_confederation_peers_print): Likewise. + +2000-01-16 Kunihiro Ishiguro + + * bgpd.c: Introduce peer_change_flag_with_reset() fucntion. + +2000-01-17 Kunihiro Ishiguro + + * bgp_open.c (bgp_open_option_parse): When there is no common + capability send Unsupported Capability error to the peer. + +2000-01-14 Kunihiro Ishiguro + + * bgp_open.c (bgp_capability_mp): Fix bug of mis-negotiation about + IPv6 unicast. + + * bgpd.c (bgp_init): Add "soft-reconfiguration inbound" command. + +2000-01-12 Kunihiro Ishiguro + + * bgpd.c (neighbor_strict_capability): Add + "strict-capability-match" command. + + * bgp_zebra.c (bgp_if_update): Ignore NET127 determining + router-id. + + * bgpd.c (peer_override_capability): Add "override-capability" + command. + +1999-12-16 Kunihiro Ishiguro + + * bgp_packet.c (bgp_write): Change status to Idle and set timer + after write failed. + +1999-12-14 Kunihiro Ishiguro + + * bgp_zebra.c (bgp_zebra_announce): Add info->selected check. + +1999-12-12 Kunihiro Ishiguro + + * bgp_route.c (nlri_unfeasible): nlri_unfeasible() is merged with + nlri_parse(). + +1999-12-10 Kunihiro Ishiguro + + * bgp_fsm.h (BGP_EVENT_DELETE): Macro added. + + * bgp_fsm.c (bgp_stop): Clear all event threads of the peer when + the peer is cleared. + + * bgp_zebra.c (bgp_nexthop_set): Clear interface index of + link-local address. This is KAME specific problem. + +1999-12-06 Kunihiro Ishiguro + + * bgp_attr.c (bgp_mp_reach_parse): Comment out previous code for a + while. We don't completely detect the link is shared or not at + this moment. + + * bgp_packet.c (bgp_notify_send): Make shortcut call of + bgp_write() and bgp_stop(). + + * bgp_attr.c (bgp_mp_reach_parse): Fix serious bug when getting + global and link-local address. + +1999-12-05 Kunihiro Ishiguro + + * bgpd.c (no_neighbor_port): New command added. + (peer_new): Set send_community. + +1999-12-04 Kunihiro Ishiguro + + * bgpd.c (show_ip_bgp_summary): Changed to use bgp_show_summary(). + (show_ip_mbgp_summary): Likewise. + (show_ipv6_bgp_summary): Likewise. + (show_ipv6_mbgp_summary): Add new command. + (peer_free): Free peer->host. + (peer_lookup_by_su): Delete function. + (ipv6_bgp_neighbor): Changed to use peer_remote_as(). + (sockunion_vty_out): Function deleted. + (vty_clear_bgp): Use afi instead of family. + Delete old list bgp_list. Use struct newlist *bgplist. + (peer_lookup_by_host): Function deleted. + +1999-12-03 Kunihiro Ishiguro + + * bgpd.h (struct peer_group): New structure added. + (struct peer_conf): New structure added. + (struct peer): Change all prefix_count to unsigned long. + + * bgpd.c: Reconstruct all of VTY commands reflect internal + structure change. + Use bgplist instead of bgp_list. + Use peerlist intstead of peer_list. + + * bgp_attr.c (bgp_mp_reach_parse): If nlri_parse return -1, stop + parsing then return immediately. + + * bgp_route.c (nlri_parse): When NLRI parse error occured, return + -1. + (nlri_process): Use pcount_v4_{unicast,multicast}. + (nlri_delete): Likewise. + +1999-11-25 Robert Olsson + + * bgp_routemap.c (route_match_nlri): `match nlri + unicast|multicast' and `set nlri unicast|multicast' command are + added. + +1999-11-22 Robert Olsson + + * bgpd.c: Add translate-update support. + + * bgpd.h (TRANSLATE_UPDATE_OFF): Add translate-update definition. + +1999-11-19 Robert.Olsson@data.slu.se + + * bgp_route.c (bgp_peer_delete): Add MBGP peer clear codes. + +1999-11-14 Kunihiro Ishiguro + + * bgp_open.c (bgp_capability_mp): Temporary comment out + SAFI_UNICAST_MULTICAST handling until we know the meanings. + +1999-11-13 Kunihiro Ishiguro + + * bgp_btoa.c: New file added. + +1999-11-12 Kunihiro Ishiguro + + * bgpd.h (struct peer): Add dont_capability flag. + (struct peer): Add override_capability flag. + + * bgpd.c (neighbor_dont_capability_negotiation): `neighbor PEER + dont-capability-negotiation' added. + +1999-11-12 Bill Sommerfeld + + * bgp_attr.c (bgp_mp_reach_parse): Ignore link-local addresses + attribute from non-shared-network peers. + +1999-11-10 Kunihiro Ishiguro + + * bgp_snmp.c: New file added. + + * BGP4-MIB.txt: Updated to the latest Internet-Draft + draft-ietf-idr-bgp4-mib-04.txt. + +1999-11-09 Kunihiro Ishiguro + + * bgp_route.c (bgp_route_init): Add `show ipv6 bgp prefix-list'. + + * bgp_attr.c (bgp_mp_unreach_parse): Enclose safi setup with + #ifdef HAVE_MBGPV4. + +1999-11-08 Kunihiro Ishiguro + + * bgp_dump.c (no_dump_bgp_all): Add [PATH] and [INTERVAL] to no + dump bgp commands. + (config_write_bgp_dump): Write interval value to the + configuration. + +1999-11-07 Kunihiro Ishiguro + + * bgp_zebra.c: Redistribute route-map support is added. + + * bgp_zebra.h: New file added. + +1999-11-04 Kunihiro Ishiguro + + * bgp_dump.c: BGP packet dump routine compatible with MRT. + * bgp_dump.h: BGP packet dump routine compatible with MRT. + + * bgp_debug.c: Renamed from bgp_dump.c + * bgp_debug.h: Renamed from bgp_dump.h + +1999-10-27 Kunihiro Ishiguro + + * BGP4-MIB.txt: New file added. Edited version of RFC1657. + +1999-10-25 Bill Sommerfeld + + * bgp_route.c (bgp_announce): If we're not on a shared network + with the peer and we don't have a link-local next hop, but the + inbound next-hop has a link-local address, don't readvertise it to + our peer. + +1999-10-25 Marc Boucher + + * bgp_zebra.c: Add redistribute kernel command. + +1999-10-25 Kunihiro Ishiguro + + * bgp_route.c (bgp_reset): New function added. + + * bgpd.conf.sample2: Add IPv6 configuration sample. + +1999-10-24 Bill Sommerfeld + + * bgp_route.c (ipv6_aggregate_address): Function added. + +1999-10-21 Kunihiro Ishiguro + + * bgp_packet.c (bgp_update): Unintern aspath, community, cluster + list after parsing BGP update packet. + + * bgp_attr.c (bgp_attr_aspath): Intern parsed aspath. + (bgp_attr_community): Intern parsed community. + (bgp_attr_cluster_list): Intern parsed cluster list. + + * bgp_routemap.c: Add `set community-additive' command. + +1999-10-21 Alexandr D. Kanevskiy + + * bgp_routemap.c (route_set_local_pref): Fix bug of setting + attribute flag. + +1999-10-21 Bill Sommerfeld + + * bgp_route.c (bgp_announce): Add check of IPv6 default route + announcement. + + * bgp_packet.c (bgp_update_send): Add BGP announcement logging. + +1999-10-15 Kunihiro Ishiguro + + * `show ip[v6] bgp PREFIX' show uptime of the route. + +1999-10-04 Kunihiro Ishiguro + + * bgpd.c (bgp_filter_set): Delete PEER_FAMILY_{IPV4,IPV6}. instead + of that use AF_INET and AF_INET6 directly. + (vty_clear_bgp): Add new function to support various clear ip bgp + method. + +1999-10-04 Lars Fenneberg + + * bgpd.c (clear_ip_bgp): Add `clear ip bgp ASN'. + +1999-10-03 Kunihiro Ishiguro + + * bgp_routemap.c: Add `match ip prefix-list' and `match ipv6 + prefix-list'. + +1999-09-28 Kunihiro Ishiguro + + * bgpd.c (bgp_collision_detect): Add BGP collision detection + function. + +1999-09-26 Blake Meike + + * bgpd.c (neighbor_port): New command `neighbor PEER port PORT' is + added. + +1999-08-24 Kunihiro Ishiguro + + * bgpd.c (no_neighbor_timers_keepalive): Change MIN to min. Add + min() macro. + +1999-08-19 Rick Payne + + * bgp_packet.c (bgp_open): BGP holdtimer bug is fixed. Make BGP + keepalive timer configurable. + +1999-08-15 Kunihiro Ishiguro + + * bgp_zebra.c (bgp_redistribute_set): Fix redistribute bug. + +1999-08-13 Kunihiro Ishiguro + + * bgpd.c (bgp_peer_display): show ip bgp neighbors PEER only list + the peer not all of them. + +1999-08-11 Rick Payne + + * bgp_route.c (bgp_announce): Remove MED if its an EBGP peer - + will get overwritten by route-maps. + +1999-08-08 Rick Payne + + * bgp_routemap.c: Multi protocol route-map modification. + +1999-08-01 Kunihiro Ishiguro + + * bgp_route.c: Set network statement route's origin attribute as + igp. + + * bgp_zebra.c: Set redistribute route's origin attribute as + incomplete. + + * bgp_route.c (bgp_info_cmp): Add attribute existance check, + origin attribute check, BGP peer type check. + +1999-07-30 Kunihiro Ishiguro + + * bgp_route.c (bgp_peer_delete): Reselect of IPv6 route. + +1999-07-29 Rick Payne + + * Changed route-maps to behave in a more cisco-like fashion + +1999-07-27 Kunihiro Ishiguro + + * bgp_fsm.c (bgp_stop): Very serious bug of bgp_stop () is fixed. + When multiple route to the same destination exist, bgpd try to + announce the information to stopped peer. Then add orphan write + thread is added. This cause many strange behavior of bgpd. + Reported by Georg Hitsch . + +1999-07-23 Kunihiro Ishiguro + + * bgpd.c: Change peer's A.B.C.D to PEER. + +1999-07-22 Kunihiro Ishiguro + + * bgp_route.c (bgp_announce): Add hack for link-local nexthop. + + * bgp_zebra.c (bgp_zebra_announce): Fill in nexthop address from + local address. + +1999-07-21 Kunihiro Ishiguro + + * bgp_packet.c (bgp_open): Holdtime fetch bug is fixed. Reported + by Yuji SEKIYA . + +1999-07-15 Kunihiro Ishiguro + + * bgp_fsm.c (fsm_holdtime): Don't close file descriptor in + fsm_holdtime (). + +1999-07-11 Kunihiro Ishiguro + + * bgp_routemap.c: Add `set atomic-aggregate' command. + +1999-07-06 Kunihiro Ishiguro + + * bgp_routemap.c (route_set_ip_nexthop_cmd): Change "ip nexthop" + to "ip next-hop". + +1999-07-02 Kunihiro Ishiguro + + * bgp_route.c (show_ipv6_bgp_regexp): `show ipv6 bgp regexp' + added. + +1999-07-01 Rick Payne + + * bgp_zebra.c (zebra_init): Install standard commands to + ZEBRA_NODE. + +1999-06-28 Rick Payne + + * bgpd.c (bgp_delete): bgp peer deletion bug is fixed. + +1999-06-25 Kunihiro Ishiguro + + * bgpd.c: Add neighbor update-source command as ALIAS to + neighbor_interface. + +1999-06-19 Kunihiro Ishiguro + + * bgp_attr.c (bgp_packet_attribute): Send community attribute when + send_community flag is set. + + * bgpd.h (struct peer): Add send_community flag. + +1999-06-12 Kunihiro Ishiguro + + * bgpd.c (router_bgp): router bgp's argument changed from AS_NO to + <1-65535>. + +1999-06-08 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info): Add subtype for BGP route type. + +1999-06-07 Kunihiro Ishiguro + + * bgp_community.c (community_merge): Function added. + +1999-06-04 Kunihiro Ishiguro + + * bgp_clist.c: New file. + * bgp_clist.h: New file. + + * bgp_community.h (COMMUNITY_LOCAL_AS): Added for Cisco + compatibility. + (COMMUNITY_NO_ADVERTISE): Fix typo. + +1999-05-30 Kunihiro Ishiguro + + * bgp_routemap.c: Add `set weight WEIGHT' command. + + * bgpd.c: Remove all_digit_check function. Instead of that use + all_digit function in lib/prefix.c. + + * bgp_routemap.c (bgp_route_map_init): Install + no_set_ipv6_nexthop_global_cmd and no_set_ipv6_nexthop_local_cmd + element to the RMAP_NODE. + +1999-05-28 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_make_str): Declare aspath_delimiter_char + inside aspath_make_str function. + (aspath_prepend): New function is added for AS path prepend. + (aspath_make_str_count): Renamed from aspath_make_str. AS path + count is set to the structure. + (aspath_merge): New function. + +1999-05-22 Kunihiro Ishiguro + + * bgp_zebra.c (redistribute_bgp): Add new DEFUN. + (no_redistribute_bgp): Likewise. + (router_zebra): Semantics changed. Now 'router zebra' is default + behavior of bgpd. + +1999-05-14 Kunihiro Ishiguro + + * bgp_routemap.c: Add some commands to bgp route-map. + match ip next-hop: New command. + match metric: New command. + set metric: Doc fix. + set local-preference: Add DEFUN. + +1999-05-14 Stephen R. van den Berg + + * bgp_main.c (signal_init): SIGTERM call sigint. + (sigint): Loggging more better message. + +1999-05-12 Kunihiro Ishiguro + + * bgp_attr.c (bgp_packet_attribute): AS path attribute extended + length bit check is added. + +1999-05-11 Kunihiro Ishiguro + + * bgp_routemap.c (bgp_route_map_init): Call route_map_install_set + function with route_set_local_pref_cmd argument. + (no_match_aspath): Function added. + (route_set_metric): Set attribute flag bit. + + * bgp_attr.c (bgp_packet_attribute): MULTI_EXIT_DISC is now in BGP + packet. + +1999-05-07 Kunihiro Ishiguro + + * bgpd.c (no_neighbor_timers_holdtime): `no neighbor PEER timers + holdtime' command is added. + + * bgpd.h (BGP_DEFAULT_HOLDTIME_BIG): Delete define. + + * bgpd.c (bgp_prefix_list_set): New function added. + (bgp_prefix_list_unset): Likewise. + (bgp_prefix_list_update): Likewise. + (show_ip_bgp_neighbors): prefix-list information display. + +1999-05-06 Kunihiro Ishiguro + + * bgpd.c (bgp_delete): Function added for `no router bgp'. + +1999-05-05 Kunihiro Ishiguro + + * bgp_dump.c (bgp_dump_attr): Add originator_id display. + + * bgpd.c (bgp_router_id): Even when address is malformed set the + value to configuration bug fixed. + (no_bgp_router_id): New function. + (no_bgp_cluster_id): New function. + +1999-05-04 Kunihiro Ishiguro + + * bgpd.h (BGP_ATTR_ORIGINATOR_ID): Changed from BGP_ATTR_ORIGINATOR. + +1999-05-02 Kunihiro Ishiguro + + * bgp_route.c (bgp_announce): Add route reflector check. + +1999-05-01 Kunihiro Ishiguro + + * bgpd.c (bgp_cluster_id): Add function for route reflector. + (neighbor_route_reflector_client): Likewise. + (no_neighbor_route_reflector_client): Likewise. + + * bgpd.h (struct bgp ): Add cluster for route reflector. + + * bgp_route.c (show_ip_bgp_prefix_list): New command is added. + +1999-04-24 Kunihiro Ishiguro + + * Makefile.am (noinst_HEADERS): Add bgp_filter.h + + * bgp_aspath.c (aspath_undup): Function deleted. aspath_free () + has same functionality. + + * bgp_filter.h: New file. + + * bgp_aspath.c (aspath_unintern): Rename aspath_free () to + aspath_unintern () + (aspath_free): New function. + +1999-04-23 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_aggregate): Function added. + + * bgp_aspath.h (aspath_aggregate): Prototype added. + + * bgp_aspath.c (aspath_empty_aspath): New argument + gated_dont_eat_flag is added. + +1999-04-18 Kunihiro Ishiguro + + * bgp_route.c: Add bgp_aggregate_ipv4 and bgp_aggregate_ipv6. + +1999-04-17 Kunihiro Ishiguro + + * bgp_route.c (aggregate_address): Function added. + + * bgp_zebra.c (zebra_read): Change log to zlog. + +1999-04-15 Kunihiro Ishiguro + + * Makefile.am (noninst_HEADERS): Added for make dist. + +1999-04-09 Kunihiro Ishiguro + + * aspath_regex.c: Removed from distribution. + +1999-04-07 Kunihiro Ishiguro + + * bgp_attr.c (bgp_packet_attribute): Old draft-00 packet treatment + bug fixed. + +1999-04-06 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_add_left): Fix empty aspath bug. Reported + by kad@gibson.skif.net. + + * bgp_regex.[ch]: New file added. + + +1999-04-05 Kunihiro Ishiguro + + * bgp_filter.c: New file added. + +1999-04-01 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_empty_aspath): Change for peering with + gated. + +1999-03-24 Kunihiro Ishiguro + + * bgp_main.c (main): Default loggin method changed from syslog to + stdout. + +1999-03-05 Kunihiro Ishiguro + + * bgp_route.c: Delete obsolete default attribute DEFUN. + +1999-03-04 Kunihiro Ishiguro + + * bgp_attr.c: Make attribute structure put into attribute hash. + +1999-03-02 Kunihiro Ishiguro + + * bgp_view.c : Delete file. + +1999-02-25 Kunihiro Ishiguro + + * bgp_routemap.c (bgp_apply_route_map): Add prefix argument. + + * bgp_route.h (struct bgp_info): Add bgp_info structre. I'll + replace bgp_route with this. + + * bgp_routemap.c (route_match_ip_address): Fix bug of passing non + prefix value to access_list_apply(). + + * bgpd.conf.sample: Add route-map sample. + Delete obsolete default-attr statements. + + * bgp_packet.c: Use stream_fifo for packet queueing. + +1999-02-24 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_add_left): add non empty aspath treatment. + + * bgp_main.c: include unistd.h for daemon(). + + * bgp_route.c (nlri_process): add IPv6 table lookup. + + * bgp_attr.c (route_parse_ipv6): call nlri_process(). + (attr_make): Obsolete function attr_make deleted. + +1999-02-22 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_add_left): change function name from + aspath_add_leftmost_as(). + +1999-02-21 Kunihiro Ishiguro + + * bgp_aspath.c: add aspath_add_leftmost_as (). + +1999-02-18 Peter Galbavy + + * syslog support added + +1999-01-26 Kunihiro Ishiguro + + * bgpd.c: DEFUN (neighbor_nexthop): deleted. + DEFUN (neighbor_distribute_list): added. + +1999-01-19 Kunihiro Ishiguro + + * bgpd.h (struct peer ): header_buf and read_buf is removed. + + * bgp_peer.[ch]: Deleted. Peer related functions are merged to + bgpd.c + + * bgp_network.c: New file. + * bgp_network.h: New file. + + * bgp_packet.h: New file. + +1999-01-11 Kunihiro Ishiguro + + * bgp_packet.c (bgp_keepalive_send): Now BGP keepalive packet is + buffered. + +1999-01-08 Kunihiro Ishiguro + + * bgp_packet.c: New file. + +1998-12-22 Kunihiro Ishiguro + + * bgp_zebra.c (zebra_client): Use zebra_connect() in lib/client.c. + + * `show ip bgp' bug fixed. + * aspath_log (): Remove argument logfp. + +1998-12-15 Kunihiro Ishiguro + + * bgp_fsm.h: New file. + +1998-12-15 Magnus Ahltorp + + * bgp_attr.c, bgp_community.h, bgp_dump.c, bgp_fsm.c, bgp_open.c + bgp_peer.c, bgp_peer.h, bgp_route.c, bgp_route.h, bgp_view.c + bgpd.c, bgpd.h, bgp_attr.c, bgp_community.h, bgp_dump.c, + bgp_fsm.c, bgp_open.c, bgp_peer.c, bgp_peer.h: Prototype fixes. + +1998-12-09 Kunihiro Ishiguro + + * bgpd.c (bgp_config_write): Delete vector v argument. + +1998-12-07 Kunihiro Ishiguro + + * bgpd.h: Delete annoying ld_[124]byte and st_[124]byte macros. + +1998-11-23 Kunihiro Ishiguro + + * bgp_radix.[ch]: removed. + +1998-09-15 HEO SeonMeyong + + * bgp_main.c: ifdef HYDRANGEA -> ifdef KAME + +1998-08-13 Kunihiro Ishiguro + + * bgp_dump.c: delete nroute(). + +1998-05-19 Yamshita TAKAO + + * bgp_aspath.c: HAVE_CONFIG_H typo :-) + * bgpd.h: Modify for compile on Solaris. + * bgp_aspath.h: likewize + * bgp_community.h: likewize + * bgp_routemap.c: likewize + +1998-05-18 Yamshita TAKAO + + * bgpd.h: Modify for compile on Solaris. + * bgp_aspath.h: likewize + +1998-05-08 Kunihiro Ishiguro + + * routemap.[ch]: move to ../lib directory. + +1998-05-07 Kunihiro Ishiguro + + * routemap.c (route_map_apply): add function. + +1998-05-06 Kunihiro Ishiguro + + * routemap.h: add file. + + * bgp_peer.h (enum ): change PEER_{IBGP,EBGP} to BGP_PEER_{IBGP,EBGP} + +1998-05-03 Kunihiro Ishiguro + + * Makefile.am: sysconfdir_DATA added. + +1998-05-02 Kunihiro Ishiguro + + * bgp_dump.c: add `debug bgp fsm' + add `no debug bgp fsm' + add `show debug bgp' + * bgp_open.c: File added. + +1998-05-01 Kunihiro Ishiguro + + * .cvsignore: File added. + +1998-04-30 Kunihiro Ishiguro + + * bgp_community.[ch]: File added. + +1998-03-04 Kunihiro Ishiguro + + * bgpd now use lib/thread.[ch]. + +1998-01-06 Kunihiro Ishiguro + + * bgpd.c (show_ip_bgp_neighbors): add 'show ip bgp neighbors' command. + + * bgpd.h (BGP_DEFAULT_START_TIMER): change from 1 to 30. + +1997-12-30 Kunihiro Ishiguro + + * bgp_vty.c: bgp_vty.c deleted. + + * bgpd.c (config_write_neighbor): add ebgp-multihop command. + +1997-12-29 Kunihiro Ishiguro + + * bgp_fsm.c: [-p bgp_port] and [-P vty_port] works + +1997-12-06 Kunihiro Ishiguro + + * bgp_vty.c: new file. + + * bgp_attr.c: add new logging system. + +1997-11-23 Kunihiro Ishiguro + + * Change all inet_addr call into inet_aton. + +1997-11-10 Kunihiro Ishiguro + + * bgp_radix.c: change radix_peer_delete + +1997-10-04 Kunihiro Ishiguro + + * bgp_aspath.c: move AS_TOKEN_??? definition from header to c source. + +1997-09-12 Kunihiro Ishiguro + + * bgp_dump.c (bgp_log_route): add dump_attr function + +1997-09-06 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_test): change AS_SET brace from '[' to '{' + * bgp_dump.c (bgp_log_route): change logfile format. + +1997-08-19 Kunihiro Ishiguro + + * bgp_open.c (bgp_open): move bgp_open function from bgpd.c + * bgp_attr.c (community_str2com): add community value generation + * bgp_attr.h: add SAFI definition for BGP-4+ + +1997-08-18 Kunihiro Ishiguro + + * bgpd.h: add BGP_OPEN_OPT_CAP for Capabilities Optional Parameter + * Makefile.in: add bgp_open.o, delete bgp_loop.o + * bgp_open.c: newfile which manages BGP Open message + * bgp_loop.c: this file is merged with bgp_fsm.c + * bgp_radix.c (radix_add): radix_add() now return route_t instead + of int + (bgp_sim): now we can read update & withdraw from file + * bgp_route.c: add route_free() call into route_parse etc. + +1997-08-17 Kunihiro Ishiguro + + * bgp_radix.c: Radix code is completely rewritten. It has better + memory treatment than old one. + +1997-08-14 Kunihiro Ishiguro + + * bgp_route.c: route_alloc for route struct allocation statistics. + * bgpd.c (bgp_make_update): now we cann announce MED attribute. + * bgp_aspath.c (aspath_print_all): change aspath_print_all output + format. + +1997-08-13 Kunihiro Ishiguro + + * bgp_term.c (term_parse): add command : show asstat, show ashash + * bgp_aspath.c: aspath_cmp bug fix + (aspath_print_all): add aspath_print_all (); + * bgp_peer.h: delete rlist element from struct peer. + +1997-08-12 Kunihiro Ishiguro + + * bgp_aspath.c: completely rewritten. + * bgp_aspath.h: completely rewritten. + add AsPath, AsSegment structure + add AS_SET treatment + change Hash codes + +1997-08-09 Kunihiro Ishiguro + + * bgp_attr.h: add Attribute flags defines + * bgp_route.c: delete rlist related functions + * bgp_aspath.c (as_origin): add as_origin function + (aspath_print): move from bgp_dump.c and add support of AS_SET + change Hash related function names. + +1997-08-08 Kunihiro Ishiguro + + * bgp_aspath.h: add next entry, delete rlist entry from struct aspath + +1997-08-04 Kunihiro Ishiguro + + * bgp_aspath.c (as_sort): add function as_sort + * bgp_aspath.h: add IBGP, EBGP + diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am new file mode 100644 index 0000000..535554f --- /dev/null +++ b/bgpd/Makefile.am @@ -0,0 +1,44 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +noinst_LIBRARIES = libbgp.a +sbin_PROGRAMS = bgpd + +libbgp_a_SOURCES = \ + bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \ + bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ + bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ + bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ + bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_tcpsig.c + +noinst_HEADERS = \ + bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ + bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \ + bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ + bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ + bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_tcpsig.h + +bgpd_SOURCES = \ + bgp_main.c $(libbgp_a_SOURCES) + +bgpd_LDADD = ../lib/libzebra.a + +sysconf_DATA = bgpd.conf.sample bgpd.conf.sample2 + +EXTRA_DIST = $(sysconf_DATA) BGP4-MIB.txt + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done diff --git a/bgpd/Makefile.in b/bgpd/Makefile.in new file mode 100644 index 0000000..cf8eb6c --- /dev/null +++ b/bgpd/Makefile.in @@ -0,0 +1,465 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CPP = @CPP@ +CURSES = @CURSES@ +DEPDIR = @DEPDIR@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LIBPAM = @LIBPAM@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA = @INSTALL@ -m 600 + +noinst_LIBRARIES = libbgp.a +sbin_PROGRAMS = bgpd + +libbgp_a_SOURCES = \ + bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \ + bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ + bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ + bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ + bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_tcpsig.c + + +noinst_HEADERS = \ + bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ + bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \ + bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ + bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ + bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_tcpsig.h + + +bgpd_SOURCES = \ + bgp_main.c $(libbgp_a_SOURCES) + + +bgpd_LDADD = ../lib/libzebra.a + +sysconf_DATA = bgpd.conf.sample bgpd.conf.sample2 + +EXTRA_DIST = $(sysconf_DATA) BGP4-MIB.txt +subdir = bgpd +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libbgp_a_AR = $(AR) cru +libbgp_a_LIBADD = +am_libbgp_a_OBJECTS = bgpd.$(OBJEXT) bgp_fsm.$(OBJEXT) \ + bgp_aspath.$(OBJEXT) bgp_community.$(OBJEXT) bgp_attr.$(OBJEXT) \ + bgp_debug.$(OBJEXT) bgp_route.$(OBJEXT) bgp_zebra.$(OBJEXT) \ + bgp_open.$(OBJEXT) bgp_routemap.$(OBJEXT) bgp_packet.$(OBJEXT) \ + bgp_network.$(OBJEXT) bgp_filter.$(OBJEXT) bgp_regex.$(OBJEXT) \ + bgp_clist.$(OBJEXT) bgp_dump.$(OBJEXT) bgp_snmp.$(OBJEXT) \ + bgp_ecommunity.$(OBJEXT) bgp_mplsvpn.$(OBJEXT) \ + bgp_nexthop.$(OBJEXT) bgp_damp.$(OBJEXT) bgp_table.$(OBJEXT) \ + bgp_advertise.$(OBJEXT) bgp_vty.$(OBJEXT) bgp_tcpsig.$(OBJEXT) +libbgp_a_OBJECTS = $(am_libbgp_a_OBJECTS) +sbin_PROGRAMS = bgpd$(EXEEXT) +PROGRAMS = $(sbin_PROGRAMS) + +am__objects_1 = bgpd.$(OBJEXT) bgp_fsm.$(OBJEXT) bgp_aspath.$(OBJEXT) \ + bgp_community.$(OBJEXT) bgp_attr.$(OBJEXT) bgp_debug.$(OBJEXT) \ + bgp_route.$(OBJEXT) bgp_zebra.$(OBJEXT) bgp_open.$(OBJEXT) \ + bgp_routemap.$(OBJEXT) bgp_packet.$(OBJEXT) \ + bgp_network.$(OBJEXT) bgp_filter.$(OBJEXT) bgp_regex.$(OBJEXT) \ + bgp_clist.$(OBJEXT) bgp_dump.$(OBJEXT) bgp_snmp.$(OBJEXT) \ + bgp_ecommunity.$(OBJEXT) bgp_mplsvpn.$(OBJEXT) \ + bgp_nexthop.$(OBJEXT) bgp_damp.$(OBJEXT) bgp_table.$(OBJEXT) \ + bgp_advertise.$(OBJEXT) bgp_vty.$(OBJEXT) bgp_tcpsig.$(OBJEXT) +am_bgpd_OBJECTS = bgp_main.$(OBJEXT) $(am__objects_1) +bgpd_OBJECTS = $(am_bgpd_OBJECTS) +bgpd_DEPENDENCIES = ../lib/libzebra.a +bgpd_LDFLAGS = +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/bgp_advertise.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_aspath.Po ./$(DEPDIR)/bgp_attr.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_clist.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_community.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_damp.Po ./$(DEPDIR)/bgp_debug.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_dump.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_ecommunity.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_filter.Po ./$(DEPDIR)/bgp_fsm.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_main.Po ./$(DEPDIR)/bgp_mplsvpn.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_network.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_nexthop.Po ./$(DEPDIR)/bgp_open.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_packet.Po ./$(DEPDIR)/bgp_regex.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_route.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_routemap.Po ./$(DEPDIR)/bgp_snmp.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_table.Po ./$(DEPDIR)/bgp_tcpsig.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgp_vty.Po ./$(DEPDIR)/bgp_zebra.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bgpd.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CFLAGS = @CFLAGS@ +DIST_SOURCES = $(libbgp_a_SOURCES) $(bgpd_SOURCES) +DATA = $(sysconf_DATA) + +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in +SOURCES = $(libbgp_a_SOURCES) $(bgpd_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign bgpd/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libbgp.a: $(libbgp_a_OBJECTS) $(libbgp_a_DEPENDENCIES) + -rm -f libbgp.a + $(libbgp_a_AR) libbgp.a $(libbgp_a_OBJECTS) $(libbgp_a_LIBADD) + $(RANLIB) libbgp.a +sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \ + rm -f $(DESTDIR)$(sbindir)/$$f; \ + done + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) +bgpd$(EXEEXT): $(bgpd_OBJECTS) $(bgpd_DEPENDENCIES) + @rm -f bgpd$(EXEEXT) + $(LINK) $(bgpd_LDFLAGS) $(bgpd_OBJECTS) $(bgpd_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_advertise.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_aspath.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_attr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_clist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_community.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_damp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_debug.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_dump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_ecommunity.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_filter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_fsm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_mplsvpn.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_network.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_nexthop.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_open.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_packet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_regex.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_route.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_routemap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_snmp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_table.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_tcpsig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_vty.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_zebra.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgpd.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `cygpath -w $<` +CCDEPMODE = @CCDEPMODE@ +uninstall-info-am: +sysconfDATA_INSTALL = $(INSTALL_DATA) + +uninstall-sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(sysconf_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \ + rm -f $(DESTDIR)$(sysconfdir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-sbinPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-sbinPROGRAMS install-sysconfDATA + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \ + uninstall-sysconfDATA + +.PHONY: GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES clean-sbinPROGRAMS distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-sbinPROGRAMS install-strip install-sysconfDATA \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic tags uninstall uninstall-am \ + uninstall-info-am uninstall-sbinPROGRAMS uninstall-sysconfDATA + + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c new file mode 100644 index 0000000..01a3307 --- /dev/null +++ b/bgpd/bgp_advertise.c @@ -0,0 +1,405 @@ +/* BGP advertisement and adjacency + Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro + + This file is part of GNU Zebra. + + GNU Zebra 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, or (at your option) any + later version. + + GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include + +#include "command.h" +#include "memory.h" +#include "prefix.h" +#include "hash.h" +#include "thread.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_advertise.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_mplsvpn.h" + +/* BGP advertise attribute is used for pack same attribute update into + one packet. To do that we maintain attribute hash in struct + peer. */ +static struct bgp_advertise_attr * +baa_new () +{ + return (struct bgp_advertise_attr *) + XCALLOC (MTYPE_BGP_ADVERTISE_ATTR, sizeof (struct bgp_advertise_attr)); +} + +static void +baa_free (struct bgp_advertise_attr *baa) +{ + XFREE (MTYPE_BGP_ADVERTISE_ATTR, baa); +} + +static void * +baa_hash_alloc (struct bgp_advertise_attr *ref) +{ + struct bgp_advertise_attr *baa; + + baa = baa_new (); + baa->attr = ref->attr; + return baa; +} + +static unsigned int +baa_hash_key (struct bgp_advertise_attr *baa) +{ + return attrhash_key_make (baa->attr); +} + +static int +baa_hash_cmp (struct bgp_advertise_attr *baa1, struct bgp_advertise_attr *baa2) +{ + return attrhash_cmp (baa1->attr, baa2->attr); +} + +/* BGP update and withdraw information is stored in BGP advertise + structure. This structure is referred from BGP adjacency + information. */ +static struct bgp_advertise * +bgp_advertise_new () +{ + return (struct bgp_advertise *) + XCALLOC (MTYPE_BGP_ADVERTISE, sizeof (struct bgp_advertise)); +} + +void +bgp_advertise_free (struct bgp_advertise *adv) +{ + XFREE (MTYPE_BGP_ADVERTISE, adv); +} + +void +bgp_advertise_add (struct bgp_advertise_attr *baa, + struct bgp_advertise *adv) +{ + adv->next = baa->adv; + if (baa->adv) + baa->adv->prev = adv; + baa->adv = adv; +} + +void +bgp_advertise_delete (struct bgp_advertise_attr *baa, + struct bgp_advertise *adv) +{ + if (adv->next) + adv->next->prev = adv->prev; + if (adv->prev) + adv->prev->next = adv->next; + else + baa->adv = adv->next; +} + +static struct bgp_advertise_attr * +bgp_advertise_intern (struct hash *hash, struct attr *attr) +{ + struct bgp_advertise_attr ref; + struct bgp_advertise_attr *baa; + + ref.attr = bgp_attr_intern (attr); + baa = (struct bgp_advertise_attr *) hash_get (hash, &ref, baa_hash_alloc); + baa->refcnt++; + + return baa; +} + +void +bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa) +{ + if (baa->refcnt) + baa->refcnt--; + + if (baa->refcnt && baa->attr) + bgp_attr_unintern (baa->attr); + else + { + if (baa->attr) + { + hash_release (hash, baa); + bgp_attr_unintern (baa->attr); + } + baa_free (baa); + } +} + +/* BGP adjacency keeps minimal advertisement information. */ +void +bgp_adj_out_free (struct bgp_adj_out *adj) +{ + XFREE (MTYPE_BGP_ADJ_OUT, adj); +} + +int +bgp_adj_out_lookup (struct peer *peer, struct prefix *p, + afi_t afi, safi_t safi, struct bgp_node *rn) +{ + struct bgp_adj_out *adj; + + for (adj = rn->adj_out; adj; adj = adj->next) + if (adj->peer == peer) + break; + + if (! adj) + return 0; + + return (adj->adv + ? (adj->adv->baa ? 1 : 0) + : (adj->attr ? 1 : 0)); +} + +struct bgp_advertise * +bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj, + afi_t afi, safi_t safi) +{ + struct bgp_advertise *adv; + struct bgp_advertise_attr *baa; + struct bgp_advertise *next; + + adv = adj->adv; + baa = adv->baa; + next = NULL; + + if (baa) + { + /* Unlink myself from advertise attribute FIFO. */ + bgp_advertise_delete (baa, adv); + + /* Fetch next advertise candidate. */ + next = baa->adv; + + /* Unintern BGP advertise attribute. */ + bgp_advertise_unintern (peer->hash[afi][safi], baa); + adv->baa = NULL; + adv->rn = NULL; + } + + /* Unlink myself from advertisement FIFO. */ + FIFO_DEL (adv); + + /* Free memory. */ + bgp_advertise_free (adj->adv); + adj->adv = NULL; + + return next; +} + +void +bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p, + struct attr *attr, afi_t afi, safi_t safi, + struct bgp_info *binfo) +{ + struct bgp_adj_out *adj = NULL; + struct bgp_advertise *adv; + +#ifdef DISABLE_BGP_ANNOUNCE + return; +#endif /* DISABLE_BGP_ANNOUNCE */ + + /* Look for adjacency information. */ + if (rn) + { + for (adj = rn->adj_out; adj; adj = adj->next) + if (adj->peer == peer) + break; + } + + if (! adj) + { + adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out)); + + if (rn) + { + BGP_ADJ_OUT_ADD (rn, adj); + bgp_lock_node (rn); + } + } + + if (adj->adv) + bgp_advertise_clean (peer, adj, afi, safi); + + adj->peer = peer; + adj->adv = bgp_advertise_new (); + + adv = adj->adv; + adv->rn = rn; + adv->binfo = binfo; + if (attr) + adv->baa = bgp_advertise_intern (peer->hash[afi][safi], attr); + else + adv->baa = baa_new (); + adv->adj = adj; + + /* Add new advertisement to advertisement attribute list. */ + bgp_advertise_add (adv->baa, adv); + + FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo); +} + +void +bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p, + afi_t afi, safi_t safi) +{ + struct bgp_adj_out *adj; + struct bgp_advertise *adv; + +#ifdef DISABLE_BGP_ANNOUNCE + return; +#endif /* DISABLE_BGP_ANNOUNCE */ + + /* Lookup existing adjacency, if it is not there return immediately. */ + for (adj = rn->adj_out; adj; adj = adj->next) + if (adj->peer == peer) + break; + + if (! adj) + return; + + /* Clearn up previous advertisement. */ + if (adj->adv) + bgp_advertise_clean (peer, adj, afi, safi); + + if (adj->attr) + { + /* We need advertisement structure. */ + adj->adv = bgp_advertise_new (); + adv = adj->adv; + adv->rn = rn; + adv->adj = adj; + + /* Add to synchronization entry for withdraw announcement. */ + FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo); + + /* Schedule packet write. */ + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + } + else + { + /* Remove myself from adjacency. */ + BGP_ADJ_OUT_DEL (rn, adj); + + /* Free allocated information. */ + bgp_adj_out_free (adj); + + bgp_unlock_node (rn); + } +} + +void +bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj, + struct peer *peer, afi_t afi, safi_t safi) +{ + if (adj->attr) + bgp_attr_unintern (adj->attr); + + if (adj->adv) + bgp_advertise_clean (peer, adj, afi, safi); + + BGP_ADJ_OUT_DEL (rn, adj); + bgp_adj_out_free (adj); +} + +void +bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr) +{ + struct bgp_adj_in *adj; + + for (adj = rn->adj_in; adj; adj = adj->next) + { + if (adj->peer == peer) + { + if (adj->attr != attr) + { + bgp_attr_unintern (adj->attr); + adj->attr = bgp_attr_intern (attr); + } + return; + } + } + adj = XCALLOC (MTYPE_BGP_ADJ_IN, sizeof (struct bgp_adj_in)); + adj->peer = peer; + adj->attr = bgp_attr_intern (attr); + BGP_ADJ_IN_ADD (rn, adj); + bgp_lock_node (rn); +} + +void +bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai) +{ + bgp_attr_unintern (bai->attr); + BGP_ADJ_IN_DEL (rn, bai); + XFREE (MTYPE_BGP_ADJ_IN, bai); +} + +void +bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer) +{ + struct bgp_adj_in *adj; + + for (adj = rn->adj_in; adj; adj = adj->next) + if (adj->peer == peer) + break; + + if (! adj) + return; + + bgp_adj_in_remove (rn, adj); + bgp_unlock_node (rn); +} + +void +bgp_sync_init (struct peer *peer) +{ + afi_t afi; + safi_t safi; + struct bgp_synchronize *sync; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + sync = XCALLOC (MTYPE_TMP, sizeof (struct bgp_synchronize)); + FIFO_INIT (&sync->update); + FIFO_INIT (&sync->withdraw); + FIFO_INIT (&sync->withdraw_low); + peer->sync[afi][safi] = sync; + peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp); + } +} + +void +bgp_sync_delete (struct peer *peer) +{ + afi_t afi; + safi_t safi; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + if (peer->sync[afi][safi]) + XFREE (MTYPE_TMP, peer->sync[afi][safi]); + peer->sync[afi][safi] = NULL; + + hash_free (peer->hash[afi][safi]); + } +} diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h new file mode 100644 index 0000000..500d295 --- /dev/null +++ b/bgpd/bgp_advertise.h @@ -0,0 +1,145 @@ +/* BGP advertisement and adjacency + Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro + + This file is part of GNU Zebra. + + GNU Zebra 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, or (at your option) any + later version. + + GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* BGP advertise FIFO. */ +struct bgp_advertise_fifo +{ + struct bgp_advertise *next; + struct bgp_advertise *prev; +}; + +/* BGP advertise attribute. */ +struct bgp_advertise_attr +{ + /* Head of advertisement pointer. */ + struct bgp_advertise *adv; + + /* Reference counter. */ + unsigned long refcnt; + + /* Attribute pointer to be announced. */ + struct attr *attr; +}; + +struct bgp_advertise +{ + /* FIFO for advertisement. */ + struct bgp_advertise_fifo fifo; + + /* Link list for same attribute advertise. */ + struct bgp_advertise *next; + struct bgp_advertise *prev; + + /* Prefix information. */ + struct bgp_node *rn; + + /* Reference pointer. */ + struct bgp_adj_out *adj; + + /* Advertisement attribute. */ + struct bgp_advertise_attr *baa; + + /* BGP info. */ + struct bgp_info *binfo; +}; + +/* BGP adjacency out. */ +struct bgp_adj_out +{ + /* Lined list pointer. */ + struct bgp_adj_out *next; + struct bgp_adj_out *prev; + + /* Advertised peer. */ + struct peer *peer; + + /* Advertised attribute. */ + struct attr *attr; + + /* Advertisement information. */ + struct bgp_advertise *adv; +}; + +/* BGP adjacency in. */ +struct bgp_adj_in +{ + /* Linked list pointer. */ + struct bgp_adj_in *next; + struct bgp_adj_in *prev; + + /* Received peer. */ + struct peer *peer; + + /* Received attribute. */ + struct attr *attr; +}; + +/* BGP advertisement list. */ +struct bgp_synchronize +{ + struct bgp_advertise_fifo update; + struct bgp_advertise_fifo withdraw; + struct bgp_advertise_fifo withdraw_low; +}; + +/* BGP adjacency linked list. */ +#define BGP_INFO_ADD(N,A,TYPE) \ + do { \ + (A)->prev = NULL; \ + (A)->next = (N)->TYPE; \ + if ((N)->TYPE) \ + (N)->TYPE->prev = (A); \ + (N)->TYPE = (A); \ + } while (0) + +#define BGP_INFO_DEL(N,A,TYPE) \ + do { \ + if ((A)->next) \ + (A)->next->prev = (A)->prev; \ + if ((A)->prev) \ + (A)->prev->next = (A)->next; \ + else \ + (N)->TYPE = (A)->next; \ + } while (0) + +#define BGP_ADJ_IN_ADD(N,A) BGP_INFO_ADD(N,A,adj_in) +#define BGP_ADJ_IN_DEL(N,A) BGP_INFO_DEL(N,A,adj_in) +#define BGP_ADJ_OUT_ADD(N,A) BGP_INFO_ADD(N,A,adj_out) +#define BGP_ADJ_OUT_DEL(N,A) BGP_INFO_DEL(N,A,adj_out) + +/* Prototypes. */ +void bgp_adj_out_set (struct bgp_node *, struct peer *, struct prefix *, + struct attr *, afi_t, safi_t, struct bgp_info *); +void bgp_adj_out_unset (struct bgp_node *, struct peer *, struct prefix *, + afi_t, safi_t); +void bgp_adj_out_remove (struct bgp_node *, struct bgp_adj_out *, + struct peer *, afi_t, safi_t); +int bgp_adj_out_lookup (struct peer *, struct prefix *, afi_t, safi_t, + struct bgp_node *); + +void bgp_adj_in_set (struct bgp_node *, struct peer *, struct attr *); +void bgp_adj_in_unset (struct bgp_node *, struct peer *); +void bgp_adj_in_remove (struct bgp_node *, struct bgp_adj_in *); + +struct bgp_advertise * +bgp_advertise_clean (struct peer *, struct bgp_adj_out *, afi_t, safi_t); + +void bgp_sync_init (struct peer *); +void bgp_sync_delete (struct peer *); diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c new file mode 100644 index 0000000..d685423 --- /dev/null +++ b/bgpd/bgp_aspath.c @@ -0,0 +1,1186 @@ +/* AS path management routines. + Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro + + This file is part of GNU Zebra. + + GNU Zebra 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, or (at your option) any + later version. + + GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include + +#include "hash.h" +#include "memory.h" +#include "vector.h" +#include "vty.h" +#include "str.h" +#include "log.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_aspath.h" + +/* Attr. Flags and Attr. Type Code. */ +#define AS_HEADER_SIZE 2 + +/* Two octet is used for AS value. */ +#define AS_VALUE_SIZE sizeof (as_t) + +/* AS segment octet length. */ +#define ASSEGMENT_LEN(X) ((X)->length * AS_VALUE_SIZE + AS_HEADER_SIZE) + +/* To fetch and store as segment value. */ +struct assegment +{ + u_char type; + u_char length; + as_t asval[1]; +}; + +/* Hash for aspath. This is the top level structure of AS path. */ +struct hash *ashash; + +static struct aspath * +aspath_new () +{ + struct aspath *aspath; + + aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); + memset (aspath, 0, sizeof (struct aspath)); + return aspath; +} + +/* Free AS path structure. */ +void +aspath_free (struct aspath *aspath) +{ + if (!aspath) + return; + if (aspath->data) + XFREE (MTYPE_AS_SEG, aspath->data); + if (aspath->str) + XFREE (MTYPE_AS_STR, aspath->str); + XFREE (MTYPE_AS_PATH, aspath); +} + +/* Unintern aspath from AS path bucket. */ +void +aspath_unintern (struct aspath *aspath) +{ + struct aspath *ret; + + if (aspath->refcnt) + aspath->refcnt--; + + if (aspath->refcnt == 0) + { + /* This aspath must exist in aspath hash table. */ + ret = hash_release (ashash, aspath); + assert (ret != NULL); + aspath_free (aspath); + } +} + +/* Return the start or end delimiters for a particular Segment type */ +#define AS_SEG_START 0 +#define AS_SEG_END 1 +static char +aspath_delimiter_char (u_char type, u_char which) +{ + int i; + struct + { + int type; + char start; + char end; + } aspath_delim_char [] = + { + { AS_SET, '{', '}' }, + { AS_SEQUENCE, ' ', ' ' }, + { AS_CONFED_SET, '[', ']' }, + { AS_CONFED_SEQUENCE, '(', ')' }, + { 0 } + }; + + for (i = 0; aspath_delim_char[i].type != 0; i++) + { + if (aspath_delim_char[i].type == type) + { + if (which == AS_SEG_START) + return aspath_delim_char[i].start; + else if (which == AS_SEG_END) + return aspath_delim_char[i].end; + } + } + return ' '; +} + +/* Convert aspath structure to string expression. */ +char * +aspath_make_str_count (struct aspath *as) +{ + int space; + u_char type; + caddr_t pnt; + caddr_t end; + struct assegment *assegment; + int str_size = ASPATH_STR_DEFAULT_LEN; + int str_pnt; + u_char *str_buf; + int count = 0; + + /* Empty aspath. */ + if (as->length == 0) + { + str_buf = XMALLOC (MTYPE_AS_STR, 1); + str_buf[0] = '\0'; + as->count = count; + return str_buf; + } + + /* Set default value. */ + space = 0; + type = AS_SEQUENCE; + + /* Set initial pointer. */ + pnt = as->data; + end = pnt + as->length; + + str_buf = XMALLOC (MTYPE_AS_STR, str_size); + str_pnt = 0; + + assegment = (struct assegment *) pnt; + + while (pnt < end) + { + int i; + int estimate_len; + + /* For fetch value. */ + assegment = (struct assegment *) pnt; + + /* Check AS type validity. */ + if ((assegment->type != AS_SET) && + (assegment->type != AS_SEQUENCE) && + (assegment->type != AS_CONFED_SET) && + (assegment->type != AS_CONFED_SEQUENCE)) + { + XFREE (MTYPE_AS_STR, str_buf); + return NULL; + } + + /* Check AS length. */ + if ((pnt + (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE) > end) + { + XFREE (MTYPE_AS_STR, str_buf); + return NULL; + } + + /* Buffer length check. */ + estimate_len = ((assegment->length * 6) + 4); + + /* String length check. */ + while (str_pnt + estimate_len >= str_size) + { + str_size *= 2; + str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size); + } + + /* If assegment type is changed, print previous type's end + character. */ + if (type != AS_SEQUENCE) + str_buf[str_pnt++] = aspath_delimiter_char (type, AS_SEG_END); + if (space) + str_buf[str_pnt++] = ' '; + + if (assegment->type != AS_SEQUENCE) + str_buf[str_pnt++] = aspath_delimiter_char (assegment->type, AS_SEG_START); + + space = 0; + + /* Increment count - ignoring CONFED SETS/SEQUENCES */ + if (assegment->type != AS_CONFED_SEQUENCE + && assegment->type != AS_CONFED_SET) + { + if (assegment->type == AS_SEQUENCE) + count += assegment->length; + else if (assegment->type == AS_SET) + count++; + } + + for (i = 0; i < assegment->length; i++) + { + int len; + + if (space) + { + if (assegment->type == AS_SET + || assegment->type == AS_CONFED_SET) + str_buf[str_pnt++] = ','; + else + str_buf[str_pnt++] = ' '; + } + else + space = 1; + + len = sprintf (str_buf + str_pnt, "%d", ntohs (assegment->asval[i])); + str_pnt += len; + } + + type = assegment->type; + pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE; + } + + if (assegment->type != AS_SEQUENCE) + str_buf[str_pnt++] = aspath_delimiter_char (assegment->type, AS_SEG_END); + + str_buf[str_pnt] = '\0'; + + as->count = count; + + return str_buf; +} + +/* Intern allocated AS path. */ +struct aspath * +aspath_intern (struct aspath *aspath) +{ + struct aspath *find; + + /* Assert this AS path structure is not interned. */ + assert (aspath->refcnt == 0); + + /* Check AS path hash. */ + find = hash_get (ashash, aspath, hash_alloc_intern); + + if (find != aspath) + aspath_free (aspath); + + find->refcnt++; + + if (! find->str) + find->str = aspath_make_str_count (find); + + return find; +} + +/* Duplicate aspath structure. Created same aspath structure but + reference count and AS path string is cleared. */ +struct aspath * +aspath_dup (struct aspath *aspath) +{ + struct aspath *new; + + new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); + memset (new, 0, sizeof (struct aspath)); + + new->length = aspath->length; + + if (new->length) + { + new->data = XMALLOC (MTYPE_AS_SEG, aspath->length); + memcpy (new->data, aspath->data, aspath->length); + } + else + new->data = NULL; + + /* new->str = aspath_make_str_count (aspath); */ + + return new; +} + +void * +aspath_hash_alloc (struct aspath *arg) +{ + struct aspath *aspath; + + /* New aspath strucutre is needed. */ + aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); + memset ((void *) aspath, 0, sizeof (struct aspath)); + aspath->length = arg->length; + + /* In case of IBGP connection aspath's length can be zero. */ + if (arg->length) + { + aspath->data = XMALLOC (MTYPE_AS_SEG, arg->length); + memcpy (aspath->data, arg->data, arg->length); + } + else + aspath->data = NULL; + + /* Make AS path string. */ + aspath->str = aspath_make_str_count (aspath); + + /* Malformed AS path value. */ + if (! aspath->str) + { + aspath_free (aspath); + return NULL; + } + + return aspath; +} + +/* AS path parse function. pnt is a pointer to byte stream and length + is length of byte stream. If there is same AS path in the the AS + path hash then return it else make new AS path structure. */ +struct aspath * +aspath_parse (caddr_t pnt, int length) +{ + struct aspath as; + struct aspath *find; + + /* If length is odd it's malformed AS path. */ + if (length % 2) + return NULL; + + /* Looking up aspath hash entry. */ + as.data = pnt; + as.length = length; + + /* If already same aspath exist then return it. */ + find = hash_get (ashash, &as, aspath_hash_alloc); + if (! find) + return NULL; + find->refcnt++; + + return find; +} + +#define min(A,B) ((A) < (B) ? (A) : (B)) + +#define ASSEGMENT_SIZE(N) (AS_HEADER_SIZE + ((N) * AS_VALUE_SIZE)) + +struct aspath * +aspath_aggregate_segment_copy (struct aspath *aspath, struct assegment *seg, + int i) +{ + struct assegment *newseg; + + if (! aspath->data) + { + aspath->data = XMALLOC (MTYPE_AS_SEG, ASSEGMENT_SIZE (i)); + newseg = (struct assegment *) aspath->data; + aspath->length = ASSEGMENT_SIZE (i); + } + else + { + aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, + aspath->length + ASSEGMENT_SIZE (i)); + newseg = (struct assegment *) (aspath->data + aspath->length); + aspath->length += ASSEGMENT_SIZE (i); + } + + newseg->type = seg->type; + newseg->length = i; + memcpy (newseg->asval, seg->asval, (i * AS_VALUE_SIZE)); + + return aspath; +} + +struct assegment * +aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset, + as_t as) +{ + int i; + + /* If this is first AS set member, create new as-set segment. */ + if (asset == NULL) + { + if (! aspath->data) + { + aspath->data = XMALLOC (MTYPE_AS_SEG, ASSEGMENT_SIZE (1)); + asset = (struct assegment *) aspath->data; + aspath->length = ASSEGMENT_SIZE (1); + } + else + { + aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, + aspath->length + ASSEGMENT_SIZE (1)); + asset = (struct assegment *) (aspath->data + aspath->length); + aspath->length += ASSEGMENT_SIZE (1); + } + asset->type = AS_SET; + asset->length = 1; + asset->asval[0] = as; + } + else + { + size_t offset; + + /* Check this AS value already exists or not. */ + for (i = 0; i < asset->length; i++) + if (asset->asval[i] == as) + return asset; + + offset = (caddr_t) asset - (caddr_t) aspath->data; + aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, + aspath->length + AS_VALUE_SIZE); + + asset = (struct assegment *) (aspath->data + offset); + aspath->length += AS_VALUE_SIZE; + asset->asval[asset->length] = as; + asset->length++; + } + + return asset; +} + +/* Modify as1 using as2 for aggregation. */ +struct aspath * +aspath_aggregate (struct aspath *as1, struct aspath *as2) +{ + int i; + int minlen; + int match; + int match1; + int match2; + caddr_t cp1; + caddr_t cp2; + caddr_t end1; + caddr_t end2; + struct assegment *seg1; + struct assegment *seg2; + struct aspath *aspath; + struct assegment *asset; + + match = 0; + minlen = 0; + aspath = NULL; + asset = NULL; + cp1 = as1->data; + end1 = as1->data + as1->length; + cp2 = as2->data; + end2 = as2->data + as2->length; + + seg1 = (struct assegment *) cp1; + seg2 = (struct assegment *) cp2; + + /* First of all check common leading sequence. */ + while ((cp1 < end1) && (cp2 < end2)) + { + /* Check segment type. */ + if (seg1->type != seg2->type) + break; + + /* Minimum segment length. */ + minlen = min (seg1->length, seg2->length); + + for (match = 0; match < minlen; match++) + if (seg1->asval[match] != seg2->asval[match]) + break; + + if (match) + { + if (! aspath) + aspath = aspath_new(); + aspath = aspath_aggregate_segment_copy (aspath, seg1, match); + } + + if (match != minlen || match != seg1->length + || seg1->length != seg2->length) + break; + + cp1 += ((seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE); + cp2 += ((seg2->length * AS_VALUE_SIZE) + AS_HEADER_SIZE); + + seg1 = (struct assegment *) cp1; + seg2 = (struct assegment *) cp2; + } + + if (! aspath) + aspath = aspath_new(); + + /* Make as-set using rest of all information. */ + match1 = match; + while (cp1 < end1) + { + seg1 = (struct assegment *) cp1; + + for (i = match1; i < seg1->length; i++) + asset = aspath_aggregate_as_set_add (aspath, asset, seg1->asval[i]); + + match1 = 0; + cp1 += ((seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE); + } + + match2 = match; + while (cp2 < end2) + { + seg2 = (struct assegment *) cp2; + + for (i = match2; i < seg2->length; i++) + asset = aspath_aggregate_as_set_add (aspath, asset, seg2->asval[i]); + + match2 = 0; + cp2 += ((seg2->length * AS_VALUE_SIZE) + AS_HEADER_SIZE); + } + + return aspath; +} + +/* When a BGP router receives an UPDATE with an MP_REACH_NLRI + attribute, check the leftmost AS number in the AS_PATH attribute is + or not the peer's AS number. */ +int +aspath_firstas_check (struct aspath *aspath, as_t asno) +{ + caddr_t pnt; + struct assegment *assegment; + + if (aspath == NULL) + return 0; + + pnt = aspath->data; + assegment = (struct assegment *) pnt; + + if (assegment + && assegment->type == AS_SEQUENCE + && assegment->asval[0] == htons (asno)) + return 1; + + return 0; +} + +/* AS path loop check. If aspath contains asno then return 1. */ +int +aspath_loop_check (struct aspath *aspath, as_t asno) +{ + caddr_t pnt; + caddr_t end; + struct assegment *assegment; + int count = 0; + + if (aspath == NULL) + return 0; + + pnt = aspath->data; + end = aspath->data + aspath->length; + + while (pnt < end) + { + int i; + assegment = (struct assegment *) pnt; + + for (i = 0; i < assegment->length; i++) + if (assegment->asval[i] == htons (asno)) + count++; + + pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE; + } + return count; +} + +/* When all of AS path is private AS return 1. */ +int +aspath_private_as_check (struct aspath *aspath) +{ + caddr_t pnt; + caddr_t end; + struct assegment *assegment; + + if (aspath == NULL) + return 0; + + if (aspath->length == 0) + return 0; + + pnt = aspath->data; + end = aspath->data + aspath->length; + + while (pnt < end) + { + int i; + assegment = (struct assegment *) pnt; + + for (i = 0; i < assegment->length; i++) + { + if (ntohs (assegment->asval[i]) < BGP_PRIVATE_AS_MIN + || ntohs (assegment->asval[i]) > BGP_PRIVATE_AS_MAX) + return 0; + } + pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE; + } + return 1; +} + +/* Merge as1 to as2. as2 should be uninterned aspath. */ +struct aspath * +aspath_merge (struct aspath *as1, struct aspath *as2) +{ + caddr_t data; + + if (! as1 || ! as2) + return NULL; + + data = XMALLOC (MTYPE_AS_SEG, as1->length + as2->length); + memcpy (data, as1->data, as1->length); + memcpy (data + as1->length, as2->data, as2->length); + + XFREE (MTYPE_AS_SEG, as2->data); + as2->data = data; + as2->length += as1->length; + as2->count += as1->count; + return as2; +} + +/* Prepend as1 to as2. as2 should be uninterned aspath. */ +struct aspath * +aspath_prepend (struct aspath *as1, struct aspath *as2) +{ + caddr_t pnt; + caddr_t end; + struct assegment *seg1 = NULL; + struct assegment *seg2 = NULL; + + if (! as1 || ! as2) + return NULL; + + seg2 = (struct assegment *) as2->data; + + /* In case of as2 is empty AS. */ + if (seg2 == NULL) + { + as2->length = as1->length; + as2->data = XMALLOC (MTYPE_AS_SEG, as1->length); + as2->count = as1->count; + memcpy (as2->data, as1->data, as1->length); + return as2; + } + + /* assegment points last segment of as1. */ + pnt = as1->data; + end = as1->data + as1->length; + while (pnt < end) + { + seg1 = (struct assegment *) pnt; + pnt += (seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE; + } + + /* In case of as1 is empty AS. */ + if (seg1 == NULL) + return as2; + + /* Compare last segment type of as1 and first segment type of as2. */ + if (seg1->type != seg2->type) + return aspath_merge (as1, as2); + + if (seg1->type == AS_SEQUENCE) + { + caddr_t newdata; + struct assegment *seg = NULL; + + newdata = XMALLOC (MTYPE_AS_SEG, + as1->length + as2->length - AS_HEADER_SIZE); + memcpy (newdata, as1->data, as1->length); + seg = (struct assegment *) (newdata + ((caddr_t)seg1 - as1->data)); + seg->length += seg2->length; + memcpy (newdata + as1->length, as2->data + AS_HEADER_SIZE, + as2->length - AS_HEADER_SIZE); + + XFREE (MTYPE_AS_SEG, as2->data); + as2->data = newdata; + as2->length += (as1->length - AS_HEADER_SIZE); + as2->count += as1->count; + + return as2; + } + else + { + /* AS_SET merge code is needed at here. */ + return aspath_merge (as1, as2); + } + + /* Not reached */ +} + +/* Add specified AS to the leftmost of aspath. */ +static struct aspath * +aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type) +{ + struct assegment *assegment; + + assegment = (struct assegment *) aspath->data; + + /* In case of empty aspath. */ + if (assegment == NULL || assegment->length == 0) + { + aspath->length = AS_HEADER_SIZE + AS_VALUE_SIZE; + + if (assegment) + aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, aspath->length); + else + aspath->data = XMALLOC (MTYPE_AS_SEG, aspath->length); + + assegment = (struct assegment *) aspath->data; + assegment->type = type; + assegment->length = 1; + assegment->asval[0] = htons (asno); + + return aspath; + } + + if (assegment->type == type) + { + caddr_t newdata; + struct assegment *newsegment; + + newdata = XMALLOC (MTYPE_AS_SEG, aspath->length + AS_VALUE_SIZE); + newsegment = (struct assegment *) newdata; + + newsegment->type = type; + newsegment->length = assegment->length + 1; + newsegment->asval[0] = htons (asno); + + memcpy (newdata + AS_HEADER_SIZE + AS_VALUE_SIZE, + aspath->data + AS_HEADER_SIZE, + aspath->length - AS_HEADER_SIZE); + + XFREE (MTYPE_AS_SEG, aspath->data); + + aspath->data = newdata; + aspath->length += AS_VALUE_SIZE; + } else { + caddr_t newdata; + struct assegment *newsegment; + + newdata = XMALLOC (MTYPE_AS_SEG, aspath->length + AS_VALUE_SIZE + AS_HEADER_SIZE); + newsegment = (struct assegment *) newdata; + + newsegment->type = type; + newsegment->length = 1; + newsegment->asval[0] = htons (asno); + + memcpy (newdata + AS_HEADER_SIZE + AS_VALUE_SIZE, + aspath->data, + aspath->length); + + XFREE (MTYPE_AS_SEG, aspath->data); + + aspath->data = newdata; + aspath->length += AS_HEADER_SIZE + AS_VALUE_SIZE; + } + + return aspath; +} + +/* Add specified AS to the leftmost of aspath. */ +struct aspath * +aspath_add_seq (struct aspath *aspath, as_t asno) +{ + return aspath_add_one_as (aspath, asno, AS_SEQUENCE); +} + +/* Compare leftmost AS value for MED check. If as1's leftmost AS and + as2's leftmost AS is same return 1. */ +int +aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2) +{ + struct assegment *seg1; + struct assegment *seg2; + as_t as1; + as_t as2; + + seg1 = (struct assegment *) aspath1->data; + seg2 = (struct assegment *) aspath2->data; + + while (seg1 && seg1->length + && (seg1->type == AS_CONFED_SEQUENCE || seg1->type == AS_CONFED_SET)) + seg1 = (struct assegment *) ((caddr_t) seg1 + ASSEGMENT_LEN (seg1)); + while (seg2 && seg2->length + && (seg2->type == AS_CONFED_SEQUENCE || seg2->type == AS_CONFED_SET)) + seg2 = (struct assegment *) ((caddr_t) seg2 + ASSEGMENT_LEN (seg2)); + + /* Check as1's */ + if (seg1 == NULL || seg1->length == 0 || seg1->type != AS_SEQUENCE) + return 0; + as1 = seg1->asval[0]; + + if (seg2 == NULL || seg2->length == 0 || seg2->type != AS_SEQUENCE) + return 0; + as2 = seg2->asval[0]; + + if (as1 == as2) + return 1; + + return 0; +} + +/* Compare leftmost AS value for MED check. If as1's leftmost AS and + as2's leftmost AS is same return 1. (confederation as-path + only). */ +int +aspath_cmp_left_confed (struct aspath *aspath1, struct aspath *aspath2) +{ + struct assegment *seg1; + struct assegment *seg2; + + as_t as1; + as_t as2; + + if (aspath1->count || aspath2->count) + return 0; + + seg1 = (struct assegment *) aspath1->data; + seg2 = (struct assegment *) aspath2->data; + + /* Check as1's */ + if (seg1 == NULL || seg1->length == 0 || seg1->type != AS_CONFED_SEQUENCE) + return 0; + as1 = seg1->asval[0]; + + /* Check as2's */ + if (seg2 == NULL || seg2->length == 0 || seg2->type != AS_CONFED_SEQUENCE) + return 0; + as2 = seg2->asval[0]; + + if (as1 == as2) + return 1; + + return 0; +} + +/* Delete first sequential AS_CONFED_SEQUENCE from aspath. */ +struct aspath * +aspath_delete_confed_seq (struct aspath *aspath) +{ + int seglen; + struct assegment *assegment; + + if (! aspath) + return aspath; + + assegment = (struct assegment *) aspath->data; + + while (assegment) + { + if (assegment->type != AS_CONFED_SEQUENCE) + return aspath; + + seglen = ASSEGMENT_LEN (assegment); + + if (seglen == aspath->length) + { + XFREE (MTYPE_AS_SEG, aspath->data); + aspath->data = NULL; + aspath->length = 0; + } + else + { + memcpy (aspath->data, aspath->data + seglen, + aspath->length - seglen); + aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, + aspath->length - seglen); + aspath->length -= seglen; + } + + assegment = (struct assegment *) aspath->data; + } + return aspath; +} + +/* Add new AS number to the leftmost part of the aspath as + AS_CONFED_SEQUENCE. */ +struct aspath* +aspath_add_confed_seq (struct aspath *aspath, as_t asno) +{ + return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE); +} + +/* Add new as value to as path structure. */ +void +aspath_as_add (struct aspath *as, as_t asno) +{ + caddr_t pnt; + caddr_t end; + struct assegment *assegment; + + /* Increase as->data for new as value. */ + as->data = XREALLOC (MTYPE_AS_SEG, as->data, as->length + 2); + as->length += 2; + + pnt = as->data; + end = as->data + as->length; + assegment = (struct assegment *) pnt; + + /* Last segment search procedure. */ + while (pnt + 2 < end) + { + assegment = (struct assegment *) pnt; + + /* We add 2 for segment_type and segment_length and segment + value assegment->length * 2. */ + pnt += (AS_HEADER_SIZE + (assegment->length * AS_VALUE_SIZE)); + } + + assegment->asval[assegment->length] = htons (asno); + assegment->length++; +} + +/* Add new as segment to the as path. */ +void +aspath_segment_add (struct aspath *as, int type) +{ + struct assegment *assegment; + + if (as->data == NULL) + { + as->data = XMALLOC (MTYPE_AS_SEG, 2); + assegment = (struct assegment *) as->data; + as->length = 2; + } + else + { + as->data = XREALLOC (MTYPE_AS_SEG, as->data, as->length + 2); + assegment = (struct assegment *) (as->data + as->length); + as->length += 2; + } + + assegment->type = type; + assegment->length = 0; +} + +struct aspath * +aspath_empty () +{ + return aspath_parse (NULL, 0); +} + +struct aspath * +aspath_empty_get () +{ + struct aspath *aspath; + + aspath = aspath_new (); + aspath->str = aspath_make_str_count (aspath); + return aspath; +} + +unsigned long +aspath_count () +{ + return ashash->count; +} + +/* + Theoretically, one as path can have: + + One BGP packet size should be less than 4096. + One BGP attribute size should be less than 4096 - BGP header size. + One BGP aspath size should be less than 4096 - BGP header size - + BGP mandantry attribute size. +*/ + +/* AS path string lexical token enum. */ +enum as_token + { + as_token_asval, + as_token_set_start, + as_token_set_end, + as_token_confed_start, + as_token_confed_end, + as_token_unknown + }; + +/* Return next token and point for string parse. */ +char * +aspath_gettoken (char *buf, enum as_token *token, u_short *asno) +{ + char *p = buf; + + /* Skip space. */ + while (isspace ((int) *p)) + p++; + + /* Check the end of the string and type specify characters + (e.g. {}()). */ + switch (*p) + { + case '\0': + return NULL; + break; + case '{': + *token = as_token_set_start; + p++; + return p; + break; + case '}': + *token = as_token_set_end; + p++; + return p; + break; + case '(': + *token = as_token_confed_start; + p++; + return p; + break; + case ')': + *token = as_token_confed_end; + p++; + return p; + break; + } + + /* Check actual AS value. */ + if (isdigit ((int) *p)) + { + u_short asval; + + *token = as_token_asval; + asval = (*p - '0'); + p++; + while (isdigit ((int) *p)) + { + asval *= 10; + asval += (*p - '0'); + p++; + } + *asno = asval; + return p; + } + + /* There is no match then return unknown token. */ + *token = as_token_unknown; + return p++; +} + +struct aspath * +aspath_str2aspath (char *str) +{ + enum as_token token; + u_short as_type; + u_short asno; + struct aspath *aspath; + int needtype; + + aspath = aspath_new (); + + /* We start default type as AS_SEQUENCE. */ + as_type = AS_SEQUENCE; + needtype = 1; + + while ((str = aspath_gettoken (str, &token, &asno)) != NULL) + { + switch (token) + { + case as_token_asval: + if (needtype) + { + aspath_segment_add (aspath, as_type); + needtype = 0; + } + aspath_as_add (aspath, asno); + break; + case as_token_set_start: + as_type = AS_SET; + aspath_segment_add (aspath, as_type); + needtype = 0; + break; + case as_token_set_end: + as_type = AS_SEQUENCE; + needtype = 1; + break; + case as_token_confed_start: + as_type = AS_CONFED_SEQUENCE; + aspath_segment_add (aspath, as_type); + needtype = 0; + break; + case as_token_confed_end: + as_type = AS_SEQUENCE; + needtype = 1; + break; + case as_token_unknown: + default: + return NULL; + break; + } + } + + aspath->str = aspath_make_str_count (aspath); + + return aspath; +} + +/* Make hash value by raw aspath data. */ +unsigned int +aspath_key_make (struct aspath *aspath) +{ + unsigned int key = 0; + int length; + unsigned short *pnt; + + length = aspath->length / 2; + pnt = (unsigned short *) aspath->data; + + while (length) + { + key += *pnt++; + length--; + } + + return key; +} + +/* If two aspath have same value then return 1 else return 0 */ +int +aspath_cmp (struct aspath *as1, struct aspath *as2) +{ + if (as1->length == as2->length + && !memcmp (as1->data, as2->data, as1->length)) + return 1; + else + return 0; +} + +/* AS path hash initialize. */ +void +aspath_init () +{ + ashash = hash_create_size (32767, aspath_key_make, aspath_cmp); +} + +/* return and as path value */ +const char * +aspath_print (struct aspath *as) +{ + return as->str; +} + +/* Printing functions */ +void +aspath_print_vty (struct vty *vty, struct aspath *as) +{ + vty_out (vty, "%s", as->str); +} + +void +aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty) +{ + struct aspath *as; + + as = (struct aspath *) backet->data; + + vty_out (vty, "[%p:%d] (%ld) ", backet, backet->key, as->refcnt); + vty_out (vty, "%s%s", as->str, VTY_NEWLINE); +} + +/* Print all aspath and hash information. This function is used from + `show ip bgp paths' command. */ +void +aspath_print_all_vty (struct vty *vty) +{ + hash_iterate (ashash, + (void (*) (struct hash_backet *, void *)) + aspath_show_all_iterator, + vty); +} diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h new file mode 100644 index 0000000..ae829e8 --- /dev/null +++ b/bgpd/bgp_aspath.h @@ -0,0 +1,77 @@ +/* AS path related definitions. + Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + + This file is part of GNU Zebra. + + GNU Zebra 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, or (at your option) any + later version. + + GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* AS path segment type. */ +#define AS_SET 1 +#define AS_SEQUENCE 2 +#define AS_CONFED_SEQUENCE 3 +#define AS_CONFED_SET 4 + +/* Private AS range defined in RFC2270. */ +#define BGP_PRIVATE_AS_MIN 64512 +#define BGP_PRIVATE_AS_MAX 65535 + +/* AS path may be include some AsSegments. */ +struct aspath +{ + /* Reference count to this aspath. */ + unsigned long refcnt; + + /* Rawdata length. */ + int length; + + /* AS count. */ + int count; + + /* Rawdata. */ + caddr_t data; + + /* String expression of AS path. This string is used by vty output + and AS path regular expression match. */ + char *str; +}; + +#define ASPATH_STR_DEFAULT_LEN 32 + +/* Prototypes. */ +void aspath_init (); +struct aspath *aspath_parse (); +struct aspath *aspath_dup (struct aspath *); +struct aspath *aspath_aggregate (struct aspath *, struct aspath *); +struct aspath *aspath_prepend (struct aspath *, struct aspath *); +struct aspath *aspath_add_seq (struct aspath *, as_t); +struct aspath *aspath_add_confed_seq (struct aspath *, as_t); +int aspath_cmp_left (struct aspath *, struct aspath *); +int aspath_cmp_left_confed (struct aspath *, struct aspath *); +struct aspath *aspath_delete_confed_seq (struct aspath *); +struct aspath *aspath_empty (); +struct aspath *aspath_empty_get (); +struct aspath *aspath_str2aspath (char *); +void aspath_free (struct aspath *); +struct aspath *aspath_intern (struct aspath *); +void aspath_unintern (struct aspath *); +const char *aspath_print (struct aspath *); +void aspath_print_vty (struct vty *, struct aspath *); +void aspath_print_all_vty (struct vty *); +unsigned int aspath_key_make (struct aspath *); +int aspath_loop_check (struct aspath *, as_t); +int aspath_private_as_check (struct aspath *); +int aspath_firstas_check (struct aspath *, as_t); +unsigned long aspath_count (); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c new file mode 100644 index 0000000..147e388 --- /dev/null +++ b/bgpd/bgp_attr.c @@ -0,0 +1,1842 @@ +/* BGP attributes management routines. + Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro + + This file is part of GNU Zebra. + + GNU Zebra 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, or (at your option) any + later version. + + GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include + +#include "linklist.h" +#include "prefix.h" +#include "memory.h" +#include "vector.h" +#include "vty.h" +#include "stream.h" +#include "log.h" +#include "hash.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_ecommunity.h" + +/* Attribute strings for logging. */ +struct message attr_str [] = + { + { BGP_ATTR_ORIGIN, "ORIGIN" }, + { BGP_ATTR_AS_PATH, "AS_PATH" }, + { BGP_ATTR_NEXT_HOP, "NEXT_HOP" }, + { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" }, + { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" }, + { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" }, + { BGP_ATTR_AGGREGATOR, "AGGREGATOR" }, + { BGP_ATTR_COMMUNITIES, "COMMUNITY" }, + { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" }, + { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" }, + { BGP_ATTR_DPA, "DPA" }, + { BGP_ATTR_ADVERTISER, "ADVERTISER"} , + { BGP_ATTR_RCID_PATH, "RCID_PATH" }, + { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" }, + { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" }, + { 0, NULL } + }; + +struct hash *cluster_hash; + +void * +cluster_hash_alloc (struct cluster_list *val) +{ + struct cluster_list *cluster; + + cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list)); + cluster->length = val->length; + + if (cluster->length) + { + cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length); + memcpy (cluster->list, val->list, val->length); + } + else + cluster->list = NULL; + + cluster->refcnt = 0; + + return cluster; +} + +/* Cluster list related functions. */ +struct cluster_list * +cluster_parse (caddr_t pnt, int length) +{ + struct cluster_list tmp; + struct cluster_list *cluster; + + tmp.length = length; + tmp.list = (struct in_addr *) pnt; + + cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc); + cluster->refcnt++; + return cluster; +} + +int +cluster_loop_check (struct cluster_list *cluster, struct in_addr originator) +{ + int i; + + for (i = 0; i < cluster->length / 4; i++) + if (cluster->list[i].s_addr == originator.s_addr) + return 1; + return 0; +} + +unsigned int +cluster_hash_key_make (struct cluster_list *cluster) +{ + unsigned int key = 0; + int length; + caddr_t pnt; + + length = cluster->length; + pnt = (caddr_t) cluster->list; + + while (length) + key += pnt[--length]; + + return key; +} + +int +cluster_hash_cmp (struct cluster_list *cluster1, struct cluster_list *cluster2) +{ + if (cluster1->length == cluster2->length && + memcmp (cluster1->list, cluster2->list, cluster1->length) == 0) + return 1; + return 0; +} + +void +cluster_free (struct cluster_list *cluster) +{ + if (cluster->list) + XFREE (MTYPE_CLUSTER_VAL, cluster->list); + XFREE (MTYPE_CLUSTER, cluster); +} + +struct cluster_list * +cluster_dup (struct cluster_list *cluster) +{ + struct cluster_list *new; + + new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list)); + memset (new, 0, sizeof (struct cluster_list)); + new->length = cluster->length; + + if (cluster->length) + { + new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length); + memcpy (new->list, cluster->list, cluster->length); + } + else + new->list = NULL; + + return new; +} + +struct cluster_list * +cluster_intern (struct cluster_list *cluster) +{ + struct cluster_list *find; + + find = hash_get (cluster_hash, cluster, cluster_hash_alloc); + find->refcnt++; + + return find; +} + +void +cluster_unintern (struct cluster_list *cluster) +{ + struct cluster_list *ret; + + if (cluster->refcnt) + cluster->refcnt--; + + if (cluster->refcnt == 0) + { + ret = hash_release (cluster_hash, cluster); + cluster_free (cluster); + } +} + +void +cluster_init () +{ + cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp); +} + +/* Unknown transit attribute. */ +struct hash *transit_hash; + +void +transit_free (struct transit *transit) +{ + if (transit->val) + XFREE (MTYPE_TRANSIT_VAL, transit->val); + XFREE (MTYPE_TRANSIT, transit); +} + +void * +transit_hash_alloc (struct transit *transit) +{ + /* Transit structure is already allocated. */ + return transit; +} + +struct transit * +transit_intern (struct transit *transit) +{ + struct transit *find; + + find = hash_get (transit_hash, transit, transit_hash_alloc); + if (find != transit) + transit_free (transit); + find->refcnt++; + + return find; +} + +void +transit_unintern (struct transit *transit) +{ + struct transit *ret; + + if (transit->refcnt) + transit->refcnt--; + + if (transit->refcnt == 0) + { + ret = hash_release (transit_hash, transit); + transit_free (transit); + } +} + +unsigned int +transit_hash_key_make (struct transit *transit) +{ + unsigned int key = 0; + int length; + caddr_t pnt; + + length = transit->length; + pnt = (caddr_t) transit->val; + + while (length) + key += pnt[--length]; + + return key; +} + +int +transit_hash_cmp (struct transit *transit1, struct transit *transit2) +{ + if (transit1->length == transit2->length && + memcmp (transit1->val, transit2->val, transit1->length) == 0) + return 1; + return 0; +} + +void +transit_init () +{ + transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp); +} + +/* Attribute hash routines. */ + +struct hash *attrhash; + +unsigned int +attrhash_key_make (struct attr *attr) +{ + unsigned int key = 0; + + key += attr->origin; + key += attr->nexthop.s_addr; + key += attr->med; + key += attr->local_pref; + key += attr->aggregator_as; + key += attr->aggregator_addr.s_addr; + key += attr->weight; + + key += attr->mp_nexthop_global_in.s_addr; + if (attr->aspath) + key += aspath_key_make (attr->aspath); + if (attr->community) + key += community_hash_make (attr->community); + if (attr->ecommunity) + key += ecommunity_hash_make (attr->ecommunity); + if (attr->cluster) + key += cluster_hash_key_make (attr->cluster); + if (attr->transit) + key += transit_hash_key_make (attr->transit); + +#ifdef HAVE_IPV6 + { + int i; + + key += attr->mp_nexthop_len; + for (i = 0; i < 16; i++) + key += attr->mp_nexthop_global.s6_addr[i]; + for (i = 0; i < 16; i++) + key += attr->mp_nexthop_local.s6_addr[i]; + } +#endif /* HAVE_IPV6 */ + + return key; +} + +int +attrhash_cmp (struct attr *attr1, struct attr *attr2) +{ + if (attr1->flag == attr2->flag + && attr1->origin == attr2->origin + && attr1->nexthop.s_addr == attr2->nexthop.s_addr + && attr1->med == attr2->med + && attr1->local_pref == attr2->local_pref + && attr1->aggregator_as == attr2->aggregator_as + && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr + && attr1->weight == attr2->weight +#ifdef HAVE_IPV6 + && attr1->mp_nexthop_len == attr2->mp_nexthop_len + && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global) + && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local) +#endif /* HAVE_IPV6 */ + && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in) + && attr1->aspath == attr2->aspath + && attr1->community == attr2->community + && attr1->ecommunity == attr2->ecommunity + && attr1->cluster == attr2->cluster + && attr1->transit == attr2->transit) + return 1; + else + return 0; +} + +void +attrhash_init () +{ + attrhash = hash_create (attrhash_key_make, attrhash_cmp); +} + +void +attr_show_all_iterator (struct hash_backet *backet, struct vty *vty) +{ + struct attr *attr = backet->data; + + vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt, + inet_ntoa (attr->nexthop), VTY_NEWLINE); +} + +void +attr_show_all (struct vty *vty) +{ + hash_iterate (attrhash, + (void (*)(struct hash_backet *, void *)) + attr_show_all_iterator, + vty); +} + +void * +bgp_attr_hash_alloc (struct attr *val) +{ + struct attr *attr; + + attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr)); + *attr = *val; + attr->refcnt = 0; + return attr; +} + +/* Internet argument attribute. */ +struct attr * +bgp_attr_intern (struct attr *attr) +{ + struct attr *find; + + /* Intern referenced strucutre. */ + if (attr->aspath) + { + if (! attr->aspath->refcnt) + attr->aspath = aspath_intern (attr->aspath); + else + attr->aspath->refcnt++; + } + if (attr->community) + { + if (! attr->community->refcnt) + attr->community = community_intern (attr->community); + else + attr->community->refcnt++; + } + if (attr->ecommunity) + { + if (! attr->ecommunity->refcnt) + attr->ecommunity = ecommunity_intern (attr->ecommunity); + else + attr->ecommunity->refcnt++; + } + if (attr->cluster) + { + if (! attr->cluster->refcnt) + attr->cluster = cluster_intern (attr->cluster); + else + attr->cluster->refcnt++; + } + if (attr->transit) + { + if (! attr->transit->refcnt) + attr->transit = transit_intern (attr->transit); + else + attr->transit->refcnt++; + } + + find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc); + find->refcnt++; + + return find; +} + +/* Make network statement's attribute. */ +struct attr * +bgp_attr_default_set (struct attr *attr, u_char origin) +{ + memset (attr, 0, sizeof (struct attr)); + + attr->origin = origin; + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); + attr->aspath = aspath_empty (); + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + attr->weight = 32768; + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); +#ifdef HAVE_IPV6 + attr->mp_nexthop_len = 16; +#endif + return attr; +} + +/* Make network statement's attribute. */ +struct attr * +bgp_attr_default_intern (u_char origin) +{ + struct attr attr; + struct attr *new; + + memset (&attr, 0, sizeof (struct attr)); + + attr.origin = origin; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); + attr.aspath = aspath_empty (); + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + attr.weight = 32768; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); +#ifdef HAVE_IPV6 + attr.mp_nexthop_len = 16; +#endif + + new = bgp_attr_intern (&attr); + aspath_unintern (new->aspath); + return new; +} + +struct attr * +bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, + struct aspath *aspath, + struct community *community, int as_set) +{ + struct attr attr; + struct attr *new; + + memset (&attr, 0, sizeof (struct attr)); + + /* Origin attribute. */ + attr.origin = origin; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); + + /* AS path attribute. */ + if (aspath) + attr.aspath = aspath_intern (aspath); + else + attr.aspath = aspath_empty (); + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + + /* Next hop attribute. */ + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); + + if (community) + { + attr.community = community; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); + } + + attr.weight = 32768; +#ifdef HAVE_IPV6 + attr.mp_nexthop_len = 16; +#endif + if (! as_set) + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); + if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) + attr.aggregator_as = bgp->confed_id; + else + attr.aggregator_as = bgp->as; + attr.aggregator_addr = bgp->router_id; + + new = bgp_attr_intern (&attr); + aspath_unintern (new->aspath); + return new; +} + +/* Free bgp attribute and aspath. */ +void +bgp_attr_unintern (struct attr *attr) +{ + struct attr *ret; + struct aspath *aspath; + struct community *community; + struct ecommunity *ecommunity; + struct cluster_list *cluster; + struct transit *transit; + + /* Decrement attribute reference. */ + attr->refcnt--; + aspath = attr->aspath; + community = attr->community; + ecommunity = attr->ecommunity; + cluster = attr->cluster; + transit = attr->transit; + + /* If reference becomes zero then free attribute object. */ + if (attr->refcnt == 0) + { + ret = hash_release (attrhash, attr); + assert (ret != NULL); + XFREE (MTYPE_ATTR, attr); + } + + /* aspath refcount shoud be decrement. */ + if (aspath) + aspath_unintern (aspath); + if (community) + community_unintern (community); + if (ecommunity) + ecommunity_unintern (ecommunity); + if (cluster) + cluster_unintern (cluster); + if (transit) + transit_unintern (transit); +} + +void +bgp_attr_flush (struct attr *attr) +{ + if (attr->aspath && ! attr->aspath->refcnt) + aspath_free (attr->aspath); + if (attr->community && ! attr->community->refcnt) + community_free (attr->community); + if (attr->ecommunity && ! attr->ecommunity->refcnt) + ecommunity_free (attr->ecommunity); + if (attr->cluster && ! attr->cluster->refcnt) + cluster_free (attr->cluster); + if (attr->transit && ! attr->transit->refcnt) + transit_free (attr->transit); +} + +/* Get origin attribute of the update message. */ +int +bgp_attr_origin (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag, u_char *startp) +{ + bgp_size_t total; + + /* total is entire attribute length include Attribute Flags (1), + Attribute Type code (1) and Attribute length (1 or 2). */ + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + + /* If any recognized attribute has Attribute Flags that conflict + with the Attribute Type Code, then the Error Subcode is set to + Attribute Flags Error. The Data field contains the erroneous + attribute (type, length and value). */ + if (flag != BGP_ATTR_FLAG_TRANS) + { + zlog (peer->log, LOG_ERR, + "Origin attribute flag isn't transitive %d", flag); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + return -1; + } + + /* If any recognized attribute has Attribute Length that conflicts + with the expected length (based on the attribute type code), then + the Error Subcode is set to Attribute Length Error. The Data + field contains the erroneous attribute (type, length and + value). */ + if (length != 1) + { + zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d", + length); + bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); + return -1; + } + + /* Fetch origin attribute. */ + attr->origin = stream_getc (BGP_INPUT (peer)); + + /* If the ORIGIN attribute has an undefined value, then the Error + Subcode is set to Invalid Origin Attribute. The Data field + contains the unrecognized attribute (type, length and value). */ + if ((attr->origin != BGP_ORIGIN_IGP) + && (attr->origin != BGP_ORIGIN_EGP) + && (attr->origin != BGP_ORIGIN_INCOMPLETE)) + { + zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d", + attr->origin); + + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_ORIGIN, + startp, total); + return -1; + } + + /* Set oring attribute flag. */ + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); + + return 0; +} + +/* Parse AS path information. This function is wrapper of + aspath_parse. */ +int +bgp_attr_aspath (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag, u_char *startp) +{ + struct bgp *bgp; + struct aspath *aspath; + bgp_size_t total; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + + /* Flag check. */ + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) + || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + { + zlog (peer->log, LOG_ERR, + "Origin attribute flag isn't transitive %d", flag); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + return -1; + } + + /* In case of IBGP, length will be zero. */ + attr->aspath = aspath_parse (stream_pnt (peer->ibuf), length); + if (! attr->aspath) + { + zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length); + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_AS_PATH); + return -1; + } + + bgp = peer->bgp; + + /* First AS check for EBGP. */ + if (! bgp_flag_check (bgp, BGP_FLAG_NO_ENFORCE_FIRST_AS)) + { + if (peer_sort (peer) == BGP_PEER_EBGP + && ! aspath_firstas_check (attr->aspath, peer->as)) + { + zlog (peer->log, LOG_ERR, + "%s incorrect first AS (must be %d)", peer->host, peer->as); + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_AS_PATH); + return -1; + } + } + + /* local-as prepend */ + if (peer->change_local_as && + ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) + { + aspath = aspath_dup (attr->aspath); + aspath = aspath_add_seq (aspath, peer->change_local_as); + aspath_unintern (attr->aspath); + attr->aspath = aspath_intern (aspath); + } + + /* Forward pointer. */ + stream_forward (peer->ibuf, length); + + /* Set aspath attribute flag. */ + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + + return 0; +} + +/* Nexthop attribute. */ +int +bgp_attr_nexthop (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag, u_char *startp) +{ + bgp_size_t total; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + + /* Flag check. */ + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) + || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + { + zlog (peer->log, LOG_ERR, + "Origin attribute flag isn't transitive %d", flag); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + return -1; + } + + /* Check nexthop attribute length. */ + if (length != 4) + { + zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]", + length); + + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); + return -1; + } + + attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf); + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); + + return 0; +} + +/* MED atrribute. */ +int +bgp_attr_med (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag, u_char *startp) +{ + bgp_size_t total; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + + /* Length check. */ + if (length != 4) + { + zlog (peer->log, LOG_ERR, + "MED attribute length isn't four [%d]", length); + + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); + return -1; + } + + attr->med = stream_getl (peer->ibuf); + + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + + return 0; +} + +/* Local preference attribute. */ +int +bgp_attr_local_pref (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag) +{ + /* If it is contained in an UPDATE message that is received from an + external peer, then this attribute MUST be ignored by the + receiving speaker. */ + if (peer_sort (peer) == BGP_PEER_EBGP) + { + stream_forward (peer->ibuf, length); + return 0; + } + + if (length == 4) + attr->local_pref = stream_getl (peer->ibuf); + else + attr->local_pref = 0; + + /* Set atomic aggregate flag. */ + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); + + return 0; +} + +/* Atomic aggregate. */ +int +bgp_attr_atomic (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag) +{ + if (length != 0) + { + zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length); + + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + return -1; + } + + /* Set atomic aggregate flag. */ + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + + return 0; +} + +/* Aggregator attribute */ +int +bgp_attr_aggregator (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag) +{ + if (length != 6) + { + zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length); + + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + return -1; + } + attr->aggregator_as = stream_getw (peer->ibuf); + attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf); + + /* Set atomic aggregate flag. */ + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); + + return 0; +} + +/* Community attribute. */ +int +bgp_attr_community (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag) +{ + if (length == 0) + attr->community = NULL; + else + { + attr->community = community_parse (stream_pnt (peer->ibuf), length); + stream_forward (peer->ibuf, length); + } + + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); + + return 0; +} + +/* Originator ID attribute. */ +int +bgp_attr_originator_id (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag) +{ + if (length != 4) + { + zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length); + + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + return -1; + } + + attr->originator_id.s_addr = stream_get_ipv4 (peer->ibuf); + + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); + + return 0; +} + +/* Cluster list attribute. */ +int +bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag) +{ + /* Check length. */ + if (length % 4) + { + zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length); + + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + return -1; + } + + attr->cluster = cluster_parse (stream_pnt (peer->ibuf), length); + + stream_forward (peer->ibuf, length);; + + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST); + + return 0; +} + +/* Multiprotocol reachability information parse. */ +int +bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, + struct bgp_nlri *mp_update) +{ + u_int16_t afi; + u_char safi; + u_char snpa_num; + u_char snpa_len; + u_char *lim; + bgp_size_t nlri_len; + int ret; + struct stream *s; + + /* Set end of packet. */ + s = peer->ibuf; + lim = stream_pnt (s) + length; + + /* Load AFI, SAFI. */ + afi = stream_getw (s); + safi = stream_getc (s); + + /* Get nexthop length. */ + attr->mp_nexthop_len = stream_getc (s); + + /* Nexthop length check. */ + switch (attr->mp_nexthop_len) + { + case 4: + stream_get (&attr->mp_nexthop_global_in, s, 4); + break; + case 12: + { + u_int32_t rd_high; + u_int32_t rd_low; + + rd_high = stream_getl (s); + rd_low = stream_getl (s); + stream_get (&attr->mp_nexthop_global_in, s, 4); + } + break; +#ifdef HAVE_IPV6 + case 16: + stream_get (&attr->mp_nexthop_global, s, 16); + break; + case 32: + stream_get (&attr->mp_nexthop_global, s, 16); + stream_get (&attr->mp_nexthop_local, s, 16); + if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local)) + { + char buf1[INET6_ADDRSTRLEN]; + char buf2[INET6_ADDRSTRLEN]; + + if (BGP_DEBUG (update, UPDATE_IN)) + zlog_warn ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host, + inet_ntop (AF_INET6, &attr->mp_nexthop_global, + buf1, INET6_ADDRSTRLEN), + inet_ntop (AF_INET6, &attr->mp_nexthop_local, + buf2, INET6_ADDRSTRLEN)); + + attr->mp_nexthop_len = 16; + } + break; +#endif /* HAVE_IPV6 */ + default: + zlog_info ("Wrong multiprotocol next hop length: %d", + attr->mp_nexthop_len); + return -1; + break; + } + + snpa_num = stream_getc (s); + + while (snpa_num--) + { + snpa_len = stream_getc (s); + stream_forward (s, (snpa_len + 1) >> 1); + } + + nlri_len = lim - stream_pnt (s); + + if (safi != BGP_SAFI_VPNV4) + { + ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len); + if (ret < 0) + return -1; + } + + mp_update->afi = afi; + mp_update->safi = safi; + mp_update->nlri = stream_pnt (s); + mp_update->length = nlri_len; + + stream_forward (s, nlri_len); + + return 0; +} + +/* Multiprotocol unreachable parse */ +int +bgp_mp_unreach_parse (struct peer *peer, int length, + struct bgp_nlri *mp_withdraw) +{ + struct stream *s; + u_int16_t afi; + u_char safi; + u_char *lim; + u_int16_t withdraw_len; + int ret; + + s = peer->ibuf; + lim = stream_pnt (s) + length; + + afi = stream_getw (s); + safi = stream_getc (s); + + withdraw_len = lim - stream_pnt (s); + + if (safi != BGP_SAFI_VPNV4) + { + ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len); + if (ret < 0) + return -1; + } + + mp_withdraw->afi = afi; + mp_withdraw->safi = safi; + mp_withdraw->nlri = stream_pnt (s); + mp_withdraw->length = withdraw_len; + + stream_forward (s, withdraw_len); + + return 0; +} + +/* Extended Community attribute. */ +int +bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag) +{ + if (length == 0) + attr->ecommunity = NULL; + else + { + attr->ecommunity = ecommunity_parse (stream_pnt (peer->ibuf), length); + stream_forward (peer->ibuf, length); + } + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); + + return 0; +} + +/* BGP unknown attribute treatment. */ +int +bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, + u_char type, bgp_size_t length, u_char *startp) +{ + bgp_size_t total; + struct transit *transit; + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s Unknown attribute is received (type %d, length %d)", + peer->host, type, length); + + /* Forward read pointer of input stream. */ + stream_forward (peer->ibuf, length); + + /* Adjest total length to include type and length. */ + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + + /* If any of the mandatory well-known attributes are not recognized, + then the Error Subcode is set to Unrecognized Well-known + Attribute. The Data field contains the unrecognized attribute + (type, length and value). */ + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) + { + /* Adjust startp to do not include flag value. */ + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_UNREC_ATTR, + startp, total); + return -1; + } + + /* Unrecognized non-transitive optional attributes must be quietly + ignored and not passed along to other BGP peers. */ + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + return 0; + + /* If a path with recognized transitive optional attribute is + accepted and passed along to other BGP peers and the Partial bit + in the Attribute Flags octet is set to 1 by some previous AS, it + is not set back to 0 by the current AS. */ + SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL); + + /* Store transitive attribute to the end of attr->transit. */ + if (! attr->transit) + { + attr->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit)); + memset (attr->transit, 0, sizeof (struct transit)); + } + + transit = attr->transit; + + if (transit->val) + transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val, + transit->length + total); + else + transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total); + + memcpy (transit->val + transit->length, startp, total); + transit->length += total; + + return 0; +} + +/* Read attribute of update packet. This function is called from + bgp_update() in bgpd.c. */ +int +bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, + struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw) +{ + int ret; + u_char flag; + u_char type; + bgp_size_t length; + u_char *startp, *endp; + u_char *attr_endp; + u_char seen[BGP_ATTR_BITMAP_SIZE]; + + /* Initialize bitmap. */ + memset (seen, 0, BGP_ATTR_BITMAP_SIZE); + + /* End pointer of BGP attribute. */ + endp = BGP_INPUT_PNT (peer) + size; + + /* Get attributes to the end of attribute length. */ + while (BGP_INPUT_PNT (peer) < endp) + { + /* Check remaining length check.*/ + if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN) + { + zlog (peer->log, LOG_WARNING, + "%s error BGP attribute length %d is smaller than min len", + peer->host, endp - STREAM_PNT (BGP_INPUT (peer))); + + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + return -1; + } + + /* Fetch attribute flag and type. */ + startp = BGP_INPUT_PNT (peer); + flag = stream_getc (BGP_INPUT (peer)); + type = stream_getc (BGP_INPUT (peer)); + + /* Check extended attribue length bit. */ + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)) + length = stream_getw (BGP_INPUT (peer)); + else + length = stream_getc (BGP_INPUT (peer)); + + /* If any attribute appears more than once in the UPDATE + message, then the Error Subcode is set to Malformed Attribute + List. */ + + if (CHECK_BITMAP (seen, type)) + { + zlog (peer->log, LOG_WARNING, + "%s error BGP attribute type %d appears twice in a message", + peer->host, type); + + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); + return -1; + } + + /* Set type to bitmap to check duplicate attribute. `type' is + unsigned char so it never overflow bitmap range. */ + + SET_BITMAP (seen, type); + + /* Overflow check. */ + attr_endp = BGP_INPUT_PNT (peer) + length; + + if (attr_endp > endp) + { + zlog (peer->log, LOG_WARNING, + "%s BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp); + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + return -1; + } + + /* OK check attribute and store it's value. */ + switch (type) + { + case BGP_ATTR_ORIGIN: + ret = bgp_attr_origin (peer, length, attr, flag, startp); + break; + case BGP_ATTR_AS_PATH: + ret = bgp_attr_aspath (peer, length, attr, flag, startp); + break; + case BGP_ATTR_NEXT_HOP: + ret = bgp_attr_nexthop (peer, length, attr, flag, startp); + break; + case BGP_ATTR_MULTI_EXIT_DISC: + ret = bgp_attr_med (peer, length, attr, flag, startp); + break; + case BGP_ATTR_LOCAL_PREF: + ret = bgp_attr_local_pref (peer, length, attr, flag); + break; + case BGP_ATTR_ATOMIC_AGGREGATE: + ret = bgp_attr_atomic (peer, length, attr, flag); + break; + case BGP_ATTR_AGGREGATOR: + ret = bgp_attr_aggregator (peer, length, attr, flag); + break; + case BGP_ATTR_COMMUNITIES: + ret = bgp_attr_community (peer, length, attr, flag); + break; + case BGP_ATTR_ORIGINATOR_ID: + ret = bgp_attr_originator_id (peer, length, attr, flag); + break; + case BGP_ATTR_CLUSTER_LIST: + ret = bgp_attr_cluster_list (peer, length, attr, flag); + break; + case BGP_ATTR_MP_REACH_NLRI: + ret = bgp_mp_reach_parse (peer, length, attr, mp_update); + break; + case BGP_ATTR_MP_UNREACH_NLRI: + ret = bgp_mp_unreach_parse (peer, length, mp_withdraw); + break; + case BGP_ATTR_EXT_COMMUNITIES: + ret = bgp_attr_ext_communities (peer, length, attr, flag); + break; + default: + ret = bgp_attr_unknown (peer, attr, flag, type, length, startp); + break; + } + + /* If error occured immediately return to the caller. */ + if (ret < 0) + return ret; + + /* Check the fetched length. */ + if (BGP_INPUT_PNT (peer) != attr_endp) + { + zlog (peer->log, LOG_WARNING, + "%s BGP attribute fetch error", peer->host); + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + return -1; + } + } + + /* Check final read pointer is same as end pointer. */ + if (BGP_INPUT_PNT (peer) != endp) + { + zlog (peer->log, LOG_WARNING, + "%s BGP attribute length mismatch", peer->host); + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + return -1; + } + + /* Finally intern unknown attribute. */ + if (attr->transit) + attr->transit = transit_intern (attr->transit); + + return 0; +} + +/* Well-known attribute check. */ +int +bgp_attr_check (struct peer *peer, struct attr *attr) +{ + u_char type = 0; + + if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) + type = BGP_ATTR_ORIGIN; + + if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) + type = BGP_ATTR_AS_PATH; + + if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) + type = BGP_ATTR_NEXT_HOP; + + if (peer_sort (peer) == BGP_PEER_IBGP + && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) + type = BGP_ATTR_LOCAL_PREF; + + if (type) + { + zlog (peer->log, LOG_WARNING, + "%s Missing well-known attribute %d.", + peer->host, type); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MISS_ATTR, + &type, 1); + return -1; + } + return 0; +} + +int stream_put_prefix (struct stream *, struct prefix *); + +/* Make attribute packet. */ +bgp_size_t +bgp_packet_attribute (struct bgp *bgp, struct peer *peer, + struct stream *s, struct attr *attr, struct prefix *p, + afi_t afi, safi_t safi, struct peer *from, + struct prefix_rd *prd, u_char *tag) +{ + unsigned long cp; + struct aspath *aspath; + + if (! bgp) + bgp = bgp_get_default (); + + /* Remember current pointer. */ + cp = stream_get_putp (s); + + /* Origin attribute. */ + stream_putc (s, BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_ORIGIN); + stream_putc (s, 1); + stream_putc (s, attr->origin); + + /* AS path attribute. */ + + /* If remote-peer is EBGP */ + if (peer_sort (peer) == BGP_PEER_EBGP + && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) + || attr->aspath->length == 0) + && ! (CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) + && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))) + { + aspath = aspath_dup (attr->aspath); + + if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) + { + /* Strip the confed info, and then stuff our path CONFED_ID + on the front */ + aspath = aspath_delete_confed_seq (aspath); + aspath = aspath_add_seq (aspath, bgp->confed_id); + } + else + { + aspath = aspath_add_seq (aspath, peer->local_as); + if (peer->change_local_as) + aspath = aspath_add_seq (aspath, peer->change_local_as); + } + } + else if (peer_sort (peer) == BGP_PEER_CONFED) + { + /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */ + aspath = aspath_dup (attr->aspath); + aspath = aspath_add_confed_seq (aspath, peer->local_as); + } + else + aspath = attr->aspath; + + /* AS path attribute extended length bit check. */ + if (aspath->length > 255) + { + stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_AS_PATH); + stream_putw (s, aspath->length); + } + else + { + stream_putc (s, BGP_ATTR_FLAG_TRANS); + stream_putc(s, BGP_ATTR_AS_PATH); + stream_putc (s, aspath->length); + } + stream_put (s, aspath->data, aspath->length); + + if (aspath != attr->aspath) + aspath_free (aspath); + + /* Nexthop attribute. */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP) + { + stream_putc (s, BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_NEXT_HOP); + stream_putc (s, 4); + if (safi == SAFI_MPLS_VPN) + { + if (attr->nexthop.s_addr == 0) + stream_put_ipv4 (s, peer->nexthop.v4.s_addr); + else + stream_put_ipv4 (s, attr->nexthop.s_addr); + } + else + stream_put_ipv4 (s, attr->nexthop.s_addr); + } + + /* MED attribute. */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); + stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC); + stream_putc (s, 4); + stream_putl (s, attr->med); + } + + /* Local preference. */ + if (peer_sort (peer) == BGP_PEER_IBGP || + peer_sort (peer) == BGP_PEER_CONFED) + { + stream_putc (s, BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_LOCAL_PREF); + stream_putc (s, 4); + stream_putl (s, attr->local_pref); + } + + /* Atomic aggregate. */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE)) + { + stream_putc (s, BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE); + stream_putc (s, 0); + } + + /* Aggregator. */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_AGGREGATOR); + stream_putc (s, 6); + stream_putw (s, attr->aggregator_as); + stream_put_ipv4 (s, attr->aggregator_addr.s_addr); + } + + /* Community attribute. */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) + && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))) + { + if (attr->community->size * 4 > 255) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_COMMUNITIES); + stream_putw (s, attr->community->size * 4); + } + else + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_COMMUNITIES); + stream_putc (s, attr->community->size * 4); + } + stream_put (s, attr->community->val, attr->community->size * 4); + } + + /* Route Reflector. */ + if (peer_sort (peer) == BGP_PEER_IBGP + && from + && peer_sort (from) == BGP_PEER_IBGP) + { + /* Originator ID. */ + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); + stream_putc (s, BGP_ATTR_ORIGINATOR_ID); + stream_putc (s, 4); + + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) + stream_put_in_addr (s, &attr->originator_id); + else + { + if (from) + stream_put_in_addr (s, &from->remote_id); + else + stream_put_in_addr (s, &attr->originator_id); + } + + /* Cluster list. */ + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); + stream_putc (s, BGP_ATTR_CLUSTER_LIST); + + if (attr->cluster) + { + stream_putc (s, attr->cluster->length + 4); + /* If this peer configuration's parent BGP has cluster_id. */ + if (bgp->config & BGP_CONFIG_CLUSTER_ID) + stream_put_in_addr (s, &bgp->cluster_id); + else + stream_put_in_addr (s, &bgp->router_id); + stream_put (s, attr->cluster->list, attr->cluster->length); + } + else + { + stream_putc (s, 4); + /* If this peer configuration's parent BGP has cluster_id. */ + if (bgp->config & BGP_CONFIG_CLUSTER_ID) + stream_put_in_addr (s, &bgp->cluster_id); + else + stream_put_in_addr (s, &bgp->router_id); + } + } + +#ifdef HAVE_IPV6 + /* If p is IPv6 address put it into attribute. */ + if (p->family == AF_INET6) + { + unsigned long sizep; + + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); + stream_putc (s, BGP_ATTR_MP_REACH_NLRI); + sizep = stream_get_putp (s); + stream_putc (s, 0); /* Length of this attribute. */ + stream_putw (s, AFI_IP6); /* AFI */ + stream_putc (s, safi); /* SAFI */ + + stream_putc (s, attr->mp_nexthop_len); + + if (attr->mp_nexthop_len == 16) + stream_put (s, &attr->mp_nexthop_global, 16); + else if (attr->mp_nexthop_len == 32) + { + stream_put (s, &attr->mp_nexthop_global, 16); + stream_put (s, &attr->mp_nexthop_local, 16); + } + + /* SNPA */ + stream_putc (s, 0); + + /* Prefix write. */ + stream_put_prefix (s, p); + + /* Set MP attribute length. */ + stream_putc_at (s, sizep, (stream_get_putp (s) - sizep) - 1); + } +#endif /* HAVE_IPV6 */ + + if (p->family == AF_INET && safi == SAFI_MULTICAST) + { + unsigned long sizep; + + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); + stream_putc (s, BGP_ATTR_MP_REACH_NLRI); + sizep = stream_get_putp (s); + stream_putc (s, 0); /* Length of this attribute. */ + stream_putw (s, AFI_IP); /* AFI */ + stream_putc (s, SAFI_MULTICAST); /* SAFI */ + + stream_putc (s, 4); + stream_put_ipv4 (s, attr->nexthop.s_addr); + + /* SNPA */ + stream_putc (s, 0); + + /* Prefix write. */ + stream_put_prefix (s, p); + + /* Set MP attribute length. */ + stream_putc_at (s, sizep, (stream_get_putp (s) - sizep) - 1); + } + + if (p->family == AF_INET && safi == SAFI_MPLS_VPN) + { + unsigned long sizep; + + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); + stream_putc (s, BGP_ATTR_MP_REACH_NLRI); + sizep = stream_get_putp (s); + stream_putc (s, 0); /* Length of this attribute. */ + stream_putw (s, AFI_IP); /* AFI */ + stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */ + + stream_putc (s, 12); + stream_putl (s, 0); + stream_putl (s, 0); + stream_put (s, &attr->mp_nexthop_global_in, 4); + + /* SNPA */ + stream_putc (s, 0); + + /* Tag, RD, Prefix write. */ + stream_putc (s, p->prefixlen + 88); + stream_put (s, tag, 3); + stream_put (s, prd->val, 8); + stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); + + /* Set MP attribute length. */ + stream_putc_at (s, sizep, (stream_get_putp (s) - sizep) - 1); + } + + /* Extended Communities attribute. */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) + && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) + { + if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED) + { + if (attr->ecommunity->size * 8 > 255) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); + stream_putw (s, attr->ecommunity->size * 8); + } + else + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); + stream_putc (s, attr->ecommunity->size * 8); + } + stream_put (s, attr->ecommunity->val, attr->ecommunity->size * 8); + } + else + { + u_char *pnt; + int tbit; + int ecom_tr_size = 0; + int i; + + for (i = 0; i < attr->ecommunity->size; i++) + { + pnt = attr->ecommunity->val + (i * 8); + tbit = *pnt; + + if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE)) + continue; + + ecom_tr_size++; + } + + if (ecom_tr_size) + { + if (ecom_tr_size * 8 > 255) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); + stream_putw (s, ecom_tr_size * 8); + } + else + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); + stream_putc (s, ecom_tr_size * 8); + } + + for (i = 0; i < attr->ecommunity->size; i++) + { + pnt = attr->ecommunity->val + (i * 8); + tbit = *pnt; + + if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE)) + continue; + + stream_put (s, pnt, 8); + } + } + } + } + + /* Unknown transit attribute. */ + if (attr->transit) + stream_put (s, attr->transit->val, attr->transit->length); + + /* Return total size of attribute. */ + return stream_get_putp (s) - cp; +} + +bgp_size_t +bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, + afi_t afi, safi_t safi, struct prefix_rd *prd, + u_char *tag) +{ + unsigned long cp; + unsigned long attrlen_pnt; + bgp_size_t size; + + cp = stream_get_putp (s); + + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); + stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI); + + attrlen_pnt = stream_get_putp (s); + stream_putc (s, 0); /* Length of this attribute. */ + + stream_putw (s, family2afi (p->family)); + + if (safi == SAFI_MPLS_VPN) + { + /* SAFI */ + stream_putc (s, BGP_SAFI_VPNV4); + + /* prefix. */ + stream_putc (s, p->prefixlen + 88); + stream_put (s, tag, 3); + stream_put (s, prd->val, 8); + stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); + } + else + { + /* SAFI */ + stream_putc (s, safi); + + /* prefix */ + stream_put_prefix (s, p); + } + + /* Set MP attribute length. */ + size = stream_get_putp (s) - attrlen_pnt - 1; + stream_putc_at (s, attrlen_pnt, size); + + return stream_get_putp (s) - cp; +} + +/* Initialization of attribute. */ +void +bgp_attr_init () +{ + void attrhash_init (); + + aspath_init (); + attrhash_init (); + community_init (); + ecommunity_init (); + cluster_init (); + transit_init (); +} + +/* Make attribute packet. */ +void +bgp_dump_routes_attr (struct stream *s, struct attr *attr) +{ + unsigned long cp; + unsigned long len; + struct aspath *aspath; + + /* Remember current pointer. */ + cp = stream_get_putp (s); + + /* Place holder of length. */ + stream_putw (s, 0); + + /* Origin attribute. */ + stream_putc (s, BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_ORIGIN); + stream_putc (s, 1); + stream_putc (s, attr->origin); + + aspath = attr->aspath; + + if (aspath->length > 255) + { + stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_AS_PATH); + stream_putw (s, aspath->length); + } + else + { + stream_putc (s, BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_AS_PATH); + stream_putc (s, aspath->length); + } + stream_put (s, aspath->data, aspath->length); + + /* Nexthop attribute. */ + stream_putc (s, BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_NEXT_HOP); + stream_putc (s, 4); + stream_put_ipv4 (s, attr->nexthop.s_addr); + + /* MED attribute. */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); + stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC); + stream_putc (s, 4); + stream_putl (s, attr->med); + } + + /* Local preference. */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) + { + stream_putc (s, BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_LOCAL_PREF); + stream_putc (s, 4); + stream_putl (s, attr->local_pref); + } + + /* Atomic aggregate. */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE)) + { + stream_putc (s, BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE); + stream_putc (s, 0); + } + + /* Aggregator. */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_AGGREGATOR); + stream_putc (s, 6); + stream_putw (s, attr->aggregator_as); + stream_put_ipv4 (s, attr->aggregator_addr.s_addr); + } + + /* Community attribute. */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)) + { + if (attr->community->size * 4 > 255) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_COMMUNITIES); + stream_putw (s, attr->community->size * 4); + } + else + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_COMMUNITIES); + stream_putc (s, attr->community->size * 4); + } + stream_put (s, attr->community->val, attr->community->size * 4); + } + + /* Return total size of attribute. */ + len = stream_get_putp (s) - cp - 2; + stream_putw_at (s, cp, len); +} diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h new file mode 100644 index 0000000..9c5bf87 --- /dev/null +++ b/bgpd/bgp_attr.h @@ -0,0 +1,125 @@ +/* BGP attributes. + Copyright (C) 1996, 97, 98 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Simple bit mapping. */ +#define BITMAP_NBBY 8 + +#define SET_BITMAP(MAP, NUM) \ + SET_FLAG (MAP[(NUM) / BITMAP_NBBY], 1 << ((NUM) % BITMAP_NBBY)) + +#define CHECK_BITMAP(MAP, NUM) \ + CHECK_FLAG (MAP[(NUM) / BITMAP_NBBY], 1 << ((NUM) % BITMAP_NBBY)) + +/* BGP Attribute type range. */ +#define BGP_ATTR_TYPE_RANGE 256 +#define BGP_ATTR_BITMAP_SIZE (BGP_ATTR_TYPE_RANGE / BITMAP_NBBY) + +/* BGP Attribute flags. */ +#define BGP_ATTR_FLAG_OPTIONAL 0x80 /* Attribute is optional. */ +#define BGP_ATTR_FLAG_TRANS 0x40 /* Attribute is transitive. */ +#define BGP_ATTR_FLAG_PARTIAL 0x20 /* Attribute is partial. */ +#define BGP_ATTR_FLAG_EXTLEN 0x10 /* Extended length flag. */ + +/* BGP attribute header must bigger than 2. */ +#define BGP_ATTR_MIN_LEN 2 /* Attribute flag and type. */ + +/* BGP attribute structure. */ +struct attr +{ + /* Reference count of this attribute. */ + unsigned long refcnt; + + /* Flag of attribute is set or not. */ + u_int32_t flag; + + /* Attributes. */ + u_char origin; + struct in_addr nexthop; + u_int32_t med; + u_int32_t local_pref; + as_t aggregator_as; + struct in_addr aggregator_addr; + u_int32_t weight; + struct in_addr originator_id; + struct cluster_list *cluster; + + u_char mp_nexthop_len; +#ifdef HAVE_IPV6 + struct in6_addr mp_nexthop_global; + struct in6_addr mp_nexthop_local; +#endif /* HAVE_IPV6 */ + struct in_addr mp_nexthop_global_in; + struct in_addr mp_nexthop_local_in; + + /* AS Path structure */ + struct aspath *aspath; + + /* Community structure */ + struct community *community; + + /* Extended Communities attribute. */ + struct ecommunity *ecommunity; + + /* Unknown transitive attribute. */ + struct transit *transit; +}; + +/* Router Reflector related structure. */ +struct cluster_list +{ + unsigned long refcnt; + int length; + struct in_addr *list; +}; + +/* Unknown transit attribute. */ +struct transit +{ + unsigned long refcnt; + int length; + u_char *val; +}; + +#define ATTR_FLAG_BIT(X) (1 << ((X) - 1)) + +/* Prototypes. */ +void bgp_attr_init (); +int bgp_attr_parse (struct peer *, struct attr *, bgp_size_t, + struct bgp_nlri *, struct bgp_nlri *); +int bgp_attr_check (struct peer *, struct attr *); +struct attr *bgp_attr_intern (struct attr *attr); +void bgp_attr_unintern (struct attr *); +void bgp_attr_flush (struct attr *); +struct attr *bgp_attr_default_set (struct attr *attr, u_char); +struct attr *bgp_attr_default_intern (u_char); +struct attr *bgp_attr_aggregate_intern (struct bgp *, u_char, struct aspath *, struct community *, int as_set); +bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *, struct stream *, struct attr *, struct prefix *, afi_t, safi_t, struct peer *, struct prefix_rd *, u_char *); +bgp_size_t bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, afi_t, safi_t, struct prefix_rd *, u_char *); +void bgp_dump_routes_attr (struct stream *, struct attr *); +unsigned int attrhash_key_make (struct attr *); +int attrhash_cmp (struct attr *, struct attr *); +void attr_show_all (struct vty *); + +/* Cluster list prototypes. */ +int cluster_loop_check (struct cluster_list *, struct in_addr); +void cluster_unintern (struct cluster_list *); + +/* Transit attribute prototypes. */ +void transit_unintern (struct transit *); diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c new file mode 100644 index 0000000..be02549 --- /dev/null +++ b/bgpd/bgp_clist.c @@ -0,0 +1,848 @@ +/* BGP community-list and extcommunity-list. + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "command.h" +#include "prefix.h" +#include "memory.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_clist.h" + +/* Lookup master structure for community-list or + extcommunity-list. */ +struct community_list_master * +community_list_master_lookup (struct community_list_handler *ch, int master) +{ + if (ch) + switch (master) + { + case COMMUNITY_LIST_MASTER: + return &ch->community_list; + break; + case EXTCOMMUNITY_LIST_MASTER: + return &ch->extcommunity_list; + } + return NULL; +} + +/* Allocate a new community list entry. */ +struct community_entry * +community_entry_new () +{ + struct community_entry *new; + + new = XMALLOC (MTYPE_COMMUNITY_LIST_ENTRY, sizeof (struct community_entry)); + memset (new, 0, sizeof (struct community_entry)); + return new; +} + +/* Free community list entry. */ +void +community_entry_free (struct community_entry *entry) +{ + switch (entry->style) + { + case COMMUNITY_LIST_STANDARD: + if (entry->u.com) + community_free (entry->u.com); + break; + case EXTCOMMUNITY_LIST_STANDARD: + /* In case of standard extcommunity-list, configuration string + is made by ecommunity_ecom2str(). */ + if (entry->config) + XFREE (MTYPE_ECOMMUNITY_STR, entry->config); + if (entry->u.ecom) + ecommunity_free (entry->u.ecom); + break; + case COMMUNITY_LIST_EXPANDED: + case EXTCOMMUNITY_LIST_EXPANDED: + if (entry->config) + XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config); + if (entry->reg) + bgp_regex_free (entry->reg); + default: + break; + } + XFREE (MTYPE_COMMUNITY_LIST_ENTRY, entry); +} + +/* Allocate a new community-list. */ +struct community_list * +community_list_new () +{ + struct community_list *new; + + new = XMALLOC (MTYPE_COMMUNITY_LIST, sizeof (struct community_list)); + memset (new, 0, sizeof (struct community_list)); + return new; +} + +/* Free community-list. */ +void +community_list_free (struct community_list *list) +{ + if (list->name) + XFREE (MTYPE_COMMUNITY_LIST_NAME, list->name); + XFREE (MTYPE_COMMUNITY_LIST, list); +} + +struct community_list * +community_list_insert (struct community_list_handler *ch, + char *name, int master) +{ + int i; + long number; + struct community_list *new; + struct community_list *point; + struct community_list_list *list; + struct community_list_master *cm; + + /* Lookup community-list master. */ + cm = community_list_master_lookup (ch, master); + if (! cm) + return NULL; + + /* Allocate new community_list and copy given name. */ + new = community_list_new (); + new->name = XSTRDUP (MTYPE_COMMUNITY_LIST_NAME, name); + + /* If name is made by all digit character. We treat it as + number. */ + for (number = 0, i = 0; i < strlen (name); i++) + { + if (isdigit ((int) name[i])) + number = (number * 10) + (name[i] - '0'); + else + break; + } + + /* In case of name is all digit character */ + if (i == strlen (name)) + { + new->sort = COMMUNITY_LIST_NUMBER; + + /* Set access_list to number list. */ + list = &cm->num; + + for (point = list->head; point; point = point->next) + if (atol (point->name) >= number) + break; + } + else + { + new->sort = COMMUNITY_LIST_STRING; + + /* Set access_list to string list. */ + list = &cm->str; + + /* Set point to insertion point. */ + for (point = list->head; point; point = point->next) + if (strcmp (point->name, name) >= 0) + break; + } + + /* Link to upper list. */ + new->parent = list; + + /* In case of this is the first element of master. */ + if (list->head == NULL) + { + list->head = list->tail = new; + return new; + } + + /* In case of insertion is made at the tail of access_list. */ + if (point == NULL) + { + new->prev = list->tail; + list->tail->next = new; + list->tail = new; + return new; + } + + /* In case of insertion is made at the head of access_list. */ + if (point == list->head) + { + new->next = list->head; + list->head->prev = new; + list->head = new; + return new; + } + + /* Insertion is made at middle of the access_list. */ + new->next = point; + new->prev = point->prev; + + if (point->prev) + point->prev->next = new; + point->prev = new; + + return new; +} + +struct community_list * +community_list_lookup (struct community_list_handler *ch, + char *name, int master) +{ + struct community_list *list; + struct community_list_master *cm; + + if (! name) + return NULL; + + cm = community_list_master_lookup (ch, master); + if (! cm) + return NULL; + + for (list = cm->num.head; list; list = list->next) + if (strcmp (list->name, name) == 0) + return list; + for (list = cm->str.head; list; list = list->next) + if (strcmp (list->name, name) == 0) + return list; + + return NULL; +} + +struct community_list * +community_list_get (struct community_list_handler *ch, char *name, int master) +{ + struct community_list *list; + + list = community_list_lookup (ch, name, master); + if (! list) + list = community_list_insert (ch, name, master); + return list; +} + +void +community_list_delete (struct community_list *list) +{ + struct community_list_list *clist; + struct community_entry *entry, *next; + + for (entry = list->head; entry; entry = next) + { + next = entry->next; + community_entry_free (entry); + } + + clist = list->parent; + + if (list->next) + list->next->prev = list->prev; + else + clist->tail = list->prev; + + if (list->prev) + list->prev->next = list->next; + else + clist->head = list->next; + + community_list_free (list); +} + +int +community_list_empty_p (struct community_list *list) +{ + return (list->head == NULL && list->tail == NULL) ? 1 : 0; +} + +/* Add community-list entry to the list. */ +static void +community_list_entry_add (struct community_list *list, + struct community_entry *entry) +{ + entry->next = NULL; + entry->prev = list->tail; + + if (list->tail) + list->tail->next = entry; + else + list->head = entry; + list->tail = entry; +} + +/* Delete community-list entry from the list. */ +static void +community_list_entry_delete (struct community_list *list, + struct community_entry *entry, int style) +{ + if (entry->next) + entry->next->prev = entry->prev; + else + list->tail = entry->prev; + + if (entry->prev) + entry->prev->next = entry->next; + else + list->head = entry->next; + + community_entry_free (entry); + + if (community_list_empty_p (list)) + community_list_delete (list); +} + +/* Lookup community-list entry from the list. */ +static struct community_entry * +community_list_entry_lookup (struct community_list *list, void *arg, + int direct) +{ + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) + { + switch (entry->style) + { + case COMMUNITY_LIST_STANDARD: + if (community_cmp (entry->u.com, arg)) + return entry; + break; + case EXTCOMMUNITY_LIST_STANDARD: + if (ecommunity_cmp (entry->u.ecom, arg)) + return entry; + break; + case COMMUNITY_LIST_EXPANDED: + case EXTCOMMUNITY_LIST_EXPANDED: + if (strcmp (entry->config, arg) == 0) + return entry; + break; + default: + break; + } + } + return NULL; +} + +/* Internal function to perform regular expression match for community + attribute. */ +static int +community_regexp_match (struct community *com, regex_t *reg) +{ + char *str; + + /* When there is no communities attribute it is treated as empty + string. */ + if (com == NULL || com->size == 0) + str = ""; + else + str = community_str (com); + + /* Regular expression match. */ + if (regexec (reg, str, 0, NULL, 0) == 0) + return 1; + + /* No match. */ + return 0; +} + +static int +ecommunity_regexp_match (struct ecommunity *ecom, regex_t *reg) +{ + char *str; + + /* When there is no communities attribute it is treated as empty + string. */ + if (ecom == NULL || ecom->size == 0) + str = ""; + else + str = ecommunity_str (ecom); + + /* Regular expression match. */ + if (regexec (reg, str, 0, NULL, 0) == 0) + return 1; + + /* No match. */ + return 0; +} + +/* When given community attribute matches to the community-list return + 1 else return 0. */ +int +community_list_match (struct community *com, struct community_list *list) +{ + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) + { + if (entry->any) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + + if (entry->style == COMMUNITY_LIST_STANDARD) + { + if (community_include (entry->u.com, COMMUNITY_INTERNET)) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + + if (community_match (com, entry->u.com)) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + } + else if (entry->style == COMMUNITY_LIST_EXPANDED) + { + if (community_regexp_match (com, entry->reg)) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + } + } + return 0; +} + +int +ecommunity_list_match (struct ecommunity *ecom, struct community_list *list) +{ + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) + { + if (entry->any) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + + if (entry->style == EXTCOMMUNITY_LIST_STANDARD) + { + if (ecommunity_match (ecom, entry->u.ecom)) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + } + else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED) + { + if (ecommunity_regexp_match (ecom, entry->reg)) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + } + } + return 0; +} + +/* Perform exact matching. In case of expanded community-list, do + same thing as community_list_match(). */ +int +community_list_exact_match (struct community *com, struct community_list *list) +{ + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) + { + if (entry->any) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + + if (entry->style == COMMUNITY_LIST_STANDARD) + { + if (community_include (entry->u.com, COMMUNITY_INTERNET)) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + + if (community_cmp (com, entry->u.com)) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + } + else if (entry->style == COMMUNITY_LIST_EXPANDED) + { + if (community_regexp_match (com, entry->reg)) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + } + } + return 0; +} + +/* Do regular expression matching with single community val. */ +static int +comval_regexp_match (u_int32_t comval, regex_t *reg) +{ + /* Maximum is "65535:65535" + '\0'. */ + char c[12]; + char *str; + + switch (comval) + { + case COMMUNITY_INTERNET: + str = "internet"; + break; + case COMMUNITY_NO_EXPORT: + str = "no-export"; + break; + case COMMUNITY_NO_ADVERTISE: + str = "no-advertise"; + break; + case COMMUNITY_LOCAL_AS: + str = "local-AS"; + break; + default: + snprintf (c, sizeof c, + "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF); + str = c; + break; + } + + if (regexec (reg, str, 0, NULL, 0) == 0) + return 1; + + return 0; +} + +/* Delete all permitted communities in the list from com. */ +struct community * +community_list_match_delete (struct community *com, + struct community_list *clist) +{ + int i; + u_int32_t comval; + struct community *merge; + struct community_entry *entry; + + /* Empty community value check. */ + if (! com) + return NULL; + + /* Duplicate communities value. */ + merge = community_dup (com); + + /* For each communities value, we have to check each + community-list. */ + for (i = 0; i < com->size; i ++) + { + /* Get one communities value. */ + memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); + comval = ntohl (comval); + + /* Loop community-list. */ + for (entry = clist->head; entry; entry = entry->next) + { + /* Various match condition check. */ + if (entry->any + || (entry->style == COMMUNITY_LIST_STANDARD + && entry->u.com + && community_include (entry->u.com, comval)) + || (entry->style == COMMUNITY_LIST_EXPANDED + && entry->reg + && comval_regexp_match (comval, entry->reg))) + { + /* If the rule is "permit", delete this community value. */ + if (entry->direct == COMMUNITY_PERMIT) + community_del_val (merge, com_nthval (com, i)); + + /* Exit community-list loop, goto next communities + value. */ + break; + } + } + } + return merge; +} + +/* To avoid duplicated entry in the community-list, this function + compares specified entry to existing entry. */ +int +community_list_dup_check (struct community_list *list, + struct community_entry *new) +{ + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) + { + if (entry->style != new->style) + continue; + + if (entry->direct != new->direct) + continue; + + if (entry->any != new->any) + continue; + + if (entry->any) + return 1; + + switch (entry->style) + { + case COMMUNITY_LIST_STANDARD: + if (community_cmp (entry->u.com, new->u.com)) + return 1; + break; + case EXTCOMMUNITY_LIST_STANDARD: + if (ecommunity_cmp (entry->u.ecom, new->u.ecom)) + return 1; + break; + case COMMUNITY_LIST_EXPANDED: + case EXTCOMMUNITY_LIST_EXPANDED: + if (strcmp (entry->config, new->config) == 0) + return 1; + break; + default: + break; + } + } + return 0; +} + +/* Set community-list. */ +int +community_list_set (struct community_list_handler *ch, + char *name, char *str, int direct, int style) +{ + struct community_entry *entry = NULL; + struct community_list *list; + struct community *com = NULL; + regex_t *regex = NULL; + + /* Get community list. */ + list = community_list_get (ch, name, COMMUNITY_LIST_MASTER); + + /* When community-list already has entry, new entry should have same + style. If you want to have mixed style community-list, you can + comment out this check. */ + if (! community_list_empty_p (list)) + { + struct community_entry *first; + + first = list->head; + + if (style != first->style) + { + return (first->style == COMMUNITY_LIST_STANDARD + ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT + : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT); + } + } + + if (str) + { + if (style == COMMUNITY_LIST_STANDARD) + com = community_str2com (str); + else + regex = bgp_regcomp (str); + + if (! com && ! regex) + return COMMUNITY_LIST_ERR_MALFORMED_VAL; + } + + entry = community_entry_new (); + entry->direct = direct; + entry->style = style; + entry->any = (str ? 0 : 1); + entry->u.com = com; + entry->reg = regex; + entry->config = (regex ? XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL); + + /* Do not put duplicated community entry. */ + if (community_list_dup_check (list, entry)) + community_entry_free (entry); + else + community_list_entry_add (list, entry); + + return 0; +} + +/* Unset community-list. When str is NULL, delete all of + community-list entry belongs to the specified name. */ +int +community_list_unset (struct community_list_handler *ch, + char *name, char *str, int direct, int style) +{ + struct community_entry *entry = NULL; + struct community_list *list; + struct community *com = NULL; + regex_t *regex = NULL; + + /* Lookup community list. */ + list = community_list_lookup (ch, name, COMMUNITY_LIST_MASTER); + if (list == NULL) + return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + + /* Delete all of entry belongs to this community-list. */ + if (! str) + { + community_list_delete (list); + return 0; + } + + if (style == COMMUNITY_LIST_STANDARD) + com = community_str2com (str); + else + regex = bgp_regcomp (str); + + if (! com && ! regex) + return COMMUNITY_LIST_ERR_MALFORMED_VAL; + + if (com) + entry = community_list_entry_lookup (list, com, direct); + else + entry = community_list_entry_lookup (list, str, direct); + + if (com) + community_free (com); + if (regex) + bgp_regex_free (regex); + + if (! entry) + return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + + community_list_entry_delete (list, entry, style); + + return 0; +} + +/* Set extcommunity-list. */ +int +extcommunity_list_set (struct community_list_handler *ch, + char *name, char *str, int direct, int style) +{ + struct community_entry *entry = NULL; + struct community_list *list; + struct ecommunity *ecom = NULL; + regex_t *regex = NULL; + + entry = NULL; + + /* Get community list. */ + list = community_list_get (ch, name, EXTCOMMUNITY_LIST_MASTER); + + /* When community-list already has entry, new entry should have same + style. If you want to have mixed style community-list, you can + comment out this check. */ + if (! community_list_empty_p (list)) + { + struct community_entry *first; + + first = list->head; + + if (style != first->style) + { + return (first->style == EXTCOMMUNITY_LIST_STANDARD + ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT + : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT); + } + } + + if (str) + { + if (style == EXTCOMMUNITY_LIST_STANDARD) + ecom = ecommunity_str2com (str, 0, 1); + else + regex = bgp_regcomp (str); + + if (! ecom && ! regex) + return COMMUNITY_LIST_ERR_MALFORMED_VAL; + } + + if (ecom) + ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY); + + entry = community_entry_new (); + entry->direct = direct; + entry->style = style; + entry->any = (str ? 0 : 1); + if (ecom) + entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_CONFIG); + else if (regex) + entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str); + else + entry->config = NULL; + entry->u.ecom = ecom; + entry->reg = regex; + + /* Do not put duplicated community entry. */ + if (community_list_dup_check (list, entry)) + community_entry_free (entry); + else + community_list_entry_add (list, entry); + + return 0; +} + +/* Unset extcommunity-list. When str is NULL, delete all of + extcommunity-list entry belongs to the specified name. */ +int +extcommunity_list_unset (struct community_list_handler *ch, + char *name, char *str, int direct, int style) +{ + struct community_entry *entry = NULL; + struct community_list *list; + struct ecommunity *ecom = NULL; + regex_t *regex = NULL; + + /* Lookup extcommunity list. */ + list = community_list_lookup (ch, name, EXTCOMMUNITY_LIST_MASTER); + if (list == NULL) + return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + + /* Delete all of entry belongs to this extcommunity-list. */ + if (! str) + { + community_list_delete (list); + return 0; + } + + if (style == EXTCOMMUNITY_LIST_STANDARD) + ecom = ecommunity_str2com (str, 0, 1); + else + regex = bgp_regcomp (str); + + if (! ecom && ! regex) + return COMMUNITY_LIST_ERR_MALFORMED_VAL; + + if (ecom) + entry = community_list_entry_lookup (list, ecom, direct); + else + entry = community_list_entry_lookup (list, str, direct); + + if (ecom) + ecommunity_free (ecom); + if (regex) + bgp_regex_free (regex); + + if (! entry) + return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + + community_list_entry_delete (list, entry, style); + + return 0; +} + +/* Initializa community-list. Return community-list handler. */ +struct community_list_handler * +community_list_init () +{ + struct community_list_handler *ch; + ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER, + sizeof (struct community_list_handler)); + return ch; +} + +/* Terminate community-list. */ +void +community_list_terminate (struct community_list_handler *ch) +{ + struct community_list_master *cm; + struct community_list *list; + + cm = &ch->community_list; + while ((list = cm->num.head) != NULL) + community_list_delete (list); + while ((list = cm->str.head) != NULL) + community_list_delete (list); + + cm = &ch->extcommunity_list; + while ((list = cm->num.head) != NULL) + community_list_delete (list); + while ((list = cm->str.head) != NULL) + community_list_delete (list); + + XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch); +} diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h new file mode 100644 index 0000000..c7b7c50 --- /dev/null +++ b/bgpd/bgp_clist.h @@ -0,0 +1,146 @@ +/* BGP Community list. + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Master Community-list. */ +#define COMMUNITY_LIST_MASTER 0 +#define EXTCOMMUNITY_LIST_MASTER 1 + +/* Community-list deny and permit. */ +#define COMMUNITY_DENY 0 +#define COMMUNITY_PERMIT 1 + +/* Number and string based community-list name. */ +#define COMMUNITY_LIST_STRING 0 +#define COMMUNITY_LIST_NUMBER 1 + +/* Community-list entry types. */ +#define COMMUNITY_LIST_STANDARD 0 /* Standard community-list. */ +#define COMMUNITY_LIST_EXPANDED 1 /* Expanded community-list. */ +#define EXTCOMMUNITY_LIST_STANDARD 2 /* Standard extcommunity-list. */ +#define EXTCOMMUNITY_LIST_EXPANDED 3 /* Expanded extcommunity-list. */ + +/* Community-list. */ +struct community_list +{ + /* Name of the community-list. */ + char *name; + + /* String or number. */ + int sort; + + /* Link to upper list. */ + struct community_list_list *parent; + + /* Linked list for other community-list. */ + struct community_list *next; + struct community_list *prev; + + /* Community-list entry in this community-list. */ + struct community_entry *head; + struct community_entry *tail; +}; + +/* Each entry in community-list. */ +struct community_entry +{ + struct community_entry *next; + struct community_entry *prev; + + /* Permit or deny. */ + u_char direct; + + /* Standard or expanded. */ + u_char style; + + /* Any match. */ + u_char any; + + /* Community structure. */ + union + { + struct community *com; + struct ecommunity *ecom; + } u; + + /* Configuration string. */ + char *config; + + /* Expanded community-list regular expression. */ + regex_t *reg; +}; + +/* Linked list of community-list. */ +struct community_list_list +{ + struct community_list *head; + struct community_list *tail; +}; + +/* Master structure of community-list and extcommunity-list. */ +struct community_list_master +{ + struct community_list_list num; + struct community_list_list str; +}; + +/* Community-list handler. community_list_init() returns this + structure as handler. */ +struct community_list_handler +{ + /* Community-list. */ + struct community_list_master community_list; + + /* Exteded community-list. */ + struct community_list_master extcommunity_list; +}; + +/* Error code of community-list. */ +#define COMMUNITY_LIST_ERR_CANT_FIND_LIST -1 +#define COMMUNITY_LIST_ERR_MALFORMED_VAL -2 +#define COMMUNITY_LIST_ERR_STANDARD_CONFLICT -3 +#define COMMUNITY_LIST_ERR_EXPANDED_CONFLICT -4 + +/* Handler. */ +extern struct community_list_handler *bgp_clist; + +/* Prototypes. */ +struct community_list_handler *community_list_init (); + +int community_list_set (struct community_list_handler *ch, + char *name, char *str, int direct, int style); +int community_list_unset (struct community_list_handler *ch, + char *name, char *str, int direct, int style); +int extcommunity_list_set (struct community_list_handler *ch, + char *name, char *str, int direct, int style); +int extcommunity_list_unset (struct community_list_handler *ch, + char *name, char *str, int direct, int style); + +struct community_list_master * +community_list_master_lookup (struct community_list_handler *, int); + +struct community_list * +community_list_lookup (struct community_list_handler *, char *, int); + +int community_list_match (struct community *, struct community_list *); +int ecommunity_list_match (struct ecommunity *, struct community_list *); +int community_list_exact_match (struct community *, struct community_list *); +struct community * +community_list_match_delete (struct community *, + struct community_list *); diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c new file mode 100644 index 0000000..83b1cc5 --- /dev/null +++ b/bgpd/bgp_community.c @@ -0,0 +1,629 @@ +/* Community attribute related functions. + Copyright (C) 1998, 2001 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "hash.h" +#include "memory.h" + +#include "bgpd/bgp_community.h" + +/* Hash of community attribute. */ +struct hash *comhash; + +/* Allocate a new communities value. */ +struct community * +community_new () +{ + return (struct community *) XCALLOC (MTYPE_COMMUNITY, + sizeof (struct community)); +} + +/* Free communities value. */ +void +community_free (struct community *com) +{ + if (com->val) + XFREE (MTYPE_COMMUNITY_VAL, com->val); + if (com->str) + XFREE (MTYPE_COMMUNITY_STR, com->str); + XFREE (MTYPE_COMMUNITY, com); +} + +/* Add one community value to the community. */ +void +community_add_val (struct community *com, u_int32_t val) +{ + com->size++; + if (com->val) + com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com)); + else + com->val = XMALLOC (MTYPE_COMMUNITY_VAL, com_length (com)); + + val = htonl (val); + memcpy (com_lastval (com), &val, sizeof (u_int32_t)); +} + +/* Delete one community. */ +void +community_del_val (struct community *com, u_int32_t *val) +{ + int i = 0; + int c = 0; + + if (! com->val) + return; + + while (i < com->size) + { + if (memcmp (com->val + i, val, sizeof (u_int32_t)) == 0) + { + c = com->size -i -1; + + if (c > 0) + memcpy (com->val + i, com->val + (i + 1), c * sizeof (val)); + + com->size--; + + if (com->size > 0) + com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, + com_length (com)); + else + { + XFREE (MTYPE_COMMUNITY_VAL, com->val); + com->val = NULL; + } + return; + } + i++; + } +} + +/* Delete all communities listed in com2 from com1 */ +struct community * +community_delete (struct community *com1, struct community *com2) +{ + int i = 0; + + while(i < com2->size) + { + community_del_val (com1, com2->val + i); + i++; + } + + return com1; +} + +/* Callback function from qsort(). */ +int +community_compare (const void *a1, const void *a2) +{ + u_int32_t v1; + u_int32_t v2; + + memcpy (&v1, a1, sizeof (u_int32_t)); + memcpy (&v2, a2, sizeof (u_int32_t)); + v1 = ntohl (v1); + v2 = ntohl (v2); + + if (v1 < v2) + return -1; + if (v1 > v2) + return 1; + return 0; +} + +int +community_include (struct community *com, u_int32_t val) +{ + int i; + + val = htonl (val); + + for (i = 0; i < com->size; i++) + if (memcmp (&val, com_nthval (com, i), sizeof (u_int32_t)) == 0) + return 1; + + return 0; +} + +u_int32_t +community_val_get (struct community *com, int i) +{ + u_char *p; + u_int32_t val; + + p = (u_char *) com->val; + p += (i * 4); + + memcpy (&val, p, sizeof (u_int32_t)); + + return ntohl (val); +} + +/* Sort and uniq given community. */ +struct community * +community_uniq_sort (struct community *com) +{ + int i; + struct community *new; + u_int32_t val; + + if (! com) + return NULL; + + new = community_new ();; + + for (i = 0; i < com->size; i++) + { + val = community_val_get (com, i); + + if (! community_include (new, val)) + community_add_val (new, val); + } + + qsort (new->val, new->size, sizeof (u_int32_t), community_compare); + + return new; +} + +/* Convert communities attribute to string. + + For Well-known communities value, below keyword is used. + + 0x0 "internet" + 0xFFFFFF01 "no-export" + 0xFFFFFF02 "no-advertise" + 0xFFFFFF03 "local-AS" + + For other values, "AS:VAL" format is used. */ +static char * +community_com2str (struct community *com) +{ + int i; + char *str; + char *pnt; + int len; + int first; + u_int32_t comval; + u_int16_t as; + u_int16_t val; + + /* When communities attribute is empty. */ + if (com->size == 0) + { + str = XMALLOC (MTYPE_COMMUNITY_STR, 1); + str[0] = '\0'; + return str; + } + + /* Memory allocation is time consuming work. So we calculate + required string length first. */ + len = 0; + + for (i = 0; i < com->size; i++) + { + memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); + comval = ntohl (comval); + + switch (comval) + { + case COMMUNITY_INTERNET: + len += strlen (" internet"); + break; + case COMMUNITY_NO_EXPORT: + len += strlen (" no-export"); + break; + case COMMUNITY_NO_ADVERTISE: + len += strlen (" no-advertise"); + break; + case COMMUNITY_LOCAL_AS: + len += strlen (" local-AS"); + break; + default: + len += strlen (" 65536:65535"); + break; + } + } + + /* Allocate memory. */ + str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len); + first = 1; + + /* Fill in string. */ + for (i = 0; i < com->size; i++) + { + memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); + comval = ntohl (comval); + + if (first) + first = 0; + else + *pnt++ = ' '; + + switch (comval) + { + case COMMUNITY_INTERNET: + strcpy (pnt, "internet"); + pnt += strlen ("internet"); + break; + case COMMUNITY_NO_EXPORT: + strcpy (pnt, "no-export"); + pnt += strlen ("no-export"); + break; + case COMMUNITY_NO_ADVERTISE: + strcpy (pnt, "no-advertise"); + pnt += strlen ("no-advertise"); + break; + case COMMUNITY_LOCAL_AS: + strcpy (pnt, "local-AS"); + pnt += strlen ("local-AS"); + break; + default: + as = (comval >> 16) & 0xFFFF; + val = comval & 0xFFFF; + sprintf (pnt, "%d:%d", as, val); + pnt += strlen (pnt); + break; + } + } + *pnt = '\0'; + + return str; +} + +/* Intern communities attribute. */ +struct community * +community_intern (struct community *com) +{ + struct community *find; + + /* Assert this community structure is not interned. */ + assert (com->refcnt == 0); + + /* Lookup community hash. */ + find = (struct community *) hash_get (comhash, com, hash_alloc_intern); + + /* Arguemnt com is allocated temporary. So when it is not used in + hash, it should be freed. */ + if (find != com) + community_free (com); + + /* Increment refrence counter. */ + find->refcnt++; + + /* Make string. */ + if (! find->str) + find->str = community_com2str (find); + + return find; +} + +/* Free community attribute. */ +void +community_unintern (struct community *com) +{ + struct community *ret; + + if (com->refcnt) + com->refcnt--; + + /* Pull off from hash. */ + if (com->refcnt == 0) + { + /* Community value com must exist in hash. */ + ret = (struct community *) hash_release (comhash, com); + assert (ret != NULL); + + community_free (com); + } +} + +/* Create new community attribute. */ +struct community * +community_parse (char *pnt, u_short length) +{ + struct community tmp; + struct community *new; + + /* If length is malformed return NULL. */ + if (length % 4) + return NULL; + + /* Make temporary community for hash look up. */ + tmp.size = length / 4; + tmp.val = (u_int32_t *) pnt; + + new = community_uniq_sort (&tmp); + + return community_intern (new); +} + +struct community * +community_dup (struct community *com) +{ + struct community *new; + + new = XCALLOC (MTYPE_COMMUNITY, sizeof (struct community)); + new->size = com->size; + if (new->size) + { + new->val = XMALLOC (MTYPE_COMMUNITY_VAL, com->size * 4); + memcpy (new->val, com->val, com->size * 4); + } + else + new->val = NULL; + return new; +} + +/* Retrun string representation of communities attribute. */ +char * +community_str (struct community *com) +{ + if (! com->str) + com->str = community_com2str (com); + return com->str; +} + +/* Make hash value of community attribute. This function is used by + hash package.*/ +unsigned int +community_hash_make (struct community *com) +{ + int c; + unsigned int key; + unsigned char *pnt; + + key = 0; + pnt = (unsigned char *)com->val; + + for(c = 0; c < com->size * 4; c++) + key += pnt[c]; + + return key; +} + +int +community_match (struct community *com1, struct community *com2) +{ + int i = 0; + int j = 0; + + if (com1 == NULL && com2 == NULL) + return 1; + + if (com1 == NULL || com2 == NULL) + return 0; + + if (com1->size < com2->size) + return 0; + + /* Every community on com2 needs to be on com1 for this to match */ + while (i < com1->size && j < com2->size) + { + if (memcmp (com1->val + i, com2->val + j, sizeof (u_int32_t)) == 0) + j++; + i++; + } + + if (j == com2->size) + return 1; + else + return 0; +} + +/* If two aspath have same value then return 1 else return 0. This + function is used by hash package. */ +int +community_cmp (struct community *com1, struct community *com2) +{ + if (com1 == NULL && com2 == NULL) + return 1; + if (com1 == NULL || com2 == NULL) + return 0; + + if (com1->size == com2->size) + if (memcmp (com1->val, com2->val, com1->size * 4) == 0) + return 1; + return 0; +} + +/* Add com2 to the end of com1. */ +struct community * +community_merge (struct community *com1, struct community *com2) +{ + if (com1->val) + com1->val = XREALLOC (MTYPE_COMMUNITY_VAL, com1->val, + (com1->size + com2->size) * 4); + else + com1->val = XMALLOC (MTYPE_COMMUNITY_VAL, (com1->size + com2->size) * 4); + + memcpy (com1->val + com1->size, com2->val, com2->size * 4); + com1->size += com2->size; + + return com1; +} + +/* Community token enum. */ +enum community_token +{ + community_token_val, + community_token_no_export, + community_token_no_advertise, + community_token_local_as, + community_token_unknown +}; + +/* Get next community token from string. */ +char * +community_gettoken (char *buf, enum community_token *token, u_int32_t *val) +{ + char *p = buf; + + /* Skip white space. */ + while (isspace ((int) *p)) + p++; + + /* Check the end of the line. */ + if (*p == '\0') + return NULL; + + /* Well known community string check. */ + if (isalpha ((int) *p)) + { + if (strncmp (p, "internet", strlen ("internet")) == 0) + { + *val = COMMUNITY_INTERNET; + *token = community_token_no_export; + p += strlen ("internet"); + return p; + } + if (strncmp (p, "no-export", strlen ("no-export")) == 0) + { + *val = COMMUNITY_NO_EXPORT; + *token = community_token_no_export; + p += strlen ("no-export"); + return p; + } + if (strncmp (p, "no-advertise", strlen ("no-advertise")) == 0) + { + *val = COMMUNITY_NO_ADVERTISE; + *token = community_token_no_advertise; + p += strlen ("no-advertise"); + return p; + } + if (strncmp (p, "local-AS", strlen ("local-AS")) == 0) + { + *val = COMMUNITY_LOCAL_AS; + *token = community_token_local_as; + p += strlen ("local-AS"); + return p; + } + + /* Unknown string. */ + *token = community_token_unknown; + return p; + } + + /* Community value. */ + if (isdigit ((int) *p)) + { + int separator = 0; + int digit = 0; + u_int32_t community_low = 0; + u_int32_t community_high = 0; + + while (isdigit ((int) *p) || *p == ':') + { + if (*p == ':') + { + if (separator) + { + *token = community_token_unknown; + return p; + } + else + { + separator = 1; + digit = 0; + community_high = community_low << 16; + community_low = 0; + } + } + else + { + digit = 1; + community_low *= 10; + community_low += (*p - '0'); + } + p++; + } + if (! digit) + { + *token = community_token_unknown; + return p; + } + *val = community_high + community_low; + *token = community_token_val; + return p; + } + *token = community_token_unknown; + return p; +} + +/* convert string to community structure */ +struct community * +community_str2com (char *str) +{ + struct community *com = NULL; + struct community *com_sort = NULL; + u_int32_t val; + enum community_token token; + + while ((str = community_gettoken (str, &token, &val))) + { + switch (token) + { + case community_token_val: + case community_token_no_export: + case community_token_no_advertise: + case community_token_local_as: + if (com == NULL) + com = community_new(); + community_add_val (com, val); + break; + case community_token_unknown: + default: + if (com) + community_free (com); + return NULL; + break; + } + } + + if (! com) + return NULL; + + com_sort = community_uniq_sort (com); + community_free (com); + + return com_sort; +} + +/* Return communities hash entry count. */ +unsigned long +community_count () +{ + return comhash->count; +} + +/* Return communities hash. */ +struct hash * +community_hash () +{ + return comhash; +} + +/* Initialize comminity related hash. */ +void +community_init () +{ + comhash = hash_create (community_hash_make, community_cmp); +} diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h new file mode 100644 index 0000000..58b3f9e --- /dev/null +++ b/bgpd/bgp_community.h @@ -0,0 +1,68 @@ +/* Community attribute related functions. + Copyright (C) 1998 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Communities attribute. */ +struct community +{ + /* Reference count of communities value. */ + unsigned long refcnt; + + /* Communities value size. */ + int size; + + /* Communities value. */ + u_int32_t *val; + + /* String of community attribute. This sring is used by vty output + and expanded community-list for regular expression match. */ + char *str; +}; + +/* Well-known communities value. */ +#define COMMUNITY_INTERNET 0x0 +#define COMMUNITY_NO_EXPORT 0xFFFFFF01 +#define COMMUNITY_NO_ADVERTISE 0xFFFFFF02 +#define COMMUNITY_NO_EXPORT_SUBCONFED 0xFFFFFF03 +#define COMMUNITY_LOCAL_AS 0xFFFFFF03 + +/* Macros of community attribute. */ +#define com_length(X) ((X)->size * 4) +#define com_lastval(X) ((X)->val + (X)->size - 1) +#define com_nthval(X,n) ((X)->val + (n)) + +/* Prototypes of communities attribute functions. */ +void community_init (); +void community_free (struct community *); +struct community *community_uniq_sort (struct community *); +struct community *community_parse (char *, u_short); +struct community *community_intern (struct community *); +void community_unintern (struct community *); +char *community_str (struct community *); +unsigned int community_hash_make (struct community *); +struct community *community_str2com (char *); +int community_match (struct community *, struct community *); +int community_cmp (struct community *, struct community *); +struct community *community_merge (struct community *, struct community *); +struct community *community_delete (struct community *, struct community *); +struct community *community_dup (struct community *); +int community_include (struct community *, u_int32_t); +void community_del_val (struct community *, u_int32_t *); +unsigned long community_count (); +struct hash *community_hash (); diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c new file mode 100644 index 0000000..d70105f --- /dev/null +++ b/bgpd/bgp_damp.c @@ -0,0 +1,648 @@ +/* BGP flap dampening + Copyright (C) 2001 IP Infusion Inc. + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include +#include + +#include "prefix.h" +#include "memory.h" +#include "command.h" +#include "log.h" +#include "thread.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_damp.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_advertise.h" + +/* Global variable to access damping configuration */ +struct bgp_damp_config bgp_damp_cfg; +struct bgp_damp_config *damp = &bgp_damp_cfg; + +/* Utility macro to add and delete BGP dampening information to no + used list. */ +#define BGP_DAMP_LIST_ADD(N,A) BGP_INFO_ADD(N,A,no_reuse_list) +#define BGP_DAMP_LIST_DEL(N,A) BGP_INFO_DEL(N,A,no_reuse_list) + +/* Calculate reuse list index by penalty value. */ +static int +bgp_reuse_index (int penalty) +{ + int i; + int index; + + i = (int)(((double) penalty / damp->reuse_limit - 1.0) * damp->scale_factor); + + if ( i >= damp->reuse_index_size ) + i = damp->reuse_index_size - 1; + + index = damp->reuse_index[i] - damp->reuse_index[0]; + + return (damp->reuse_offset + index) % damp->reuse_list_size; +} + +/* Add BGP dampening information to reuse list. */ +static void +bgp_reuse_list_add (struct bgp_damp_info *bdi) +{ + int index; + + index = bdi->index = bgp_reuse_index (bdi->penalty); + + bdi->prev = NULL; + bdi->next = damp->reuse_list[index]; + if (damp->reuse_list[index]) + damp->reuse_list[index]->prev = bdi; + damp->reuse_list[index] = bdi; +} + +/* Delete BGP dampening information from reuse list. */ +static void +bgp_reuse_list_delete (struct bgp_damp_info *bdi) +{ + if (bdi->next) + bdi->next->prev = bdi->prev; + if (bdi->prev) + bdi->prev->next = bdi->next; + else + damp->reuse_list[bdi->index] = bdi->next; +} + +/* Return decayed penalty value. */ +int +bgp_damp_decay (time_t tdiff, int penalty) +{ + int i; + + i = (int) ((double) tdiff / DELTA_T); + + if (i == 0) + return penalty; + + if (i >= damp->decay_array_size) + return 0; + + return (int) (penalty * damp->decay_array[i]); +} + +/* Handler of reuse timer event. Each route in the current reuse-list + is evaluated. RFC2439 Section 4.8.7. */ +int +bgp_reuse_timer (struct thread *t) +{ + struct bgp_damp_info *bdi; + struct bgp_damp_info *next; + time_t t_now, t_diff; + struct bgp *bgp; + int bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t); + + damp->t_reuse = NULL; + damp->t_reuse = + thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE); + + bgp = bgp_get_default (); + if (! bgp) + return 0; + + t_now = time (NULL); + + /* 1. save a pointer to the current zeroth queue head and zero the + list head entry. */ + bdi = damp->reuse_list[damp->reuse_offset]; + damp->reuse_list[damp->reuse_offset] = NULL; + + /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby + rotating the circular queue of list-heads. */ + damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size; + + /* 3. if ( the saved list head pointer is non-empty ) */ + for (; bdi; bdi = next) + { + next = bdi->next; + + /* Set t-diff = t-now - t-updated. */ + t_diff = t_now - bdi->t_updated; + + /* Set figure-of-merit = figure-of-merit * decay-array-ok [t-diff] */ + bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty); + + /* Set t-updated = t-now. */ + bdi->t_updated = t_now; + + /* if (figure-of-merit < reuse). */ + if (bdi->penalty < damp->reuse_limit) + { + /* Reuse the route. */ + UNSET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED); + bdi->suppress_time = 0; + + if (bdi->lastrecord == BGP_RECORD_UPDATE) + { + UNSET_FLAG (bdi->binfo->flags, BGP_INFO_HISTORY); + bgp_aggregate_increment (bgp, &bdi->rn->p, bdi->binfo, + bdi->afi, bdi->safi); + bgp_process (bgp, bdi->rn, bdi->afi, bdi->safi); + } + + if (bdi->penalty <= damp->reuse_limit / 2.0) + bgp_damp_info_free (bdi, 1); + else + BGP_DAMP_LIST_ADD (damp, bdi); + } + else + /* Re-insert into another list (See RFC2439 Section 4.8.6). */ + bgp_reuse_list_add (bdi); + } + + return 0; +} + +/* A route becomes unreachable (RFC2439 Section 4.8.2). */ +int +bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn, + afi_t afi, safi_t safi, int attr_change) +{ + time_t t_now; + struct bgp_damp_info *bdi; + double last_penalty = 0; + + t_now = time (NULL); + + /* Processing Unreachable Messages. */ + bdi = binfo->damp_info; + + if (bdi == NULL) + { + /* If there is no previous stability history. */ + + /* RFC2439 said: + 1. allocate a damping structure. + 2. set figure-of-merit = 1. + 3. withdraw the route. */ + + bdi = XCALLOC (MTYPE_BGP_DAMP_INFO, sizeof (struct bgp_damp_info)); + bdi->binfo = binfo; + bdi->rn = rn; + bdi->penalty = (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY); + bdi->flap = 1; + bdi->start_time = t_now; + bdi->suppress_time = 0; + bdi->index = -1; + bdi->afi = afi; + bdi->safi = safi; + binfo->damp_info = bdi; + BGP_DAMP_LIST_ADD (damp, bdi); + } + else + { + last_penalty = bdi->penalty; + + /* 1. Set t-diff = t-now - t-updated. */ + bdi->penalty = + (bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty) + + (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY)); + + if (bdi->penalty > damp->ceiling) + bdi->penalty = damp->ceiling; + + bdi->flap++; + } + + bdi->lastrecord = BGP_RECORD_WITHDRAW; + bdi->t_updated = t_now; + + /* Make this route as historical status. */ + SET_FLAG (binfo->flags, BGP_INFO_HISTORY); + + /* Remove the route from a reuse list if it is on one. */ + if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)) + { + /* If decay rate isn't equal to 0, reinsert brn. */ + if (bdi->penalty != last_penalty) + { + bgp_reuse_list_delete (bdi); + bgp_reuse_list_add (bdi); + } + return BGP_DAMP_SUPPRESSED; + } + + /* If not suppressed before, do annonunce this withdraw and + insert into reuse_list. */ + if (bdi->penalty >= damp->suppress_value) + { + SET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED); + bdi->suppress_time = t_now; + BGP_DAMP_LIST_DEL (damp, bdi); + bgp_reuse_list_add (bdi); + } + + return BGP_DAMP_USED; +} + +int +bgp_damp_update (struct bgp_info *binfo, struct bgp_node *rn, + afi_t afi, safi_t safi) +{ + time_t t_now; + struct bgp_damp_info *bdi; + int status; + + bdi = binfo->damp_info; + if (! bdi) + return BGP_DAMP_USED; + + t_now = time (NULL); + UNSET_FLAG (binfo->flags, BGP_INFO_HISTORY); + + bdi->lastrecord = BGP_RECORD_UPDATE; + bdi->penalty = bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty); + + if (! CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED) + && (bdi->penalty < damp->suppress_value)) + status = BGP_DAMP_USED; + else if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED) + && (bdi->penalty < damp->reuse_limit) ) + { + UNSET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED); + bgp_reuse_list_delete (bdi); + BGP_DAMP_LIST_ADD (damp, bdi); + bdi->suppress_time = 0; + status = BGP_DAMP_USED; + } + else + status = BGP_DAMP_SUPPRESSED; + + if (bdi->penalty > damp->reuse_limit / 2.0) + bdi->t_updated = t_now; + else + bgp_damp_info_free (bdi, 0); + + return status; +} + +/* Remove dampening information and history route. */ +int +bgp_damp_scan (struct bgp_info *binfo, afi_t afi, safi_t safi) +{ + time_t t_now, t_diff; + struct bgp_damp_info *bdi; + + t_now = time (NULL); + bdi = binfo->damp_info; + + if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) + { + t_diff = t_now - bdi->suppress_time; + + if (t_diff >= damp->max_suppress_time) + { + UNSET_FLAG (binfo->flags, BGP_INFO_DAMPED); + bgp_reuse_list_delete (bdi); + BGP_DAMP_LIST_ADD (damp, bdi); + bdi->penalty = damp->reuse_limit; + bdi->suppress_time = 0; + bdi->t_updated = t_now; + + /* Need to announce UPDATE once this binfo is usable again. */ + if (bdi->lastrecord == BGP_RECORD_UPDATE) + return 1; + else + return 0; + } + } + else + { + t_diff = t_now - bdi->t_updated; + bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty); + + if (bdi->penalty <= damp->reuse_limit / 2.0) + { + /* release the bdi, bdi->binfo. */ + bgp_damp_info_free (bdi, 1); + return 0; + } + else + bdi->t_updated = t_now; + } + return 0; +} + +void +bgp_damp_info_free (struct bgp_damp_info *bdi, int withdraw) +{ + struct bgp_info *binfo; + void bgp_info_delete (struct bgp_node *, struct bgp_info *); + void bgp_info_free (struct bgp_info *); + + if (! bdi) + return; + + binfo = bdi->binfo; + binfo->damp_info = NULL; + + if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) + bgp_reuse_list_delete (bdi); + else + BGP_DAMP_LIST_DEL (damp, bdi); + + UNSET_FLAG (binfo->flags, BGP_INFO_DAMPED); + UNSET_FLAG (binfo->flags, BGP_INFO_HISTORY); + + if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) + { + bgp_info_delete (bdi->rn, binfo); + bgp_info_free (binfo); + bgp_unlock_node (bdi->rn); + } + XFREE (MTYPE_BGP_DAMP_INFO, bdi); +} + +void +bgp_damp_parameter_set (int hlife, int reuse, int sup, int maxsup) +{ + double reuse_max_ratio; + int i; + double j; + + damp->suppress_value = sup; + damp->half_life = hlife; + damp->reuse_limit = reuse; + damp->max_suppress_time = maxsup; + + /* Initialize params per bgp_damp_config. */ + damp->reuse_index_size = REUSE_ARRAY_SIZE; + + damp->ceiling = (int)(damp->reuse_limit * (pow(2, (double)damp->max_suppress_time/damp->half_life))); + + /* Decay-array computations */ + damp->decay_array_size = ceil ((double) damp->max_suppress_time / DELTA_T); + damp->decay_array = XMALLOC (MTYPE_BGP_DAMP_ARRAY, + sizeof(double) * (damp->decay_array_size)); + damp->decay_array[0] = 1.0; + damp->decay_array[1] = exp ((1.0/((double)damp->half_life/DELTA_T)) * log(0.5)); + + /* Calculate decay values for all possible times */ + for (i = 2; i < damp->decay_array_size; i++) + damp->decay_array[i] = damp->decay_array[i-1] * damp->decay_array[1]; + + /* Reuse-list computations */ + i = ceil ((double)damp->max_suppress_time / DELTA_REUSE) + 1; + if (i > REUSE_LIST_SIZE || i == 0) + i = REUSE_LIST_SIZE; + damp->reuse_list_size = i; + + damp->reuse_list = XCALLOC (MTYPE_BGP_DAMP_ARRAY, + damp->reuse_list_size + * sizeof (struct bgp_reuse_node *)); + memset (damp->reuse_list, 0x00, + damp->reuse_list_size * sizeof (struct bgp_reuse_node *)); + + /* Reuse-array computations */ + damp->reuse_index = XMALLOC (MTYPE_BGP_DAMP_ARRAY, + sizeof(int) * damp->reuse_index_size); + memset (damp->reuse_index, 0x00, + damp->reuse_list_size * sizeof (int)); + + reuse_max_ratio = (double)damp->ceiling/damp->reuse_limit; + j = (exp((double)damp->max_suppress_time/damp->half_life) * log10(2.0)); + if ( reuse_max_ratio > j && j != 0 ) + reuse_max_ratio = j; + + damp->scale_factor = (double)damp->reuse_index_size/(reuse_max_ratio - 1); + + for (i = 0; i < damp->reuse_index_size; i++) + { + damp->reuse_index[i] = + (int)(((double)damp->half_life / DELTA_REUSE) + * log10 (1.0 / (damp->reuse_limit * ( 1.0 + ((double)i/damp->scale_factor)))) / log10(0.5)); + } +} + +int +bgp_damp_enable (struct bgp *bgp, afi_t afi, safi_t safi, int half, + int reuse, int suppress, int max) +{ + if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) + { + if (damp->half_life == half + && damp->reuse_limit == reuse + && damp->suppress_value == suppress + && damp->max_suppress_time == max) + return 0; + bgp_damp_disable (bgp, afi, safi); + } + + SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); + bgp_damp_parameter_set (half, reuse, suppress, max); + + /* Register reuse timer. */ + if (! damp->t_reuse) + damp->t_reuse = + thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE); + + return 0; +} + +void +bgp_damp_config_clean (struct bgp_damp_config *damp) +{ + /* Free decay array */ + XFREE (MTYPE_BGP_DAMP_ARRAY, damp->decay_array); + + /* Free reuse index array */ + XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_index); + + /* Free reuse list array. */ + XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_list); +} + +/* Clean all the bgp_damp_info stored in reuse_list. */ +void +bgp_damp_info_clean () +{ + int i; + struct bgp_damp_info *bdi, *next; + + damp->reuse_offset = 0; + + for (i = 0; i < damp->reuse_list_size; i++) + { + if (! damp->reuse_list[i]) + continue; + + for (bdi = damp->reuse_list[i]; bdi; bdi = next) + { + next = bdi->next; + bgp_damp_info_free (bdi, 1); + } + damp->reuse_list[i] = NULL; + } + + for (bdi = damp->no_reuse_list; bdi; bdi = next) + { + next = bdi->next; + bgp_damp_info_free (bdi, 1); + } + damp->no_reuse_list = NULL; +} + +int +bgp_damp_disable (struct bgp *bgp, afi_t afi, safi_t safi) +{ + /* Cancel reuse thread. */ + if (damp->t_reuse ) + thread_cancel (damp->t_reuse); + damp->t_reuse = NULL; + + /* Clean BGP dampening information. */ + bgp_damp_info_clean (); + + /* Clear configuration */ + bgp_damp_config_clean (&bgp_damp_cfg); + + UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); + return 0; +} + +int +bgp_config_write_damp (struct vty *vty) +{ + if (&bgp_damp_cfg) + { + if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE*60 + && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE + && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS + && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4) + vty_out (vty, " bgp dampening%s", VTY_NEWLINE); + else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE*60 + && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE + && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS + && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4) + vty_out (vty, " bgp dampening %d%s", + bgp_damp_cfg.half_life/60, + VTY_NEWLINE); + else + vty_out (vty, " bgp dampening %d %d %d %d%s", + bgp_damp_cfg.half_life/60, + bgp_damp_cfg.reuse_limit, + bgp_damp_cfg.suppress_value, + bgp_damp_cfg.max_suppress_time/60, + VTY_NEWLINE); + return 1; + } + return 0; +} + +#define BGP_UPTIME_LEN 25 + +char * +bgp_get_reuse_time (int penalty, char *buf, size_t len) +{ + time_t reuse_time = 0; + struct tm *tm = NULL; + + if (penalty > damp->reuse_limit) + { + reuse_time = (int) (DELTA_T * ((log((double)damp->reuse_limit/penalty))/(log(damp->decay_array[1])))); + + if (reuse_time > damp->max_suppress_time) + reuse_time = damp->max_suppress_time; + + tm = gmtime (&reuse_time); + } + else + reuse_time = 0; + + /* Making formatted timer strings. */ +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + if (reuse_time == 0) + snprintf (buf, len, "00:00:00"); + else if (reuse_time < ONE_DAY_SECOND) + snprintf (buf, len, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (reuse_time < ONE_WEEK_SECOND) + snprintf (buf, len, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + snprintf (buf, len, "%02dw%dd%02dh", + tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + + return buf; +} + +void +bgp_damp_info_vty (struct vty *vty, struct bgp_info *binfo) +{ + struct bgp_damp_info *bdi; + time_t t_now, t_diff; + char timebuf[BGP_UPTIME_LEN]; + int penalty; + + /* BGP dampening information. */ + bdi = binfo->damp_info; + + /* If dampening is not enabled or there is no dampening information, + return immediately. */ + if (! damp || ! bdi) + return; + + /* Calculate new penalty. */ + t_now = time (NULL); + t_diff = t_now - bdi->t_updated; + penalty = bgp_damp_decay (t_diff, bdi->penalty); + + vty_out (vty, " Dampinfo: penalty %d, flapped %d times in %s", + penalty, bdi->flap, + peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN)); + + if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED) + && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + vty_out (vty, ", reuse in %s", + bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN)); + + vty_out (vty, "%s", VTY_NEWLINE); +} + +char * +bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo) +{ + struct bgp_damp_info *bdi; + time_t t_now, t_diff; + char timebuf[BGP_UPTIME_LEN]; + int penalty; + + /* BGP dampening information. */ + bdi = binfo->damp_info; + + /* If dampening is not enabled or there is no dampening information, + return immediately. */ + if (! damp || ! bdi) + return NULL; + + /* Calculate new penalty. */ + t_now = time (NULL); + t_diff = t_now - bdi->t_updated; + penalty = bgp_damp_decay (t_diff, bdi->penalty); + + return bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN); +} diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h new file mode 100644 index 0000000..f3b9bd6 --- /dev/null +++ b/bgpd/bgp_damp.h @@ -0,0 +1,141 @@ +/* BGP flap dampening + Copyright (C) 2001 IP Infusion Inc. + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Structure maintained on a per-route basis. */ +struct bgp_damp_info +{ + /* Doubly linked list. This information must be linked to + reuse_list or no_reuse_list. */ + struct bgp_damp_info *next; + struct bgp_damp_info *prev; + + /* Figure-of-merit. */ + int penalty; + + /* Number of flapping. */ + int flap; + + /* First flap time */ + time_t start_time; + + /* Last time penalty was updated. */ + time_t t_updated; + + /* Time of route start to be suppressed. */ + time_t suppress_time; + + /* Back reference to bgp_info. */ + struct bgp_info *binfo; + + /* Back reference to bgp_node. */ + struct bgp_node *rn; + + /* Current index in the reuse_list. */ + int index; + + /* Last time message type. */ + u_char lastrecord; +#define BGP_RECORD_UPDATE 1 +#define BGP_RECORD_WITHDRAW 2 + + afi_t afi; + safi_t safi; +}; + +/* Specified parameter set configuration. */ +struct bgp_damp_config +{ + /* Value over which routes suppressed. */ + int suppress_value; + + /* Value below which suppressed routes reused. */ + int reuse_limit; + + /* Max time a route can be suppressed. */ + int max_suppress_time; + + /* Time during which accumulated penalty reduces by half. */ + int half_life; + + /* Non-configurable parameters but fixed at implementation time. + * To change this values, init_bgp_damp() should be modified. + */ + int tmax; /* Max time previous instability retained */ + int reuse_list_size; /* Number of reuse lists */ + int reuse_index_size; /* Size of reuse index array */ + + /* Non-configurable parameters. Most of these are calculated from + * the configurable parameters above. + */ + unsigned int ceiling; /* Max value a penalty can attain */ + int decay_rate_per_tick; /* Calculated from half-life */ + int decay_array_size; /* Calculated using config parameters */ + double scale_factor; + int reuse_scale_factor; + + /* Decay array per-set based. */ + double *decay_array; + + /* Reuse index array per-set based. */ + int *reuse_index; + + /* Reuse list array per-set based. */ + struct bgp_damp_info **reuse_list; + int reuse_offset; + + /* All dampening information which is not on reuse list. */ + struct bgp_damp_info *no_reuse_list; + + /* Reuse timer thread per-set base. */ + struct thread* t_reuse; +}; + +#define BGP_DAMP_NONE 0 +#define BGP_DAMP_USED 1 +#define BGP_DAMP_SUPPRESSED 2 + +/* Time granularity for reuse lists */ +#define DELTA_REUSE 10 + +/* Time granularity for decay arrays */ +#define DELTA_T 5 + +#define DEFAULT_PENALTY 1000 + +#define DEFAULT_HALF_LIFE 15 +#define DEFAULT_REUSE 750 +#define DEFAULT_SUPPRESS 2000 + +#define REUSE_LIST_SIZE 256 +#define REUSE_ARRAY_SIZE 1024 + +int bgp_damp_enable (struct bgp *, afi_t, safi_t, int, int, int, int); +int bgp_damp_disable (struct bgp *, afi_t, safi_t); +int bgp_damp_withdraw (struct bgp_info *, struct bgp_node *, + afi_t, safi_t, int); +int bgp_damp_update (struct bgp_info *, struct bgp_node *, afi_t, safi_t); +int bgp_damp_scan (struct bgp_info *, afi_t, safi_t); +void bgp_damp_info_free (struct bgp_damp_info *, int); +void bgp_damp_info_clean (); +char * bgp_get_reuse_time (int, char*, size_t); +int bgp_damp_decay (time_t, int); +int bgp_config_write_damp (struct vty *); +void bgp_damp_info_vty (struct vty *, struct bgp_info *); +char * bgp_damp_reuse_time_vty (struct vty *, struct bgp_info *); diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c new file mode 100644 index 0000000..b002303 --- /dev/null +++ b/bgpd/bgp_debug.c @@ -0,0 +1,754 @@ +/* BGP-4, BGP-4+ packet debug routine + Copyright (C) 1996, 97, 99 Kunihiro Ishiguro + + This file is part of GNU Zebra. + + GNU Zebra 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, or (at your option) any + later version. + + GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include + +#include "version.h" +#include "prefix.h" +#include "linklist.h" +#include "stream.h" +#include "command.h" +#include "str.h" +#include "log.h" +#include "sockunion.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_ecommunity.h" + +unsigned long conf_bgp_debug_fsm; +unsigned long conf_bgp_debug_events; +unsigned long conf_bgp_debug_packet; +unsigned long conf_bgp_debug_filter; +unsigned long conf_bgp_debug_keepalive; +unsigned long conf_bgp_debug_update; +unsigned long conf_bgp_debug_normal; + +unsigned long term_bgp_debug_fsm; +unsigned long term_bgp_debug_events; +unsigned long term_bgp_debug_packet; +unsigned long term_bgp_debug_filter; +unsigned long term_bgp_debug_keepalive; +unsigned long term_bgp_debug_update; +unsigned long term_bgp_debug_normal; + +/* messages for BGP-4 status */ +struct message bgp_status_msg[] = + { + { 0, "null" }, + { Idle, "Idle" }, + { Connect, "Connect" }, + { Active, "Active" }, + { OpenSent, "OpenSent" }, + { OpenConfirm, "OpenConfirm" }, + { Established, "Established" }, + }; +int bgp_status_msg_max = BGP_STATUS_MAX; + +/* BGP message type string. */ +char *bgp_type_str[] = + { + NULL, + "OPEN", + "UPDATE", + "NOTIFICATION", + "KEEPALIVE", + "ROUTE-REFRESH", + "CAPABILITY" + }; + +/* message for BGP-4 Notify */ +struct message bgp_notify_msg[] = + { + { 0, "" }, + { BGP_NOTIFY_HEADER_ERR, "Message Header Error"}, + { BGP_NOTIFY_OPEN_ERR, "OPEN Message Error"}, + { BGP_NOTIFY_UPDATE_ERR, "UPDATE Message Error"}, + { BGP_NOTIFY_HOLD_ERR, "Hold Timer Expired"}, + { BGP_NOTIFY_FSM_ERR, "Finite State Machine Error"}, + { BGP_NOTIFY_CEASE, "Cease"}, + { BGP_NOTIFY_CAPABILITY_ERR, "CAPABILITY Message Error"}, + }; +int bgp_notify_msg_max = BGP_NOTIFY_MAX; + +struct message bgp_notify_head_msg[] = + { + { 0, "null"}, + { BGP_NOTIFY_HEADER_NOT_SYNC, "/Connection Not Synchronized"}, + { BGP_NOTIFY_HEADER_BAD_MESLEN, "/Bad Message Length"}, + { BGP_NOTIFY_HEADER_BAD_MESTYPE, "/Bad Message Type"} + }; +int bgp_notify_head_msg_max = BGP_NOTIFY_HEADER_MAX; + +struct message bgp_notify_open_msg[] = + { + { 0, "null" }, + { BGP_NOTIFY_OPEN_UNSUP_VERSION, "/Unsupported Version Number" }, + { BGP_NOTIFY_OPEN_BAD_PEER_AS, "/Bad Peer AS"}, + { BGP_NOTIFY_OPEN_BAD_BGP_IDENT, "/Bad BGP Identifier"}, + { BGP_NOTIFY_OPEN_UNSUP_PARAM, "/Unsupported Optional Parameter"}, + { BGP_NOTIFY_OPEN_AUTH_FAILURE, "/Authentication Failure"}, + { BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, "/Unacceptable Hold Time"}, + { BGP_NOTIFY_OPEN_UNSUP_CAPBL, "/Unsupported Capability"}, + }; +int bgp_notify_open_msg_max = BGP_NOTIFY_OPEN_MAX; + +struct message bgp_notify_update_msg[] = + { + { 0, "null"}, + { BGP_NOTIFY_UPDATE_MAL_ATTR, "/Malformed Attribute List"}, + { BGP_NOTIFY_UPDATE_UNREC_ATTR, "/Unrecognized Well-known Attribute"}, + { BGP_NOTIFY_UPDATE_MISS_ATTR, "/Missing Well-known Attribute"}, + { BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, "/Attribute Flags Error"}, + { BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, "/Attribute Length Error"}, + { BGP_NOTIFY_UPDATE_INVAL_ORIGIN, "/Invalid ORIGIN Attribute"}, + { BGP_NOTIFY_UPDATE_AS_ROUTE_LOOP, "/AS Routing Loop"}, + { BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, "/Invalid NEXT_HOP Attribute"}, + { BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, "/Optional Attribute Error"}, + { BGP_NOTIFY_UPDATE_INVAL_NETWORK, "/Invalid Network Field"}, + { BGP_NOTIFY_UPDATE_MAL_AS_PATH, "/Malformed AS_PATH"}, + }; +int bgp_notify_update_msg_max = BGP_NOTIFY_UPDATE_MAX; + +struct message bgp_notify_cease_msg[] = + { + { 0, ""}, + { BGP_NOTIFY_CEASE_MAX_PREFIX, "/Maximum Number of Prefixes Reached"}, + { BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, "/Administratively Shutdown"}, + { BGP_NOTIFY_CEASE_PEER_UNCONFIG, "/Peer Unconfigured"}, + { BGP_NOTIFY_CEASE_ADMIN_RESET, "/Administratively Reset"}, + { BGP_NOTIFY_CEASE_CONNECT_REJECT, "/Connection Rejected"}, + { BGP_NOTIFY_CEASE_CONFIG_CHANGE, "/Other Configuration Change"}, + { BGP_NOTIFY_CEASE_CONNECT_COLLISION, "/Connection Collision Resolution"}, + { BGP_NOTIFY_CEASE_OUT_OF_RESOURCE, "/Out of Resource"}, + }; +int bgp_notify_cease_msg_max = BGP_NOTIFY_CEASE_MAX; + +struct message bgp_notify_capability_msg[] = + { + { 0, "null"}, + { BGP_NOTIFY_CAPABILITY_INVALID_ACTION, "/Invalid Action Value"}, + { BGP_NOTIFY_CAPABILITY_INVALID_LENGTH, "/Invalid Capability Length"}, + { BGP_NOTIFY_CAPABILITY_MALFORMED_CODE, "/Malformed Capability Value"}, + }; +int bgp_notify_capability_msg_max = BGP_NOTIFY_CAPABILITY_MAX; + +/* Origin strings. */ +char *bgp_origin_str[] = {"i","e","?"}; +char *bgp_origin_long_str[] = {"IGP","EGP","incomplete"}; + +/* Dump attribute. */ +int +bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size) +{ + if (! attr) + return 0; + + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) + snprintf (buf, size, "nexthop %s", inet_ntoa (attr->nexthop)); + + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) + snprintf (buf + strlen (buf), size - strlen (buf), ", origin %s", + bgp_origin_str[attr->origin]); + +#ifdef HAVE_IPV6 + { + char addrbuf[BUFSIZ]; + + /* Add MP case. */ + if (attr->mp_nexthop_len == 16 || attr->mp_nexthop_len == 32) + snprintf (buf + strlen (buf), size - strlen (buf), ", mp_nexthop %s", + inet_ntop (AF_INET6, &attr->mp_nexthop_global, + addrbuf, BUFSIZ)); + + if (attr->mp_nexthop_len == 32) + snprintf (buf + strlen (buf), size - strlen (buf), "(%s)", + inet_ntop (AF_INET6, &attr->mp_nexthop_local, + addrbuf, BUFSIZ)); + } +#endif /* HAVE_IPV6 */ + + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) + snprintf (buf + strlen (buf), size - strlen (buf), ", localpref %u", + attr->local_pref); + + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) + snprintf (buf + strlen (buf), size - strlen (buf), ", metric %u", + attr->med); + + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))) + snprintf (buf + strlen (buf), size - strlen (buf), ", community %s", + community_str (attr->community)); + + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) + snprintf (buf + strlen (buf), size - strlen (buf), ", ecommunity %s", + ecommunity_str (attr->ecommunity)); + + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))) + snprintf (buf + strlen (buf), size - strlen (buf), ", atomic-aggregate"); + + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))) + snprintf (buf + strlen (buf), size - strlen (buf), ", aggregated by %d %s", + attr->aggregator_as, inet_ntoa (attr->aggregator_addr)); + + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))) + snprintf (buf + strlen (buf), size - strlen (buf), ", originator %s", + inet_ntoa (attr->originator_id)); + + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST))) + { + int i; + + snprintf (buf + strlen (buf), size - strlen (buf), ", clusterlist"); + for (i = 0; i < attr->cluster->length / 4; i++) + snprintf (buf + strlen (buf), size - strlen (buf), " %s", + inet_ntoa (attr->cluster->list[i])); + } + + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) + snprintf (buf + strlen (buf), size - strlen (buf), ", path %s", + aspath_print (attr->aspath)); + + if (strlen (buf) > 1) + return 1; + else + return 0; +} + +/* dump notify packet */ +void +bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, char *direct) +{ + char *subcode_str; + + subcode_str = ""; + + switch (bgp_notify->code) + { + case BGP_NOTIFY_HEADER_ERR: + subcode_str = LOOKUP (bgp_notify_head_msg, bgp_notify->subcode); + break; + case BGP_NOTIFY_OPEN_ERR: + subcode_str = LOOKUP (bgp_notify_open_msg, bgp_notify->subcode); + break; + case BGP_NOTIFY_UPDATE_ERR: + subcode_str = LOOKUP (bgp_notify_update_msg, bgp_notify->subcode); + break; + case BGP_NOTIFY_HOLD_ERR: + subcode_str = ""; + break; + case BGP_NOTIFY_FSM_ERR: + subcode_str = ""; + break; + case BGP_NOTIFY_CEASE: + subcode_str = LOOKUP (bgp_notify_cease_msg, bgp_notify->subcode); + break; + case BGP_NOTIFY_CAPABILITY_ERR: + subcode_str = LOOKUP (bgp_notify_capability_msg, bgp_notify->subcode); + break; + } + + if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) + zlog_info ("%%NOTIFICATION: %s neighbor %s %d/%d (%s%s) %d bytes %s", + strcmp (direct, "received") == 0 ? "received from" : "sent to", + peer->host, bgp_notify->code, bgp_notify->subcode, + LOOKUP (bgp_notify_msg, bgp_notify->code), + subcode_str, bgp_notify->length, + bgp_notify->data ? bgp_notify->data : ""); + else if (BGP_DEBUG (normal, NORMAL)) + plog_info (peer->log, "%s %s NOTIFICATION %d/%d (%s%s) %d bytes %s", + peer ? peer->host : "", + direct, bgp_notify->code, bgp_notify->subcode, + LOOKUP (bgp_notify_msg, bgp_notify->code), + subcode_str, bgp_notify->length, + bgp_notify->data ? bgp_notify->data : ""); +} + +/* Debug option setting interface. */ +unsigned long bgp_debug_option = 0; + +int +debug (unsigned int option) +{ + return bgp_debug_option & option; +} + +DEFUN (debug_bgp_fsm, + debug_bgp_fsm_cmd, + "debug bgp fsm", + DEBUG_STR + BGP_STR + "BGP Finite State Machine\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (fsm, FSM); + else + { + TERM_DEBUG_ON (fsm, FSM); + vty_out (vty, "BGP fsm debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_fsm, + no_debug_bgp_fsm_cmd, + "no debug bgp fsm", + NO_STR + DEBUG_STR + BGP_STR + "Finite State Machine\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (fsm, FSM); + else + { + TERM_DEBUG_OFF (fsm, FSM); + vty_out (vty, "BGP fsm debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_fsm, + undebug_bgp_fsm_cmd, + "undebug bgp fsm", + UNDEBUG_STR + DEBUG_STR + BGP_STR + "Finite State Machine\n"); + +DEFUN (debug_bgp_events, + debug_bgp_events_cmd, + "debug bgp events", + DEBUG_STR + BGP_STR + "BGP events\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (events, EVENTS); + else + { + TERM_DEBUG_ON (events, EVENTS); + vty_out (vty, "BGP events debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_events, + no_debug_bgp_events_cmd, + "no debug bgp events", + NO_STR + DEBUG_STR + BGP_STR + "BGP events\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (events, EVENTS); + else + { + TERM_DEBUG_OFF (events, EVENTS); + vty_out (vty, "BGP events debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_events, + undebug_bgp_events_cmd, + "undebug bgp events", + UNDEBUG_STR + BGP_STR + "BGP events\n"); + +DEFUN (debug_bgp_filter, + debug_bgp_filter_cmd, + "debug bgp filters", + DEBUG_STR + BGP_STR + "BGP filters\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (filter, FILTER); + else + { + TERM_DEBUG_ON (filter, FILTER); + vty_out (vty, "BGP filters debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_filter, + no_debug_bgp_filter_cmd, + "no debug bgp filters", + NO_STR + DEBUG_STR + BGP_STR + "BGP filters\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (filter, FILTER); + else + { + TERM_DEBUG_OFF (filter, FILTER); + vty_out (vty, "BGP filters debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_filter, + undebug_bgp_filter_cmd, + "undebug bgp filters", + UNDEBUG_STR + BGP_STR + "BGP filters\n"); + +DEFUN (debug_bgp_keepalive, + debug_bgp_keepalive_cmd, + "debug bgp keepalives", + DEBUG_STR + BGP_STR + "BGP keepalives\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (keepalive, KEEPALIVE); + else + { + TERM_DEBUG_ON (keepalive, KEEPALIVE); + vty_out (vty, "BGP keepalives debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_keepalive, + no_debug_bgp_keepalive_cmd, + "no debug bgp keepalives", + NO_STR + DEBUG_STR + BGP_STR + "BGP keepalives\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (keepalive, KEEPALIVE); + else + { + TERM_DEBUG_OFF (keepalive, KEEPALIVE); + vty_out (vty, "BGP keepalives debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_keepalive, + undebug_bgp_keepalive_cmd, + "undebug bgp keepalives", + UNDEBUG_STR + BGP_STR + "BGP keepalives\n"); + +DEFUN (debug_bgp_update, + debug_bgp_update_cmd, + "debug bgp updates", + DEBUG_STR + BGP_STR + "BGP updates\n") +{ + if (vty->node == CONFIG_NODE) + { + DEBUG_ON (update, UPDATE_IN); + DEBUG_ON (update, UPDATE_OUT); + } + else + { + TERM_DEBUG_ON (update, UPDATE_IN); + TERM_DEBUG_ON (update, UPDATE_OUT); + vty_out (vty, "BGP updates debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (debug_bgp_update_direct, + debug_bgp_update_direct_cmd, + "debug bgp updates (in|out)", + DEBUG_STR + BGP_STR + "BGP updates\n" + "Inbound updates\n" + "Outbound updates\n") +{ + if (vty->node == CONFIG_NODE) + { + if (strncmp ("i", argv[0], 1) == 0) + { + DEBUG_OFF (update, UPDATE_OUT); + DEBUG_ON (update, UPDATE_IN); + } + else + { + DEBUG_OFF (update, UPDATE_IN); + DEBUG_ON (update, UPDATE_OUT); + } + } + else + { + if (strncmp ("i", argv[0], 1) == 0) + { + TERM_DEBUG_OFF (update, UPDATE_OUT); + TERM_DEBUG_ON (update, UPDATE_IN); + vty_out (vty, "BGP updates debugging is on (inbound)%s", VTY_NEWLINE); + } + else + { + TERM_DEBUG_OFF (update, UPDATE_IN); + TERM_DEBUG_ON (update, UPDATE_OUT); + vty_out (vty, "BGP updates debugging is on (outbound)%s", VTY_NEWLINE); + } + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_update, + no_debug_bgp_update_cmd, + "no debug bgp updates", + NO_STR + DEBUG_STR + BGP_STR + "BGP updates\n") +{ + if (vty->node == CONFIG_NODE) + { + DEBUG_OFF (update, UPDATE_IN); + DEBUG_OFF (update, UPDATE_OUT); + } + else + { + TERM_DEBUG_OFF (update, UPDATE_IN); + TERM_DEBUG_OFF (update, UPDATE_OUT); + vty_out (vty, "BGP updates debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_update, + undebug_bgp_update_cmd, + "undebug bgp updates", + UNDEBUG_STR + BGP_STR + "BGP updates\n"); + +DEFUN (debug_bgp_normal, + debug_bgp_normal_cmd, + "debug bgp", + DEBUG_STR + BGP_STR) +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON (normal, NORMAL); + else + { + TERM_DEBUG_ON (normal, NORMAL); + vty_out (vty, "BGP debugging is on%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_normal, + no_debug_bgp_normal_cmd, + "no debug bgp", + NO_STR + DEBUG_STR + BGP_STR) +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF (normal, NORMAL); + else + { + TERM_DEBUG_OFF (normal, NORMAL); + vty_out (vty, "BGP debugging is off%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_normal, + undebug_bgp_normal_cmd, + "undebug bgp", + UNDEBUG_STR + BGP_STR); + +DEFUN (no_debug_bgp_all, + no_debug_bgp_all_cmd, + "no debug all bgp", + NO_STR + DEBUG_STR + "Enable all debugging\n" + BGP_STR) +{ + TERM_DEBUG_OFF (normal, NORMAL); + TERM_DEBUG_OFF (events, EVENTS); + TERM_DEBUG_OFF (keepalive, KEEPALIVE); + TERM_DEBUG_OFF (update, UPDATE_IN); + TERM_DEBUG_OFF (update, UPDATE_OUT); + TERM_DEBUG_OFF (fsm, FSM); + TERM_DEBUG_OFF (filter, FILTER); + vty_out (vty, "All possible debugging has been turned off%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_all, + undebug_bgp_all_cmd, + "undebug all bgp", + UNDEBUG_STR + "Enable all debugging\n" + BGP_STR); + +DEFUN (show_debugging_bgp, + show_debugging_bgp_cmd, + "show debugging bgp", + SHOW_STR + DEBUG_STR + BGP_STR) +{ + vty_out (vty, "BGP debugging status:%s", VTY_NEWLINE); + + if (BGP_DEBUG (normal, NORMAL)) + vty_out (vty, " BGP debugging is on%s", VTY_NEWLINE); + if (BGP_DEBUG (events, EVENTS)) + vty_out (vty, " BGP events debugging is on%s", VTY_NEWLINE); + if (BGP_DEBUG (keepalive, KEEPALIVE)) + vty_out (vty, " BGP keepalives debugging is on%s", VTY_NEWLINE); + if (BGP_DEBUG (update, UPDATE_IN) && BGP_DEBUG (update, UPDATE_OUT)) + vty_out (vty, " BGP updates debugging is on%s", VTY_NEWLINE); + else if (BGP_DEBUG (update, UPDATE_IN)) + vty_out (vty, " BGP updates debugging is on (inbound)%s", VTY_NEWLINE); + else if (BGP_DEBUG (update, UPDATE_OUT)) + vty_out (vty, " BGP updates debugging is on (outbound)%s", VTY_NEWLINE); + if (BGP_DEBUG (fsm, FSM)) + vty_out (vty, " BGP fsm debugging is on%s", VTY_NEWLINE); + if (BGP_DEBUG (filter, FILTER)) + vty_out (vty, " BGP filter debugging is on%s", VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + return CMD_SUCCESS; +} + +int +bgp_config_write_debug (struct vty *vty) +{ + int write = 0; + + if (CONF_BGP_DEBUG (normal, NORMAL)) + { + vty_out (vty, "debug bgp%s", VTY_NEWLINE); + write++; + } + + if (CONF_BGP_DEBUG (events, EVENTS)) + { + vty_out (vty, "debug bgp events%s", VTY_NEWLINE); + write++; + } + + if (CONF_BGP_DEBUG (keepalive, KEEPALIVE)) + { + vty_out (vty, "debug bgp keepalives%s", VTY_NEWLINE); + write++; + } + + if (CONF_BGP_DEBUG (update, UPDATE_IN) && CONF_BGP_DEBUG (update, UPDATE_OUT)) + { + vty_out (vty, "debug bgp updates%s", VTY_NEWLINE); + write++; + } + else if (CONF_BGP_DEBUG (update, UPDATE_IN)) + { + vty_out (vty, "debug bgp updates in%s", VTY_NEWLINE); + write++; + } + else if (CONF_BGP_DEBUG (update, UPDATE_OUT)) + { + vty_out (vty, "debug bgp updates out%s", VTY_NEWLINE); + write++; + } + + if (CONF_BGP_DEBUG (fsm, FSM)) + { + vty_out (vty, "debug bgp fsm%s", VTY_NEWLINE); + write++; + } + + if (CONF_BGP_DEBUG (filter, FILTER)) + { + vty_out (vty, "debug bgp filters%s", VTY_NEWLINE); + write++; + } + + return write; +} + +struct cmd_node debug_node = + { + DEBUG_NODE, + "", + 1 + }; + +void +bgp_debug_init () +{ + install_node (&debug_node, bgp_config_write_debug); + + install_element (ENABLE_NODE, &show_debugging_bgp_cmd); + + install_element (ENABLE_NODE, &debug_bgp_fsm_cmd); + install_element (CONFIG_NODE, &debug_bgp_fsm_cmd); + install_element (ENABLE_NODE, &debug_bgp_events_cmd); + install_element (CONFIG_NODE, &debug_bgp_events_cmd); + install_element (ENABLE_NODE, &debug_bgp_filter_cmd); + install_element (CONFIG_NODE, &debug_bgp_filter_cmd); + install_element (ENABLE_NODE, &debug_bgp_keepalive_cmd); + install_element (CONFIG_NODE, &debug_bgp_keepalive_cmd); + install_element (ENABLE_NODE, &debug_bgp_update_cmd); + install_element (CONFIG_NODE, &debug_bgp_update_cmd); + install_element (ENABLE_NODE, &debug_bgp_update_direct_cmd); + install_element (CONFIG_NODE, &debug_bgp_update_direct_cmd); + install_element (ENABLE_NODE, &debug_bgp_normal_cmd); + install_element (CONFIG_NODE, &debug_bgp_normal_cmd); + + install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd); + install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_events_cmd); + install_element (ENABLE_NODE, &undebug_bgp_events_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_events_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_filter_cmd); + install_element (ENABLE_NODE, &undebug_bgp_filter_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_keepalive_cmd); + install_element (ENABLE_NODE, &undebug_bgp_keepalive_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_keepalive_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_update_cmd); + install_element (ENABLE_NODE, &undebug_bgp_update_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_update_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_normal_cmd); + install_element (ENABLE_NODE, &undebug_bgp_normal_cmd); + install_element (CONFIG_NODE, &no_debug_bgp_normal_cmd); + install_element (ENABLE_NODE, &no_debug_bgp_all_cmd); + install_element (ENABLE_NODE, &undebug_bgp_all_cmd); +} diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h new file mode 100644 index 0000000..14a8c5f --- /dev/null +++ b/bgpd/bgp_debug.h @@ -0,0 +1,113 @@ +/* BGP message debug header. + Copyright (C) 1996, 97, 98 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* sort of packet direction */ +#define DUMP_ON 1 +#define DUMP_SEND 2 +#define DUMP_RECV 4 + +/* for dump_update */ +#define DUMP_WITHDRAW 8 +#define DUMP_NLRI 16 + +/* dump detail */ +#define DUMP_DETAIL 32 + +extern int dump_open; +extern int dump_update; +extern int dump_keepalive; +extern int dump_notify; + +extern int Debug_Event; +extern int Debug_Keepalive; +extern int Debug_Update; +extern int Debug_Radix; + +#define NLRI 1 +#define WITHDRAW 2 +#define NO_OPT 3 +#define SEND 4 +#define RECV 5 +#define DETAIL 6 + +/* Prototypes. */ +void bgp_debug_init (); +void bgp_packet_dump (struct stream *); + +int debug (unsigned int option); + +extern unsigned long conf_bgp_debug_fsm; +extern unsigned long conf_bgp_debug_events; +extern unsigned long conf_bgp_debug_packet; +extern unsigned long conf_bgp_debug_filter; +extern unsigned long conf_bgp_debug_keepalive; +extern unsigned long conf_bgp_debug_update; +extern unsigned long conf_bgp_debug_normal; + +extern unsigned long term_bgp_debug_fsm; +extern unsigned long term_bgp_debug_events; +extern unsigned long term_bgp_debug_packet; +extern unsigned long term_bgp_debug_filter; +extern unsigned long term_bgp_debug_keepalive; +extern unsigned long term_bgp_debug_update; +extern unsigned long term_bgp_debug_normal; + +#define BGP_DEBUG_FSM 0x01 +#define BGP_DEBUG_EVENTS 0x01 +#define BGP_DEBUG_PACKET 0x01 +#define BGP_DEBUG_FILTER 0x01 +#define BGP_DEBUG_KEEPALIVE 0x01 +#define BGP_DEBUG_UPDATE_IN 0x01 +#define BGP_DEBUG_UPDATE_OUT 0x02 +#define BGP_DEBUG_NORMAL 0x01 + +#define BGP_DEBUG_PACKET_SEND 0x01 +#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02 + +#define BGP_DEBUG_PACKET_RECV 0x01 +#define BGP_DEBUG_PACKET_RECV_DETAIL 0x02 + +#define CONF_DEBUG_ON(a, b) (conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b)) +#define CONF_DEBUG_OFF(a, b) (conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b)) + +#define TERM_DEBUG_ON(a, b) (term_bgp_debug_ ## a |= (BGP_DEBUG_ ## b)) +#define TERM_DEBUG_OFF(a, b) (term_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b)) + +#define DEBUG_ON(a, b) \ + do { \ + CONF_DEBUG_ON(a, b); \ + TERM_DEBUG_ON(a, b); \ + } while (0) +#define DEBUG_OFF(a, b) \ + do { \ + CONF_DEBUG_OFF(a, b); \ + TERM_DEBUG_OFF(a, b); \ + } while (0) + +#define BGP_DEBUG(a, b) (term_bgp_debug_ ## a & BGP_DEBUG_ ## b) +#define CONF_BGP_DEBUG(a, b) (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b) + +extern char *bgp_type_str[]; + +int bgp_dump_attr (struct peer *, struct attr *, char *, size_t); +void bgp_notify_print (struct peer *, struct bgp_notify *, char *); + +extern struct message bgp_status_msg[]; +extern int bgp_status_msg_max; diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c new file mode 100644 index 0000000..fca51ed --- /dev/null +++ b/bgpd/bgp_dump.c @@ -0,0 +1,741 @@ +/* BGP-4 dump routine + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "log.h" +#include "stream.h" +#include "sockunion.h" +#include "command.h" +#include "prefix.h" +#include "thread.h" +#include "bgpd/bgp_table.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_dump.h" + +enum bgp_dump_type +{ + BGP_DUMP_ALL, + BGP_DUMP_UPDATES, + BGP_DUMP_ROUTES +}; + +enum MRT_MSG_TYPES { + MSG_NULL, + MSG_START, /* sender is starting up */ + MSG_DIE, /* receiver should shut down */ + MSG_I_AM_DEAD, /* sender is shutting down */ + MSG_PEER_DOWN, /* sender's peer is down */ + MSG_PROTOCOL_BGP, /* msg is a BGP packet */ + MSG_PROTOCOL_RIP, /* msg is a RIP packet */ + MSG_PROTOCOL_IDRP, /* msg is an IDRP packet */ + MSG_PROTOCOL_RIPNG, /* msg is a RIPNG packet */ + MSG_PROTOCOL_BGP4PLUS, /* msg is a BGP4+ packet */ + MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */ + MSG_PROTOCOL_OSPF, /* msg is an OSPF packet */ + MSG_TABLE_DUMP /* routing table dump */ +}; + +struct bgp_dump +{ + enum bgp_dump_type type; + + char *filename; + + FILE *fp; + + unsigned int interval; + + char *interval_str; + + struct thread *t_interval; +}; + +/* BGP packet dump output buffer. */ +struct stream *bgp_dump_obuf; + +/* BGP dump strucuture for 'dump bgp all' */ +struct bgp_dump bgp_dump_all; + +/* BGP dump structure for 'dump bgp updates' */ +struct bgp_dump bgp_dump_updates; + +/* BGP dump structure for 'dump bgp routes' */ +struct bgp_dump bgp_dump_routes; + +/* Dump whole BGP table is very heavy process. */ +struct thread *t_bgp_dump_routes; + +/* Some define for BGP packet dump. */ +FILE * +bgp_dump_open_file (struct bgp_dump *bgp_dump) +{ + int ret; + time_t clock; + struct tm *tm; + char fullpath[MAXPATHLEN]; + char realpath[MAXPATHLEN]; + + time (&clock); + tm = localtime (&clock); + + if (bgp_dump->filename[0] != DIRECTORY_SEP) + { + sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename); + ret = strftime (realpath, MAXPATHLEN, fullpath, tm); + } + else + ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm); + + if (ret == 0) + { + zlog_warn ("bgp_dump_open_file: strftime error"); + return NULL; + } + + if (bgp_dump->fp) + fclose (bgp_dump->fp); + + + bgp_dump->fp = fopen (realpath, "w"); + + if (bgp_dump->fp == NULL) + return NULL; + + return bgp_dump->fp; +} + +int +bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval) +{ + int bgp_dump_interval_func (struct thread *); + + bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func, + bgp_dump, interval); + return 0; +} + +/* Dump common header. */ +void +bgp_dump_header (struct stream *obuf, int type, int subtype) +{ + time_t now; + + /* Set header. */ + time (&now); + + /* Put dump packet header. */ + stream_putl (obuf, now); + stream_putw (obuf, type); + stream_putw (obuf, subtype); + + stream_putl (obuf, 0); /* len */ +} + +void +bgp_dump_set_size (struct stream *s, int type) +{ + stream_putl_at (s, 8, stream_get_putp (s) - BGP_DUMP_HEADER_SIZE); +} + +void +bgp_dump_routes_entry (struct prefix *p, struct bgp_info *info, int afi, + int type, unsigned int seq) +{ + struct stream *obuf; + struct attr *attr; + struct peer *peer; + int plen; + int safi = 0; + + /* Make dump stream. */ + obuf = bgp_dump_obuf; + stream_reset (obuf); + + attr = info->attr; + peer = info->peer; + + /* We support MRT's old format. */ + if (type == MSG_TABLE_DUMP) + { + bgp_dump_header (obuf, MSG_TABLE_DUMP, afi); + stream_putw (obuf, 0); /* View # */ + stream_putw (obuf, seq); /* Sequence number. */ + } + else + { + bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY); + + stream_putl (obuf, info->uptime); /* Time Last Change */ + stream_putw (obuf, afi); /* Address Family */ + stream_putc (obuf, safi); /* SAFI */ + } + + if (afi == AFI_IP) + { + if (type == MSG_TABLE_DUMP) + { + /* Prefix */ + stream_put_in_addr (obuf, &p->u.prefix4); + stream_putc (obuf, p->prefixlen); + + /* Status */ + stream_putc (obuf, 1); + + /* Originated */ + stream_putl (obuf, info->uptime); + + /* Peer's IP address */ + stream_put_in_addr (obuf, &peer->su.sin.sin_addr); + + /* Peer's AS number. */ + stream_putw (obuf, peer->as); + + /* Dump attribute. */ + bgp_dump_routes_attr (obuf, attr); + } + else + { + /* Next-Hop-Len */ + stream_putc (obuf, IPV4_MAX_BYTELEN); + stream_put_in_addr (obuf, &attr->nexthop); + stream_putc (obuf, p->prefixlen); + plen = PSIZE (p->prefixlen); + stream_put (obuf, &p->u.prefix4, plen); + bgp_dump_routes_attr (obuf, attr); + } + } +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + { + if (type == MSG_TABLE_DUMP) + { + /* Prefix */ + stream_write (obuf, (u_char *)&p->u.prefix6, IPV6_MAX_BYTELEN); + stream_putc (obuf, p->prefixlen); + + /* Status */ + stream_putc (obuf, 1); + + /* Originated */ + stream_putl (obuf, info->uptime); + + /* Peer's IP address */ + stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr, + IPV6_MAX_BYTELEN); + + /* Peer's AS number. */ + stream_putw (obuf, peer->as); + + /* Dump attribute. */ + bgp_dump_routes_attr (obuf, attr); + } + else + { + ; + } + } +#endif /* HAVE_IPV6 */ + + /* Set length. */ + bgp_dump_set_size (obuf, type); + + fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_routes.fp); + fflush (bgp_dump_routes.fp); +} + +/* Runs under child process. */ +void +bgp_dump_routes_func (int afi) +{ + struct stream *obuf; + struct bgp_node *rn; + struct bgp_info *info; + struct bgp *bgp; + struct bgp_table *table; + unsigned int seq = 0; + + obuf = bgp_dump_obuf; + + bgp = bgp_get_default (); + if (!bgp) + return; + + if (bgp_dump_routes.fp == NULL) + return; + + /* Walk down each BGP route. */ + table = bgp->rib[afi][SAFI_UNICAST]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + for (info = rn->info; info; info = info->next) + bgp_dump_routes_entry (&rn->p, info, afi, MSG_TABLE_DUMP, seq++); +} + +int +bgp_dump_interval_func (struct thread *t) +{ + struct bgp_dump *bgp_dump; + + bgp_dump = THREAD_ARG (t); + bgp_dump->t_interval = NULL; + + if (bgp_dump_open_file (bgp_dump) == NULL) + return 0; + + /* In case of bgp_dump_routes, we need special route dump function. */ + if (bgp_dump->type == BGP_DUMP_ROUTES) + { + bgp_dump_routes_func (AFI_IP); + bgp_dump_routes_func (AFI_IP6); + } + + bgp_dump_interval_add (bgp_dump, bgp_dump->interval); + + return 0; +} + +/* Dump common information. */ +void +bgp_dump_common (struct stream *obuf, struct peer *peer) +{ + char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + /* Source AS number and Destination AS number. */ + stream_putw (obuf, peer->as); + stream_putw (obuf, peer->local_as); + + if (peer->afc[AFI_IP][SAFI_UNICAST]) + { + stream_putw (obuf, peer->ifindex); + stream_putw (obuf, AFI_IP); + + stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN); + + if (peer->su_local) + stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN); + else + stream_put (obuf, empty, IPV4_MAX_BYTELEN); + } +#ifdef HAVE_IPV6 + else if (peer->afc[AFI_IP6][SAFI_UNICAST]) + { + /* Interface Index and Address family. */ + stream_putw (obuf, peer->ifindex); + stream_putw (obuf, AFI_IP6); + + /* Source IP Address and Destination IP Address. */ + stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN); + + if (peer->su_local) + stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN); + else + stream_put (obuf, empty, IPV6_MAX_BYTELEN); + } +#endif /* HAVE_IPV6 */ +} + +/* Dump BGP status change. */ +void +bgp_dump_state (struct peer *peer, int status_old, int status_new) +{ + struct stream *obuf; + + /* If dump file pointer is disabled return immediately. */ + if (bgp_dump_all.fp == NULL) + return; + + /* Make dump stream. */ + obuf = bgp_dump_obuf; + stream_reset (obuf); + + bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE); + bgp_dump_common (obuf, peer); + + stream_putw (obuf, status_old); + stream_putw (obuf, status_new); + + /* Set length. */ + bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP); + + /* Write to the stream. */ + fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_all.fp); + fflush (bgp_dump_all.fp); +} + +void +bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer, + struct stream *packet) +{ + struct stream *obuf; + + /* If dump file pointer is disabled return immediately. */ + if (bgp_dump->fp == NULL) + return; + + /* Make dump stream. */ + obuf = bgp_dump_obuf; + stream_reset (obuf); + + /* Dump header and common part. */ + bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE); + bgp_dump_common (obuf, peer); + + /* Packet contents. */ + stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet)); + + /* Set length. */ + bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP); + + /* Write to the stream. */ + fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump->fp); + fflush (bgp_dump->fp); +} + +/* Called from bgp_packet.c when BGP packet is received. */ +void +bgp_dump_packet (struct peer *peer, int type, struct stream *packet) +{ + /* bgp_dump_all. */ + bgp_dump_packet_func (&bgp_dump_all, peer, packet); + + /* bgp_dump_updates. */ + if (type == BGP_MSG_UPDATE) + bgp_dump_packet_func (&bgp_dump_updates, peer, packet); +} + +unsigned int +bgp_dump_parse_time (char *str) +{ + int i; + int len; + int seen_h; + int seen_m; + int time; + unsigned int total; + + time = 0; + total = 0; + seen_h = 0; + seen_m = 0; + len = strlen (str); + + for (i = 0; i < len; i++) + { + if (isdigit ((int) str[i])) + { + time *= 10; + time += str[i] - '0'; + } + else if (str[i] == 'H' || str[i] == 'h') + { + if (seen_h) + return 0; + if (seen_m) + return 0; + total += time * 60 *60; + time = 0; + seen_h = 1; + } + else if (str[i] == 'M' || str[i] == 'm') + { + if (seen_m) + return 0; + total += time * 60; + time = 0; + seen_h = 1; + } + else + return 0; + } + return total + time; +} + +int +bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, int type, + char *path, char *interval_str) +{ + if (interval_str) + { + unsigned int interval; + + /* Check interval string. */ + interval = bgp_dump_parse_time (interval_str); + if (interval == 0) + { + vty_out (vty, "Malformed interval string%s", VTY_NEWLINE); + return CMD_WARNING; + } + /* Set interval. */ + bgp_dump->interval = interval; + if (bgp_dump->interval_str) + free (bgp_dump->interval_str); + bgp_dump->interval_str = strdup (interval_str); + + /* Create interval thread. */ + bgp_dump_interval_add (bgp_dump, interval); + } + + /* Set type. */ + bgp_dump->type = type; + + /* Set file name. */ + if (bgp_dump->filename) + free (bgp_dump->filename); + bgp_dump->filename = strdup (path); + + /* This should be called when interval is expired. */ + bgp_dump_open_file (bgp_dump); + + return CMD_SUCCESS; +} + +int +bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump) +{ + /* Set file name. */ + if (bgp_dump->filename) + { + free (bgp_dump->filename); + bgp_dump->filename = NULL; + } + + /* This should be called when interval is expired. */ + if (bgp_dump->fp) + { + fclose (bgp_dump->fp); + bgp_dump->fp = NULL; + } + + /* Create interval thread. */ + if (bgp_dump->t_interval) + { + thread_cancel (bgp_dump->t_interval); + bgp_dump->t_interval = NULL; + } + + bgp_dump->interval = 0; + + if (bgp_dump->interval_str) + { + free (bgp_dump->interval_str); + bgp_dump->interval_str = NULL; + } + + + return CMD_SUCCESS; +} + +DEFUN (dump_bgp_all, + dump_bgp_all_cmd, + "dump bgp all PATH", + "Dump packet\n" + "BGP packet dump\n" + "Dump all BGP packets\n" + "Output filename\n") +{ + return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL); +} + +DEFUN (dump_bgp_all_interval, + dump_bgp_all_interval_cmd, + "dump bgp all PATH INTERVAL", + "Dump packet\n" + "BGP packet dump\n" + "Dump all BGP packets\n" + "Output filename\n" + "Interval of output\n") +{ + return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]); +} + +DEFUN (no_dump_bgp_all, + no_dump_bgp_all_cmd, + "no dump bgp all [PATH] [INTERVAL]", + NO_STR + "Dump packet\n" + "BGP packet dump\n" + "Dump all BGP packets\n") +{ + return bgp_dump_unset (vty, &bgp_dump_all); +} + +DEFUN (dump_bgp_updates, + dump_bgp_updates_cmd, + "dump bgp updates PATH", + "Dump packet\n" + "BGP packet dump\n" + "Dump BGP updates only\n" + "Output filename\n") +{ + return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL); +} + +DEFUN (dump_bgp_updates_interval, + dump_bgp_updates_interval_cmd, + "dump bgp updates PATH INTERVAL", + "Dump packet\n" + "BGP packet dump\n" + "Dump BGP updates only\n" + "Output filename\n" + "Interval of output\n") +{ + return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]); +} + +DEFUN (no_dump_bgp_updates, + no_dump_bgp_updates_cmd, + "no dump bgp updates [PATH] [INTERVAL]", + NO_STR + "Dump packet\n" + "BGP packet dump\n" + "Dump BGP updates only\n") +{ + return bgp_dump_unset (vty, &bgp_dump_updates); +} + +DEFUN (dump_bgp_routes, + dump_bgp_routes_cmd, + "dump bgp routes-mrt PATH", + "Dump packet\n" + "BGP packet dump\n" + "Dump whole BGP routing table\n" + "Output filename\n") +{ + return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL); +} + +DEFUN (dump_bgp_routes_interval, + dump_bgp_routes_interval_cmd, + "dump bgp routes-mrt PATH INTERVAL", + "Dump packet\n" + "BGP packet dump\n" + "Dump whole BGP routing table\n" + "Output filename\n" + "Interval of output\n") +{ + return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]); +} + +DEFUN (no_dump_bgp_routes, + no_dump_bgp_routes_cmd, + "no dump bgp routes-mrt [PATH] [INTERVAL]", + NO_STR + "Dump packet\n" + "BGP packet dump\n" + "Dump whole BGP routing table\n") +{ + return bgp_dump_unset (vty, &bgp_dump_routes); +} + +/* BGP node structure. */ +struct cmd_node bgp_dump_node = +{ + DUMP_NODE, + "", +}; + +#if 0 +char * +config_time2str (unsigned int interval) +{ + static char buf[BUFSIZ]; + + buf[0] = '\0'; + + if (interval / 3600) + { + sprintf (buf, "%dh", interval / 3600); + interval %= 3600; + } + if (interval / 60) + { + sprintf (buf + strlen (buf), "%dm", interval /60); + interval %= 60; + } + if (interval) + { + sprintf (buf + strlen (buf), "%d", interval); + } + return buf; +} +#endif + +int +config_write_bgp_dump (struct vty *vty) +{ + if (bgp_dump_all.filename) + { + if (bgp_dump_all.interval_str) + vty_out (vty, "dump bgp all %s %s%s", + bgp_dump_all.filename, bgp_dump_all.interval_str, + VTY_NEWLINE); + else + vty_out (vty, "dump bgp all %s%s", + bgp_dump_all.filename, VTY_NEWLINE); + } + if (bgp_dump_updates.filename) + { + if (bgp_dump_updates.interval_str) + vty_out (vty, "dump bgp updates %s %s%s", + bgp_dump_updates.filename, bgp_dump_updates.interval_str, + VTY_NEWLINE); + else + vty_out (vty, "dump bgp updates %s%s", + bgp_dump_updates.filename, VTY_NEWLINE); + } + if (bgp_dump_routes.filename) + { + if (bgp_dump_routes.interval_str) + vty_out (vty, "dump bgp routes-mrt %s %s%s", + bgp_dump_routes.filename, bgp_dump_routes.interval_str, + VTY_NEWLINE); + else + vty_out (vty, "dump bgp routes-mrt %s%s", + bgp_dump_routes.filename, VTY_NEWLINE); + } + return 0; +} + +/* Initialize BGP packet dump functionality. */ +void +bgp_dump_init () +{ + memset (&bgp_dump_all, 0, sizeof (struct bgp_dump)); + memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump)); + memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump)); + + bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_HEADER_SIZE); + + install_node (&bgp_dump_node, config_write_bgp_dump); + + install_element (CONFIG_NODE, &dump_bgp_all_cmd); + install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd); + install_element (CONFIG_NODE, &no_dump_bgp_all_cmd); + install_element (CONFIG_NODE, &dump_bgp_updates_cmd); + install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd); + install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd); + install_element (CONFIG_NODE, &dump_bgp_routes_cmd); + install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd); + install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd); +} diff --git a/bgpd/bgp_dump.h b/bgpd/bgp_dump.h new file mode 100644 index 0000000..d2f96a9 --- /dev/null +++ b/bgpd/bgp_dump.h @@ -0,0 +1,34 @@ +/* BGP dump routine. + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* MRT compatible packet dump values. */ +/* type value */ +#define MSG_PROTOCOL_BGP4MP 16 +/* subtype value */ +#define BGP4MP_STATE_CHANGE 0 +#define BGP4MP_MESSAGE 1 +#define BGP4MP_ENTRY 2 +#define BGP4MP_SNAPSHOT 3 + +#define BGP_DUMP_HEADER_SIZE 12 + +void bgp_dump_init (); +void bgp_dump_state (struct peer *, int, int); +void bgp_dump_packet (struct peer *, int, struct stream *); diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c new file mode 100644 index 0000000..dfb4e79 --- /dev/null +++ b/bgpd/bgp_ecommunity.c @@ -0,0 +1,843 @@ +/* BGP Extended Communities Attribute + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "hash.h" +#include "memory.h" +#include "prefix.h" +#include "command.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_ecommunity.h" + +/* Hash of community attribute. */ +struct hash *ecomhash; + +/* Allocate a new ecommunities. */ +struct ecommunity * +ecommunity_new () +{ + return (struct ecommunity *) XCALLOC (MTYPE_ECOMMUNITY, + sizeof (struct ecommunity)); +} + +/* Allocate ecommunities. */ +void +ecommunity_free (struct ecommunity *ecom) +{ + if (ecom->val) + XFREE (MTYPE_ECOMMUNITY_VAL, ecom->val); + if (ecom->str) + XFREE (MTYPE_ECOMMUNITY_STR, ecom->str); + XFREE (MTYPE_ECOMMUNITY, ecom); +} + +/* Add a new Extended Communities value to Extended Communities + Attribute structure. When the value is already exists in the + structure, we don't add the value. Newly added value is sorted by + numerical order. When the value is added to the structure return 1 + else return 0. */ +static int +ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval) +{ + u_char *p; + int ret; + int c; + + /* When this is fist value, just add it. */ + if (ecom->val == NULL) + { + ecom->size++; + ecom->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom_length (ecom)); + memcpy (ecom->val, eval->val, ECOMMUNITY_SIZE); + return 1; + } + + /* If the value already exists in the structure return 0. */ + c = 0; + for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) + { + ret = memcmp (p, eval->val, ECOMMUNITY_SIZE); + if (ret == 0) + return 0; + if (ret > 0) + break; + } + + /* Add the value to the structure with numerical sorting. */ + ecom->size++; + ecom->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length (ecom)); + + memmove (ecom->val + (c + 1) * ECOMMUNITY_SIZE, + ecom->val + c * ECOMMUNITY_SIZE, + (ecom->size - 1 - c) * ECOMMUNITY_SIZE); + memcpy (ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE); + + return 1; +} + +/* This function takes pointer to Extended Communites strucutre then + create a new Extended Communities structure by uniq and sort each + Exteneded Communities value. */ +struct ecommunity * +ecommunity_uniq_sort (struct ecommunity *ecom) +{ + int i; + struct ecommunity *new; + struct ecommunity_val *eval; + + if (! ecom) + return NULL; + + new = ecommunity_new ();; + + for (i = 0; i < ecom->size; i++) + { + eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE)); + ecommunity_add_val (new, eval); + } + return new; +} + +/* Parse Extended Communites Attribute in BGP packet. */ +struct ecommunity * +ecommunity_parse (char *pnt, u_short length) +{ + struct ecommunity tmp; + struct ecommunity *new; + + /* Length check. */ + if (length % ECOMMUNITY_SIZE) + return NULL; + + /* Prepare tmporary structure for making a new Extended Communities + Attribute. */ + tmp.size = length / ECOMMUNITY_SIZE; + tmp.val = pnt; + + /* Create a new Extended Communities Attribute by uniq and sort each + Extended Communities value */ + new = ecommunity_uniq_sort (&tmp); + + return ecommunity_intern (new); +} + +/* Duplicate the Extended Communities Attribute structure. */ +struct ecommunity * +ecommunity_dup (struct ecommunity *ecom) +{ + struct ecommunity *new; + + new = XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity)); + new->size = ecom->size; + if (new->size) + { + new->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE); + memcpy (new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE); + } + else + new->val = NULL; + return new; +} + +/* Retrun string representation of communities attribute. */ +char * +ecommunity_str (struct ecommunity *ecom) +{ + if (! ecom->str) + ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY); + return ecom->str; +} + +/* Merge two Extended Communities Attribute structure. */ +struct ecommunity * +ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2) +{ + if (ecom1->val) + ecom1->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom1->val, + (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE); + else + ecom1->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, + (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE); + + memcpy (ecom1->val + (ecom1->size * ECOMMUNITY_SIZE), + ecom2->val, ecom2->size * ECOMMUNITY_SIZE); + ecom1->size += ecom2->size; + + return ecom1; +} + +/* Intern Extended Communities Attribute. */ +struct ecommunity * +ecommunity_intern (struct ecommunity *ecom) +{ + struct ecommunity *find; + + assert (ecom->refcnt == 0); + + find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern); + + if (find != ecom) + ecommunity_free (ecom); + + find->refcnt++; + + if (! find->str) + find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY); + + return find; +} + +/* Unintern Extended Communities Attribute. */ +void +ecommunity_unintern (struct ecommunity *ecom) +{ + struct ecommunity *ret; + + if (ecom->refcnt) + ecom->refcnt--; + + /* Pull off from hash. */ + if (ecom->refcnt == 0) + { + /* Extended community must be in the hash. */ + ret = (struct ecommunity *) hash_release (ecomhash, ecom); + assert (ret != NULL); + + ecommunity_free (ecom); + } +} + +/* Utinity function to make hash key. */ +unsigned int +ecommunity_hash_make (struct ecommunity *ecom) +{ + int c; + unsigned int key; + unsigned char *pnt; + + key = 0; + pnt = ecom->val; + + for (c = 0; c < ecom->size * ECOMMUNITY_SIZE; c++) + key += pnt[c]; + + return key; +} + +/* Compare two Extended Communities Attribute structure. */ +int +ecommunity_cmp (struct ecommunity *ecom1, struct ecommunity *ecom2) +{ + if (ecom1->size == ecom2->size + && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0) + return 1; + return 0; +} + +/* Initialize Extended Comminities related hash. */ +void +ecommunity_init () +{ + ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp); +} + +/* Extended Communities token enum. */ +enum ecommunity_token +{ + ecommunity_token_rt, + ecommunity_token_soo, + ecommunity_token_val, + ecommunity_token_unknown +}; + +/* Get next Extended Communities token from the string. */ +char * +ecommunity_gettoken (char *str, struct ecommunity_val *eval, + enum ecommunity_token *token) +{ + int ret; + int dot = 0; + int digit = 0; + int separator = 0; + u_int32_t val_low = 0; + u_int32_t val_high = 0; + char *p = str; + struct in_addr ip; + char ipstr[INET_ADDRSTRLEN + 1]; + + /* Skip white space. */ + while (isspace ((int) *p)) + { + p++; + str++; + } + + /* Check the end of the line. */ + if (*p == '\0') + return NULL; + + /* "rt" and "soo" keyword parse. */ + if (! isdigit ((int) *p)) + { + /* "rt" match check. */ + if (tolower ((int) *p) == 'r') + { + p++; + if (tolower ((int) *p) == 't') + { + p++; + *token = ecommunity_token_rt; + return p; + } + if (isspace ((int) *p) || *p == '\0') + { + *token = ecommunity_token_rt; + return p; + } + goto error; + } + /* "soo" match check. */ + else if (tolower ((int) *p) == 's') + { + p++; + if (tolower ((int) *p) == 'o') + { + p++; + if (tolower ((int) *p) == 'o') + { + p++; + *token = ecommunity_token_soo; + return p; + } + if (isspace ((int) *p) || *p == '\0') + { + *token = ecommunity_token_soo; + return p; + } + goto error; + } + if (isspace ((int) *p) || *p == '\0') + { + *token = ecommunity_token_soo; + return p; + } + goto error; + } + goto error; + } + + while (isdigit ((int) *p) || *p == ':' || *p == '.') + { + if (*p == ':') + { + if (separator) + goto error; + + separator = 1; + digit = 0; + + if (dot) + { + if ((p - str) > INET_ADDRSTRLEN) + goto error; + + memset (ipstr, 0, INET_ADDRSTRLEN + 1); + memcpy (ipstr, str, p - str); + + ret = inet_aton (ipstr, &ip); + if (ret == 0) + goto error; + } + else + val_high = val_low; + + val_low = 0; + } + else if (*p == '.') + { + if (separator) + goto error; + dot++; + if (dot > 4) + goto error; + } + else + { + digit = 1; + val_low *= 10; + val_low += (*p - '0'); + } + p++; + } + + /* Low digit part must be there. */ + if (! digit || ! separator) + goto error; + + /* Encode result into routing distinguisher. */ + if (dot) + { + eval->val[0] = ECOMMUNITY_ENCODE_IP; + eval->val[1] = 0; + memcpy (&eval->val[2], &ip, sizeof (struct in_addr)); + eval->val[6] = (val_low >> 8) & 0xff; + eval->val[7] = val_low & 0xff; + } + else + { + eval->val[0] = ECOMMUNITY_ENCODE_AS; + eval->val[1] = 0; + eval->val[2] = (val_high >>8) & 0xff; + eval->val[3] = val_high & 0xff; + eval->val[4] = (val_low >>24) & 0xff; + eval->val[5] = (val_low >>16) & 0xff; + eval->val[6] = (val_low >>8) & 0xff; + eval->val[7] = val_low & 0xff; + } + *token = ecommunity_token_val; + return p; + + error: + *token = ecommunity_token_unknown; + return p; +} + +/* Convert string to extended community attribute. + + When type is already known, please specify both str and type. str + should not include keyword such as "rt" and "soo". Type is + ECOMMUNITY_TYPE_ROUTE_TARGET or ECOMMUNITY_TYPE_SITE_ORIGIN. + keyword_included should be zero. + + For example route-map's "set extcommunity" command case: + + "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3" + type = ECOMMUNITY_TYPE_ROUTE_TARGET + keyword_included = 0 + + "soo 100:1" -> str = "100:1" + type = ECOMMUNITY_TYPE_SITE_ORIGIN + keyword_included = 0 + + When string includes keyword for each extended community value. + Please specify keyword_included as non-zero value. + + For example standard extcommunity-list case: + + "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1" + type = 0 + keyword_include = 1 +*/ +struct ecommunity * +ecommunity_str2com (char *str, int type, int keyword_included) +{ + struct ecommunity *ecom = NULL; + enum ecommunity_token token; + struct ecommunity_val eval; + int keyword = 0; + + while ((str = ecommunity_gettoken (str, &eval, &token))) + { + switch (token) + { + case ecommunity_token_rt: + case ecommunity_token_soo: + if (! keyword_included || keyword) + { + if (ecom) + ecommunity_free (ecom); + return NULL; + } + keyword = 1; + + if (token == ecommunity_token_rt) + { + type = ECOMMUNITY_TYPE_ROUTE_TARGET; + } + if (token == ecommunity_token_soo) + { + type = ECOMMUNITY_TYPE_SITE_ORIGIN; + } + break; + case ecommunity_token_val: + if (keyword_included) + { + if (! keyword) + { + if (ecom) + ecommunity_free (ecom); + return NULL; + } + keyword = 0; + } + if (ecom == NULL) + ecom = ecommunity_new (); + eval.val[1] = type; + ecommunity_add_val (ecom, &eval); + break; + case ecommunity_token_unknown: + default: + if (ecom) + ecommunity_free (ecom); + return NULL; + break; + } + } + return ecom; +} + +struct ecommunity * +ecommunity_cost_str2com (char *str, u_char poi) +{ + struct ecommunity *ecom = NULL; + struct ecommunity_cost ecost; + u_int32_t id = 0; + u_int32_t val = 0; + char *p = str; + + while (isspace ((int) *p)) + p++; + + while (isdigit ((int) *p)) + { + id *= 10; + id += (*p - '0'); + p++; + } + + while (isspace ((int) *p)) + p++; + + while (isdigit ((int) *p)) + { + val *= 10; + val += (*p - '0'); + p++; + } + + ecost.type = ntohs (ECOMMUNITY_COST_COMMUNITY); + ecost.poi = poi; + ecost.id = id; + ecost.val = ntohl (val); + + ecom = ecommunity_new (); + ecommunity_add_val (ecom, (struct ecommunity_val *)&ecost); + + return ecom; +} + +/* Convert extended community attribute to string. + + Due to historical reason of industry standard implementation, there + are three types of format. + + route-map set extcommunity format + "rt 100:1 100:2" + "soo 100:3" + + extcommunity-list + "rt 100:1 rt 100:2 soo 100:3" + + "show ip bgp" and extcommunity-list regular expression matching + "RT:100:1 RT:100:2 SoO:100:3" + + For each formath please use below definition for format: + + ECOMMUNITY_FORMAT_CONFIG + ECOMMUNITY_FORMAT_DISPLAY +*/ + + +char * +ecommunity_cost_poi_print (u_char poi) +{ + if (poi == ECOMMUNITY_COST_POI_IGP) + return "igp"; + + return "?"; +} + +char * +ecommunity_ecom2str (struct ecommunity *ecom, int format) +{ + int i; + u_char *pnt; + int encode = 0; + int encode_check = 0; + int type = 0; +#define ECOMMUNITY_STR_DEFAULT_LEN 26 + int str_size; + int str_pnt; + u_char *str_buf; + char *prefix; + int len = 0; + int first = 1; + + /* For parse Extended Community attribute tupple. */ + struct ecommunity_as + { + as_t as; + u_int32_t val; + } eas; + + struct ecommunity_ip + { + struct in_addr ip; + u_int16_t val; + } eip; + + if (ecom->size == 0) + { + str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1); + str_buf[0] = '\0'; + return str_buf; + } + + /* Prepare buffer. */ + str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1); + str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1; + str_pnt = 0; + + for (i = 0; i < ecom->size; i++) + { + /* Make it sure size is enough. */ + while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size) + { + str_size *= 2; + str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size); + } + + /* Space between each value. */ + if (! first) + str_buf[str_pnt++] = ' '; + + pnt = ecom->val + (i * 8); + + /* High-order octet of type. */ + encode = *pnt++; + encode_check = encode & ~ECOMMUNITY_FLAG_NON_TRANSITIVE; + + if (encode_check != ECOMMUNITY_ENCODE_AS + && encode_check != ECOMMUNITY_ENCODE_IP + && encode_check != ECOMMUNITY_ENCODE_OPAQUE) + { + len = sprintf (str_buf + str_pnt, "?"); + str_pnt += len; + first = 0; + continue; + } + + /* Low-order octet of type. */ + type = *pnt++; + if ((encode_check == ECOMMUNITY_ENCODE_AS + || encode_check == ECOMMUNITY_ENCODE_IP + || encode_check == ECOMMUNITY_ENCODE_4OCTET_AS) + && (type == ECOMMUNITY_TYPE_ROUTE_TARGET || type == ECOMMUNITY_TYPE_SITE_ORIGIN) + && ! CHECK_FLAG (encode, ECOMMUNITY_FLAG_NON_TRANSITIVE)) + { + switch (format) + { + case ECOMMUNITY_FORMAT_CONFIG: + prefix = (type == ECOMMUNITY_TYPE_ROUTE_TARGET ? "rt " : "soo "); + break; + case ECOMMUNITY_FORMAT_DISPLAY: + prefix = (type == ECOMMUNITY_TYPE_ROUTE_TARGET ? "RT:" : "SoO:"); + break; + default: + prefix = ""; + break; + } + } + else if (encode_check == ECOMMUNITY_ENCODE_OPAQUE + && type == ECOMMUNITY_TYPE_COST_COMMUNITY + && CHECK_FLAG (encode, ECOMMUNITY_FLAG_NON_TRANSITIVE)) + { + u_int32_t val; + u_char poi; + u_char id; + + poi = *pnt++; + id = *pnt++; + memcpy (&val, pnt, 4); + + len = sprintf (str_buf + str_pnt, "Cost:%s:%d:%u", + ecommunity_cost_poi_print (poi), id, ntohl (val)); + str_pnt += len; + first = 0; + continue; + } + else + { + len = sprintf (str_buf + str_pnt, "?"); + str_pnt += len; + first = 0; + continue; + } + + /* Put string into buffer. */ + if (encode_check == ECOMMUNITY_ENCODE_AS) + { + eas.as = (*pnt++ << 8); + eas.as |= (*pnt++); + + eas.val = (*pnt++ << 24); + eas.val |= (*pnt++ << 16); + eas.val |= (*pnt++ << 8); + eas.val |= (*pnt++); + + len = sprintf (str_buf + str_pnt, "%s%d:%d", prefix, + eas.as, eas.val); + str_pnt += len; + first = 0; + } + else if (encode_check == ECOMMUNITY_ENCODE_IP) + { + memcpy (&eip.ip, pnt, 4); + pnt += 4; + eip.val = (*pnt++ << 8); + eip.val |= (*pnt++); + + len = sprintf (str_buf + str_pnt, "%s%s:%d", prefix, + inet_ntoa (eip.ip), eip.val); + str_pnt += len; + first = 0; + } + } + return str_buf; +} + +int +ecommunity_match (struct ecommunity *ecom1, struct ecommunity *ecom2) +{ + int i = 0; + int j = 0; + + if (ecom1 == NULL && ecom2 == NULL) + return 1; + + if (ecom1 == NULL || ecom2 == NULL) + return 0; + + if (ecom1->size < ecom2->size) + return 0; + + /* Every community on com2 needs to be on com1 for this to match */ + while (i < ecom1->size && j < ecom2->size) + { + if (memcmp (ecom1->val + i, ecom2->val + j, ECOMMUNITY_SIZE) == 0) + j++; + i++; + } + + if (j == ecom2->size) + return 1; + else + return 0; +} + +int +ecommunity_cost_cmp (struct ecommunity *ecom1, struct ecommunity *ecom2, u_char poi) +{ + int i = 0; + int j = 0; + int find1 = 0; + int find2 = 0; + u_char id1 = 0; + u_char id2 = 0; + u_int32_t val1 = 0; + u_int32_t val2 = 0; + + /* For parse Extended Community attribute tupple. */ + struct ecommunity_cost + { + u_int16_t type; + u_char poi; + u_char id; + u_int32_t val; + } ecost; + + if (ecom1 == NULL && ecom2 == NULL) + return 0; + + while (1) + { + while (ecom1 && i < ecom1->size) + { + memcpy (&ecost, (ecom1->val + (i * 8)), sizeof (struct ecommunity_cost)); + + if (ntohs (ecost.type) == ECOMMUNITY_COST_COMMUNITY + && ecost.poi == poi) + { + id1 = ecost.id; + val1 = ntohl (ecost.val); + find1 = 1; + break; + } + i++; + } + + while (ecom2 && j < ecom2->size) + { + memcpy (&ecost, ecom2->val + (j * 8), sizeof (struct ecommunity_cost)); + if (ntohs (ecost.type) == ECOMMUNITY_COST_COMMUNITY + && ecost.poi == poi) + { + id2 = ecost.id; + val2 = ntohl (ecost.val); + find2 = 1; + break; + } + j++; + } + + if (! find1 || ! find2) + break; + if (id1 != id2) + break; + if (val1 != val2) + break; + + find1 = 0; + find2 = 0; + i++; + j++; + } + + if (! find1) + val1 = COST_COMMUNITY_DEFAULT_COST; + if (! find2) + val2 = COST_COMMUNITY_DEFAULT_COST; + + if (find1 && find2) + { + if (id1 < id2) + return 1; + if (id1 > id2) + return -1; + } + if (val1 < val2) + return 1; + if (val1 > val2) + return -1; + + return 0; +} diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h new file mode 100644 index 0000000..b2fe79e --- /dev/null +++ b/bgpd/bgp_ecommunity.h @@ -0,0 +1,99 @@ +/* BGP Extended Communities Attribute. + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Extended Communities Transitive flag. */ +#define ECOMMUNITY_FLAG_NON_TRANSITIVE 0x40 + +/* High-order octet of the Extended Communities type field. */ +#define ECOMMUNITY_ENCODE_AS 0x00 +#define ECOMMUNITY_ENCODE_IP 0x01 +#define ECOMMUNITY_ENCODE_4OCTET_AS 0x02 +#define ECOMMUNITY_ENCODE_OPAQUE 0x03 + +/* Low-order octet of the Extended Communityes type field. */ +#define ECOMMUNITY_TYPE_COST_COMMUNITY 0x01 +#define ECOMMUNITY_TYPE_ROUTE_TARGET 0x02 +#define ECOMMUNITY_TYPE_SITE_ORIGIN 0x03 + +/* High-order octet and Low-order octet of the Extended Communityes type field. */ +#define ECOMMUNITY_COST_COMMUNITY 0x4301 + +/* Extended communities attribute string format. */ +#define ECOMMUNITY_FORMAT_CONFIG 0 +#define ECOMMUNITY_FORMAT_DISPLAY 1 +#define ECOMMUNITY_FORMAT_RMAP 2 + +/* Extended communities Cost Community */ +#define ECOMMUNITY_COST_POI_IGP 129 + +/* Extended Communities value is eight octet long. */ +#define ECOMMUNITY_SIZE 8 + +/* Cost community default value. */ +#define COST_COMMUNITY_DEFAULT_COST 0x7FFFFFFF + +/* Extended Communities attribute. */ +struct ecommunity +{ + /* Reference counter. */ + unsigned long refcnt; + + /* Size of Extended Communities attribute. */ + int size; + + /* Extended Communities value. */ + u_char *val; + + /* Human readable format string. */ + char *str; +}; + +/* Extended community value is eight octet. */ +struct ecommunity_val +{ + char val[ECOMMUNITY_SIZE]; +}; + +struct ecommunity_cost +{ + u_int16_t type; + u_char poi; + u_char id; + u_int32_t val; +}; + +#define ecom_length(X) ((X)->size * ECOMMUNITY_SIZE) + +void ecommunity_init (void); +void ecommunity_free (struct ecommunity *); +struct ecommunity *ecommunity_new (void); +struct ecommunity *ecommunity_parse (char *, u_short); +struct ecommunity *ecommunity_dup (struct ecommunity *); +struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *); +struct ecommunity *ecommunity_intern (struct ecommunity *); +int ecommunity_cmp (struct ecommunity *, struct ecommunity *); +void ecommunity_unintern (struct ecommunity *); +unsigned int ecommunity_hash_make (struct ecommunity *); +struct ecommunity *ecommunity_str2com (char *, int, int); +char *ecommunity_ecom2str (struct ecommunity *, int); +int ecommunity_match (struct ecommunity *, struct ecommunity *); +char *ecommunity_str (struct ecommunity *); +struct ecommunity *ecommunity_cost_str2com (char *, u_char); +int ecommunity_cost_cmp (struct ecommunity *, struct ecommunity *, u_char); diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c new file mode 100644 index 0000000..7a8fb03 --- /dev/null +++ b/bgpd/bgp_filter.c @@ -0,0 +1,738 @@ +/* AS path filter list. + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "command.h" +#include "log.h" +#include "memory.h" +#include "buffer.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_filter.h" + +/* List of AS filter list. */ +struct as_list_list +{ + struct as_list *head; + struct as_list *tail; +}; + +/* AS path filter master. */ +struct as_list_master +{ + /* List of access_list which name is number. */ + struct as_list_list num; + + /* List of access_list which name is string. */ + struct as_list_list str; + + /* Hook function which is executed when new access_list is added. */ + void (*add_hook) (); + + /* Hook function which is executed when access_list is deleted. */ + void (*delete_hook) (); +}; + +/* Element of AS path filter. */ +struct as_filter +{ + struct as_filter *next; + struct as_filter *prev; + + enum as_filter_type type; + + regex_t *reg; + char *reg_str; +}; + +enum as_list_type +{ + ACCESS_TYPE_STRING, + ACCESS_TYPE_NUMBER +}; + +/* AS path filter list. */ +struct as_list +{ + char *name; + + enum as_list_type type; + + struct as_list *next; + struct as_list *prev; + + struct as_filter *head; + struct as_filter *tail; +}; + +/* ip as-path access-list 10 permit AS1. */ + +static struct as_list_master as_list_master = +{ + {NULL, NULL}, + {NULL, NULL}, + NULL, + NULL +}; + +/* Allocate new AS filter. */ +struct as_filter * +as_filter_new () +{ + struct as_filter *new; + + new = XMALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter)); + memset (new, 0, sizeof (struct as_filter)); + return new; +} + +/* Free allocated AS filter. */ +void +as_filter_free (struct as_filter *asfilter) +{ + if (asfilter->reg) + bgp_regex_free (asfilter->reg); + if (asfilter->reg_str) + XFREE (MTYPE_AS_FILTER_STR, asfilter->reg_str); + XFREE (MTYPE_AS_FILTER, asfilter); +} + +/* Make new AS filter. */ +struct as_filter * +as_filter_make (regex_t *reg, char *reg_str, enum as_filter_type type) +{ + struct as_filter *asfilter; + + asfilter = as_filter_new (); + asfilter->reg = reg; + asfilter->type = type; + asfilter->reg_str = XSTRDUP (MTYPE_AS_FILTER_STR, reg_str); + + return asfilter; +} + +struct as_filter * +as_filter_lookup (struct as_list *aslist, char *reg_str, + enum as_filter_type type) +{ + struct as_filter *asfilter; + + for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) + if (strcmp (reg_str, asfilter->reg_str) == 0) + return asfilter; + return NULL; +} + +void +as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter) +{ + asfilter->next = NULL; + asfilter->prev = aslist->tail; + + if (aslist->tail) + aslist->tail->next = asfilter; + else + aslist->head = asfilter; + aslist->tail = asfilter; +} + +/* Lookup as_list from list of as_list by name. */ +struct as_list * +as_list_lookup (char *name) +{ + struct as_list *aslist; + + if (name == NULL) + return NULL; + + for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) + if (strcmp (aslist->name, name) == 0) + return aslist; + + for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) + if (strcmp (aslist->name, name) == 0) + return aslist; + + return NULL; +} + +struct as_list * +as_list_new () +{ + struct as_list *new; + + new = XMALLOC (MTYPE_AS_LIST, sizeof (struct as_list)); + memset (new, 0, sizeof (struct as_list)); + return new; +} + +void +as_list_free (struct as_list *aslist) +{ + XFREE (MTYPE_AS_LIST, aslist); +} + +/* Insert new AS list to list of as_list. Each as_list is sorted by + the name. */ +struct as_list * +as_list_insert (char *name) +{ + int i; + long number; + struct as_list *aslist; + struct as_list *point; + struct as_list_list *list; + + /* Allocate new access_list and copy given name. */ + aslist = as_list_new (); + aslist->name = strdup (name); + + /* If name is made by all digit character. We treat it as + number. */ + for (number = 0, i = 0; i < strlen (name); i++) + { + if (isdigit ((int) name[i])) + number = (number * 10) + (name[i] - '0'); + else + break; + } + + /* In case of name is all digit character */ + if (i == strlen (name)) + { + aslist->type = ACCESS_TYPE_NUMBER; + + /* Set access_list to number list. */ + list = &as_list_master.num; + + for (point = list->head; point; point = point->next) + if (atol (point->name) >= number) + break; + } + else + { + aslist->type = ACCESS_TYPE_STRING; + + /* Set access_list to string list. */ + list = &as_list_master.str; + + /* Set point to insertion point. */ + for (point = list->head; point; point = point->next) + if (strcmp (point->name, name) >= 0) + break; + } + + /* In case of this is the first element of master. */ + if (list->head == NULL) + { + list->head = list->tail = aslist; + return aslist; + } + + /* In case of insertion is made at the tail of access_list. */ + if (point == NULL) + { + aslist->prev = list->tail; + list->tail->next = aslist; + list->tail = aslist; + return aslist; + } + + /* In case of insertion is made at the head of access_list. */ + if (point == list->head) + { + aslist->next = list->head; + list->head->prev = aslist; + list->head = aslist; + return aslist; + } + + /* Insertion is made at middle of the access_list. */ + aslist->next = point; + aslist->prev = point->prev; + + if (point->prev) + point->prev->next = aslist; + point->prev = aslist; + + return aslist; +} + +struct as_list * +as_list_get (char *name) +{ + struct as_list *aslist; + + aslist = as_list_lookup (name); + if (aslist == NULL) + { + aslist = as_list_insert (name); + + /* Run hook function. */ + if (as_list_master.add_hook) + (*as_list_master.add_hook) (); + } + + return aslist; +} + +static char * +filter_type_str (enum as_filter_type type) +{ + switch (type) + { + case AS_FILTER_PERMIT: + return "permit"; + break; + case AS_FILTER_DENY: + return "deny"; + break; + default: + return ""; + break; + } +} + +void +as_list_delete (struct as_list *aslist) +{ + struct as_list_list *list; + struct as_filter *filter, *next; + + for (filter = aslist->head; filter; filter = next) + { + next = filter->next; + as_filter_free (filter); + } + + if (aslist->type == ACCESS_TYPE_NUMBER) + list = &as_list_master.num; + else + list = &as_list_master.str; + + if (aslist->next) + aslist->next->prev = aslist->prev; + else + list->tail = aslist->prev; + + if (aslist->prev) + aslist->prev->next = aslist->next; + else + list->head = aslist->next; + + as_list_free (aslist); +} + +static int +as_list_empty (struct as_list *aslist) +{ + if (aslist->head == NULL && aslist->tail == NULL) + return 1; + else + return 0; +} + +void +as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter) +{ + if (asfilter->next) + asfilter->next->prev = asfilter->prev; + else + aslist->tail = asfilter->prev; + + if (asfilter->prev) + asfilter->prev->next = asfilter->next; + else + aslist->head = asfilter->next; + + as_filter_free (asfilter); + + /* If access_list becomes empty delete it from access_master. */ + if (as_list_empty (aslist)) + as_list_delete (aslist); + + /* Run hook function. */ + if (as_list_master.delete_hook) + (*as_list_master.delete_hook) (); +} + +static int +as_filter_match (struct as_filter *asfilter, struct aspath *aspath) +{ + if (bgp_regexec (asfilter->reg, aspath) != REG_NOMATCH) + return 1; + return 0; +} + +/* Apply AS path filter to AS. */ +enum as_filter_type +as_list_apply (struct as_list *aslist, void *object) +{ + struct as_filter *asfilter; + struct aspath *aspath; + + aspath = (struct aspath *) object; + + if (aslist == NULL) + return AS_FILTER_DENY; + + for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) + { + if (as_filter_match (asfilter, aspath)) + return asfilter->type; + } + return AS_FILTER_DENY; +} + +/* Add hook function. */ +void +as_list_add_hook (void (*func) ()) +{ + as_list_master.add_hook = func; +} + +/* Delete hook function. */ +void +as_list_delete_hook (void (*func) ()) +{ + as_list_master.delete_hook = func; +} + +int +as_list_dup_check (struct as_list *aslist, struct as_filter *new) +{ + struct as_filter *asfilter; + + for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) + { + if (asfilter->type == new->type + && strcmp (asfilter->reg_str, new->reg_str) == 0) + return 1; + } + return 0; +} + +DEFUN (ip_as_path, ip_as_path_cmd, + "ip as-path access-list WORD (deny|permit) .LINE", + IP_STR + "BGP autonomous system path filter\n" + "Specify an access list name\n" + "Regular expression access list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "A regular-expression to match the BGP AS paths\n") +{ + enum as_filter_type type; + struct as_filter *asfilter; + struct as_list *aslist; + regex_t *regex; + struct buffer *b; + int i; + char *regstr; + int first = 0; + + /* Check the filter type. */ + if (strncmp (argv[1], "p", 1) == 0) + type = AS_FILTER_PERMIT; + else if (strncmp (argv[1], "d", 1) == 0) + type = AS_FILTER_DENY; + else + { + vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check AS path regex. */ + b = buffer_new (1024); + for (i = 2; i < argc; i++) + { + if (first) + buffer_putc (b, ' '); + else + first = 1; + + buffer_putstr (b, argv[i]); + } + buffer_putc (b, '\0'); + + regstr = buffer_getstr (b); + buffer_free (b); + + regex = bgp_regcomp (regstr); + if (!regex) + { + free (regstr); + vty_out (vty, "can't compile regexp %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + asfilter = as_filter_make (regex, regstr, type); + + free (regstr); + + /* Install new filter to the access_list. */ + aslist = as_list_get (argv[0]); + + /* Duplicate insertion check. */; + if (as_list_dup_check (aslist, asfilter)) + as_filter_free (asfilter); + else + as_list_filter_add (aslist, asfilter); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_as_path, + no_ip_as_path_cmd, + "no ip as-path access-list WORD (deny|permit) .LINE", + NO_STR + IP_STR + "BGP autonomous system path filter\n" + "Specify an access list name\n" + "Regular expression access list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "A regular-expression to match the BGP AS paths\n") +{ + enum as_filter_type type; + struct as_filter *asfilter; + struct as_list *aslist; + struct buffer *b; + int i; + int first = 0; + char *regstr; + regex_t *regex; + + /* Lookup AS list from AS path list. */ + aslist = as_list_lookup (argv[0]); + if (aslist == NULL) + { + vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check the filter type. */ + if (strncmp (argv[1], "p", 1) == 0) + type = AS_FILTER_PERMIT; + else if (strncmp (argv[1], "d", 1) == 0) + type = AS_FILTER_DENY; + else + { + vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Compile AS path. */ + b = buffer_new (1024); + for (i = 2; i < argc; i++) + { + if (first) + buffer_putc (b, ' '); + else + first = 1; + + buffer_putstr (b, argv[i]); + } + buffer_putc (b, '\0'); + + regstr = buffer_getstr (b); + buffer_free (b); + + regex = bgp_regcomp (regstr); + if (!regex) + { + free (regstr); + vty_out (vty, "can't compile regexp %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Lookup asfilter. */ + asfilter = as_filter_lookup (aslist, regstr, type); + + free (regstr); + bgp_regex_free (regex); + + if (asfilter == NULL) + { + vty_out (vty, "%s", VTY_NEWLINE); + return CMD_WARNING; + } + + as_list_filter_delete (aslist, asfilter); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_as_path_all, + no_ip_as_path_all_cmd, + "no ip as-path access-list WORD", + NO_STR + IP_STR + "BGP autonomous system path filter\n" + "Specify an access list name\n" + "Regular expression access list name\n") +{ + struct as_list *aslist; + + aslist = as_list_lookup (argv[0]); + if (aslist == NULL) + { + vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + as_list_delete (aslist); + + /* Run hook function. */ + if (as_list_master.delete_hook) + (*as_list_master.delete_hook) (); + + return CMD_SUCCESS; +} + +void +as_list_show (struct vty *vty, struct as_list *aslist) +{ + struct as_filter *asfilter; + + vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE); + + for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) + { + vty_out (vty, " %s %s%s", filter_type_str (asfilter->type), + asfilter->reg_str, VTY_NEWLINE); + } +} + +void +as_list_show_all (struct vty *vty) +{ + struct as_list *aslist; + struct as_filter *asfilter; + + for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) + { + vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE); + + for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) + { + vty_out (vty, " %s %s%s", filter_type_str (asfilter->type), + asfilter->reg_str, VTY_NEWLINE); + } + } + + for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) + { + vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE); + + for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) + { + vty_out (vty, " %s %s%s", filter_type_str (asfilter->type), + asfilter->reg_str, VTY_NEWLINE); + } + } +} + +DEFUN (show_ip_as_path_access_list, + show_ip_as_path_access_list_cmd, + "show ip as-path-access-list WORD", + SHOW_STR + IP_STR + "List AS path access lists\n" + "AS path access list name\n") +{ + struct as_list *aslist; + + aslist = as_list_lookup (argv[0]); + if (aslist) + as_list_show (vty, aslist); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_as_path_access_list_all, + show_ip_as_path_access_list_all_cmd, + "show ip as-path-access-list", + SHOW_STR + IP_STR + "List AS path access lists\n") +{ + as_list_show_all (vty); + return CMD_SUCCESS; +} + +int +config_write_as_list (struct vty *vty) +{ + struct as_list *aslist; + struct as_filter *asfilter; + int write = 0; + + for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) + for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) + { + vty_out (vty, "ip as-path access-list %s %s %s%s", + aslist->name, filter_type_str (asfilter->type), + asfilter->reg_str, + VTY_NEWLINE); + write++; + } + + for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) + for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) + { + vty_out (vty, "ip as-path access-list %s %s %s%s", + aslist->name, filter_type_str (asfilter->type), + asfilter->reg_str, + VTY_NEWLINE); + write++; + } + return write; +} + +struct cmd_node as_list_node = +{ + AS_LIST_NODE, + "", + 1 +}; + +/* Register functions. */ +void +bgp_filter_init () +{ + install_node (&as_list_node, config_write_as_list); + + install_element (CONFIG_NODE, &ip_as_path_cmd); + install_element (CONFIG_NODE, &no_ip_as_path_cmd); + install_element (CONFIG_NODE, &no_ip_as_path_all_cmd); + + install_element (VIEW_NODE, &show_ip_as_path_access_list_cmd); + install_element (VIEW_NODE, &show_ip_as_path_access_list_all_cmd); + install_element (ENABLE_NODE, &show_ip_as_path_access_list_cmd); + install_element (ENABLE_NODE, &show_ip_as_path_access_list_all_cmd); +} diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h new file mode 100644 index 0000000..8d55a22 --- /dev/null +++ b/bgpd/bgp_filter.h @@ -0,0 +1,31 @@ +/* AS path filter list. + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +enum as_filter_type +{ + AS_FILTER_DENY, + AS_FILTER_PERMIT +}; + +enum as_filter_type as_list_apply (struct as_list *, void *); + +struct as_list *as_list_lookup (char *); +void as_list_add_hook (void (*func) ()); +void as_list_delete_hook (void (*func) ()); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c new file mode 100644 index 0000000..83da82a --- /dev/null +++ b/bgpd/bgp_fsm.c @@ -0,0 +1,1136 @@ +/* BGP-4 Finite State Machine + From RFC1771 [A Border Gateway Protocol 4 (BGP-4)] + Copyright (C) 1996, 97, 98 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "linklist.h" +#include "prefix.h" +#include "vty.h" +#include "sockunion.h" +#include "thread.h" +#include "log.h" +#include "stream.h" +#include "memory.h" +#include "plist.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_network.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_dump.h" +#include "bgpd/bgp_open.h" +#ifdef HAVE_SNMP +#include "bgpd/bgp_snmp.h" +#endif /* HAVE_SNMP */ + +/* BGP FSM (finite state machine) has three types of functions. Type + one is thread functions. Type two is event functions. Type three + is FSM functions. Timer functions are set by bgp_timer_set + function. */ + +/* BGP event function. */ +int bgp_event (struct thread *); + +/* BGP thread functions. */ +static int bgp_start_timer (struct thread *); +static int bgp_connect_timer (struct thread *); +static int bgp_holdtime_timer (struct thread *); +static int bgp_keepalive_timer (struct thread *); + +/* BGP FSM functions. */ +static int bgp_start (struct peer *); + +/* BGP active delay jitter. */ +int +bgp_active_delay_jitter (int time) +{ + return ((rand () % (time + 1)) - (time / 2)); +} + +/* Hook function called after bgp event is occered. And vty's + neighbor command invoke this function after making neighbor + structure. */ +void +bgp_timer_set (struct peer *peer) +{ + afi_t afi; + safi_t safi; + int active_delay = 0; + + switch (peer->status) + { + case Idle: + /* First entry point of peer's finite state machine. In Idle + status start timer is on unless peer is shutdown or peer is + inactive. All other timer must be turned off */ + if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN) + || CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW) + || ! peer_active (peer)) + { + BGP_TIMER_OFF (peer->t_start); + } + else + { + if (CHECK_FLAG (peer->sflags, PEER_STATUS_CREATE_INIT)) + { + BGP_TIMER_ON (peer->t_start, bgp_start_timer, BGP_PEER_FIRST_CREATE_TIMER); + } + else + { + BGP_TIMER_ON (peer->t_start, bgp_start_timer, peer->v_start); + } + } + BGP_TIMER_OFF (peer->t_connect); + BGP_TIMER_OFF (peer->t_holdtime); + BGP_TIMER_OFF (peer->t_keepalive); + BGP_TIMER_OFF (peer->t_asorig); + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + BGP_TIMER_OFF (peer->t_routeadv[afi][safi]); + break; + + case Connect: + /* After start timer is expired, the peer moves to Connnect + status. Make sure start timer is off and connect timer is + on. */ + BGP_TIMER_OFF (peer->t_start); + BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_connect); + BGP_TIMER_OFF (peer->t_holdtime); + BGP_TIMER_OFF (peer->t_keepalive); + BGP_TIMER_OFF (peer->t_asorig); + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + BGP_TIMER_OFF (peer->t_routeadv[afi][safi]); + break; + + case Active: + /* Active is waiting connection from remote peer. And if + connect timer is expired, change status to Connect. */ + BGP_TIMER_OFF (peer->t_start); + /* If peer is passive mode, do not set connect timer. */ + if (CHECK_FLAG (peer->flags, PEER_FLAG_CONNECT_MODE_PASSIVE)) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s active open failed - TCP session must be opened passively", peer->host); + BGP_TIMER_OFF (peer->t_connect); + } + else + { + if (peer->ostatus == Idle + && ! CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) + { + active_delay = peer->v_active_delay; + active_delay += bgp_active_delay_jitter (BGP_ACTIVE_DELAY_TIMER); + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s open active, delay %d sec", peer->host, active_delay); + BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, active_delay); + } + else + { + BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, + peer->v_connect); + } + } + BGP_TIMER_OFF (peer->t_holdtime); + BGP_TIMER_OFF (peer->t_keepalive); + BGP_TIMER_OFF (peer->t_asorig); + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + BGP_TIMER_OFF (peer->t_routeadv[afi][safi]); + break; + + case OpenSent: + /* OpenSent status. */ + BGP_TIMER_OFF (peer->t_start); + BGP_TIMER_OFF (peer->t_connect); + if (peer->v_holdtime != 0) + { + BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer, + peer->v_holdtime); + } + else + { + BGP_TIMER_OFF (peer->t_holdtime); + } + BGP_TIMER_OFF (peer->t_keepalive); + BGP_TIMER_OFF (peer->t_asorig); + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + BGP_TIMER_OFF (peer->t_routeadv[afi][safi]); + break; + + case OpenConfirm: + /* OpenConfirm status. */ + BGP_TIMER_OFF (peer->t_start); + BGP_TIMER_OFF (peer->t_connect); + + /* If the negotiated Hold Time value is zero, then the Hold Time + timer and KeepAlive timers are not started. */ + if (peer->v_holdtime == 0) + { + BGP_TIMER_OFF (peer->t_holdtime); + BGP_TIMER_OFF (peer->t_keepalive); + } + else + { + BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer, + peer->v_holdtime); + BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer, + peer->v_keepalive); + } + BGP_TIMER_OFF (peer->t_asorig); + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + BGP_TIMER_OFF (peer->t_routeadv[afi][safi]); + break; + + case Established: + /* In Established status start and connect timer is turned + off. */ + BGP_TIMER_OFF (peer->t_start); + BGP_TIMER_OFF (peer->t_connect); + + /* Same as OpenConfirm, if holdtime is zero then both holdtime + and keepalive must be turned off. */ + if (peer->v_holdtime == 0) + { + BGP_TIMER_OFF (peer->t_holdtime); + BGP_TIMER_OFF (peer->t_keepalive); + } + else + { + BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer, + peer->v_holdtime); + BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer, + peer->v_keepalive); + } + BGP_TIMER_OFF (peer->t_asorig); + break; + } +} + +/* BGP start timer. This function set BGP_Start event to thread value + and process event. */ +static int +bgp_start_timer (struct thread *thread) +{ + struct peer *peer; + + peer = THREAD_ARG (thread); + peer->t_start = NULL; + + UNSET_FLAG (peer->sflags, PEER_STATUS_CREATE_INIT); + + if (BGP_DEBUG (fsm, FSM)) + zlog (peer->log, LOG_DEBUG, + "%s [FSM] Timer (start timer expire).", peer->host); + + THREAD_VAL (thread) = BGP_Start; + bgp_event (thread); + + return 0; +} + +/* BGP connect retry timer. */ +static int +bgp_connect_timer (struct thread *thread) +{ + struct peer *peer; + + peer = THREAD_ARG (thread); + peer->t_connect = NULL; + + if (BGP_DEBUG (fsm, FSM)) + zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (connect timer expire)", + peer->host); + + THREAD_VAL (thread) = ConnectRetry_timer_expired; + bgp_event (thread); + + return 0; +} + +/* BGP holdtime timer. */ +static int +bgp_holdtime_timer (struct thread *thread) +{ + struct peer *peer; + + peer = THREAD_ARG (thread); + peer->t_holdtime = NULL; + + if (BGP_DEBUG (fsm, FSM)) + zlog (peer->log, LOG_DEBUG, + "%s [FSM] Timer (holdtime timer expire)", + peer->host); + + THREAD_VAL (thread) = Hold_Timer_expired; + bgp_event (thread); + + return 0; +} + +/* BGP keepalive fire ! */ +static int +bgp_keepalive_timer (struct thread *thread) +{ + struct peer *peer; + + peer = THREAD_ARG (thread); + peer->t_keepalive = NULL; + + if (BGP_DEBUG (fsm, FSM)) + zlog (peer->log, LOG_DEBUG, + "%s [FSM] Timer (keepalive timer expire)", + peer->host); + + THREAD_VAL (thread) = KeepAlive_timer_expired; + bgp_event (thread); + + return 0; +} + +int +bgp_routeadv_timer_ipv4_unicast (struct thread *thread) +{ + struct peer *peer; + + peer = THREAD_ARG (thread); + peer->t_routeadv[AFI_IP][SAFI_UNICAST] = NULL; + + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s routeadv timer expired for IPv4 Unicast", peer->host); + + peer->synctime[AFI_IP][SAFI_UNICAST] = time (NULL); + + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + + BGP_TIMER_ON (peer->t_routeadv[AFI_IP][SAFI_UNICAST], bgp_routeadv_timer_ipv4_unicast, + peer->v_routeadv); + + return 0; +} + +int +bgp_routeadv_timer_ipv4_multicast (struct thread *thread) +{ + struct peer *peer; + + peer = THREAD_ARG (thread); + peer->t_routeadv[AFI_IP][SAFI_MULTICAST] = NULL; + + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s routeadv timer expired for IPv4 Multicast", peer->host); + + peer->synctime[AFI_IP][SAFI_MULTICAST] = time (NULL); + + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + + BGP_TIMER_ON (peer->t_routeadv[AFI_IP][SAFI_MULTICAST], bgp_routeadv_timer_ipv4_multicast, + peer->v_routeadv); + + return 0; +} + +int +bgp_routeadv_timer_ipv6_unicast (struct thread *thread) +{ + struct peer *peer; + + peer = THREAD_ARG (thread); + peer->t_routeadv[AFI_IP6][SAFI_UNICAST] = NULL; + + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s routeadv timer expired for IPv6 Unicast", peer->host); + + peer->synctime[AFI_IP6][SAFI_UNICAST] = time (NULL); + + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + + BGP_TIMER_ON (peer->t_routeadv[AFI_IP6][SAFI_UNICAST], bgp_routeadv_timer_ipv6_unicast, + peer->v_routeadv); + + return 0; +} + +int +bgp_routeadv_timer_vpnv4_unicast (struct thread *thread) +{ + struct peer *peer; + + peer = THREAD_ARG (thread); + peer->t_routeadv[AFI_IP][SAFI_MPLS_VPN] = NULL; + + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s routeadv timer expired for VPNv4 unicast", peer->host); + + peer->synctime[AFI_IP][SAFI_MPLS_VPN] = time (NULL); + + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + + BGP_TIMER_ON (peer->t_routeadv[AFI_IP][SAFI_MPLS_VPN], bgp_routeadv_timer_vpnv4_unicast, + peer->v_routeadv); + + return 0; +} + +void +bgp_routeadv_timer (struct peer *peer, afi_t afi, safi_t safi) +{ + if (afi == AFI_IP && safi == SAFI_UNICAST) + BGP_TIMER_ON (peer->t_routeadv[afi][safi], bgp_routeadv_timer_ipv4_unicast, 1); + else if (afi == AFI_IP && safi == SAFI_MULTICAST) + BGP_TIMER_ON (peer->t_routeadv[afi][safi], bgp_routeadv_timer_ipv4_multicast, 1); + else if (afi == AFI_IP6 && safi == SAFI_UNICAST) + BGP_TIMER_ON (peer->t_routeadv[afi][safi], bgp_routeadv_timer_ipv6_unicast, 1); + else if (afi == AFI_IP && safi == SAFI_MPLS_VPN) + BGP_TIMER_ON (peer->t_routeadv[afi][safi], bgp_routeadv_timer_vpnv4_unicast, 1); +} + +/* Reset bgp update timer */ +static void +bgp_uptime_reset (struct peer *peer) +{ + peer->uptime = time (NULL); +} + +/* BGP Peer Down Cause */ +char *peer_down_str[] = +{ + "", + "Router ID changed", + "Remote AS changed", + "Local AS change", + "Cluster ID changed", + "Confederation identifier changed", + "Confederation peer changed", + "RR client config change", + "RS client config change", + "Update source change", + "Address family activated", + "Admin. shutdown", + "User reset", + "BGP Notification received", + "BGP Notification send", + "Peer closed the session", + "Neighbor deleted", + "Peer-group add member", + "Peer-group delete member", + "Capability changed", + "Multihop config change", + "Password change", + "NSF peer closed the session" +}; + +int +bgp_graceful_restart_timer_expire (struct thread *thread) +{ + struct peer *peer; + afi_t afi; + safi_t safi; + + peer = THREAD_ARG (thread); + peer->t_gr_restart = NULL; + + /* NSF delete stale route */ + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) + if (peer->nsf[afi][safi]) + bgp_clear_stale_route (peer, afi, safi); + + UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); + BGP_TIMER_OFF (peer->t_gr_stale); + + if (BGP_DEBUG (events, EVENTS)) + { + zlog_info ("%s graceful restart timer expired", peer->host); + zlog_info ("%s graceful restart stalepath timer stopped", peer->host); + } + + return 0; +} + +int +bgp_graceful_stale_timer_expire (struct thread *thread) +{ + struct peer *peer; + afi_t afi; + safi_t safi; + + peer = THREAD_ARG (thread); + peer->t_gr_stale = NULL; + + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s graceful restart stalepath timer expired", peer->host); + + /* NSF delete stale route */ + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) + if (peer->nsf[afi][safi]) + bgp_clear_stale_route (peer, afi, safi); + + return 0; +} + +/* Administrative BGP peer stop event. */ +int +bgp_stop (struct peer *peer) +{ + afi_t afi; + safi_t safi; + char orf_name[BUFSIZ]; + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_CREATE_INIT)) + return 0; + + /* Increment Dropped count. */ + if (peer->status == Established) + { + bgp_fsm_change_status (peer, Idle); + peer->dropped++; + + /* bgp log-neighbor-changes of neighbor Down */ + if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) + zlog_info ("%%ADJCHANGE: neighbor %s Down %s", peer->host, + peer_down_str [(int) peer->last_reset]); + + /* graceful restart */ + if (peer->t_gr_stale) + { + BGP_TIMER_OFF (peer->t_gr_stale); + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s graceful restart stalepath timer stopped", peer->host); + } + if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) + { + if (BGP_DEBUG (events, EVENTS)) + { + zlog_info ("%s graceful restart timer started for %d sec", + peer->host, peer->v_gr_restart); + zlog_info ("%s graceful restart stalepath timer started for %d sec", + peer->host, peer->bgp->stalepath_time); + } + BGP_TIMER_ON (peer->t_gr_restart, bgp_graceful_restart_timer_expire, + peer->v_gr_restart); + BGP_TIMER_ON (peer->t_gr_stale, bgp_graceful_stale_timer_expire, + peer->bgp->stalepath_time); + } + else + { + UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); + + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) + peer->nsf[afi][safi] = 0; + } + + /* set last reset time */ + peer->resettime = time (NULL); + +#ifdef HAVE_SNMP + bgpTrapBackwardTransition (peer); +#endif /* HAVE_SNMP */ + + /* Reset uptime. */ + bgp_uptime_reset (peer); + + /* Need of clear of peer. */ + bgp_clear_route_all (peer); + + /* Reset peer synctime */ + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + peer->synctime[afi][safi] = 0; + } + + /* Stop read and write threads when exists. */ + BGP_READ_OFF (peer->t_read); + BGP_WRITE_OFF (peer->t_write); + + /* Stop all timers. */ + BGP_TIMER_OFF (peer->t_start); + BGP_TIMER_OFF (peer->t_connect); + BGP_TIMER_OFF (peer->t_holdtime); + BGP_TIMER_OFF (peer->t_keepalive); + BGP_TIMER_OFF (peer->t_asorig); + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + BGP_TIMER_OFF (peer->t_routeadv[afi][safi]); + + /* Delete all existing events of the peer. */ + BGP_EVENT_DELETE (peer); + + /* Stream reset. */ + peer->packet_size = 0; + + /* Clear input and output buffer. */ + if (peer->ibuf) + stream_reset (peer->ibuf); + if (peer->work) + stream_reset (peer->work); + stream_fifo_clean (peer->obuf); + + /* Close of file descriptor. */ + if (peer->fd >= 0) + { + close (peer->fd); + peer->fd = -1; + } + + /* Connection information. */ + if (peer->su_local) + { + XFREE (MTYPE_SOCKUNION, peer->su_local); + peer->su_local = NULL; + } + + if (peer->su_remote) + { + XFREE (MTYPE_SOCKUNION, peer->su_remote); + peer->su_remote = NULL; + } + + /* Clear remote router-id. */ + peer->remote_id.s_addr = 0; + + /* Clear peer capability flag. */ + peer->cap = 0; + + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + { + /* Reset all negotiated variables */ + peer->afc_nego[afi][safi] = 0; + peer->afc_adv[afi][safi] = 0; + peer->afc_recv[afi][safi] = 0; + + /* peer address family capability flags*/ + peer->af_cap[afi][safi] = 0; + + /* peer address family status flags*/ + peer->af_sflags[afi][safi] = 0; + + /* Received ORF prefix-filter */ + peer->orf_plist[afi][safi] = NULL; + + /* ORF received prefix-filter pnt */ + sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); + prefix_bgp_orf_remove_all (orf_name); + } + + /* Reset keepalive and holdtime */ + if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) + { + peer->v_keepalive = peer->keepalive; + peer->v_holdtime = peer->holdtime; + } + else + { + peer->v_keepalive = peer->bgp->default_keepalive; + peer->v_holdtime = peer->bgp->default_holdtime; + } + + peer->update_time = 0; + + /* Until we are sure that there is no problem about prefix count + this should be commented out.*/ +#if 0 + /* Reset prefix count */ + peer->pcount[AFI_IP][SAFI_UNICAST] = 0; + peer->pcount[AFI_IP][SAFI_MULTICAST] = 0; + peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0; + peer->pcount[AFI_IP6][SAFI_UNICAST] = 0; + peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0; +#endif /* 0 */ + + return 0; +} + +/* BGP peer is stoped by the error. */ +int +bgp_stop_with_error (struct peer *peer) +{ + /* Double start timer. */ + peer->v_active_delay *= 2; + + /* Overflow check. */ + if (peer->v_active_delay > BGP_DEFAULT_CONNECT_RETRY) + peer->v_active_delay = BGP_DEFAULT_CONNECT_RETRY; + + bgp_stop (peer); + + return 0; +} + +/* TCP connection open. Next we send open message to remote peer. And + add read thread for reading open message. */ +int +bgp_connect_success (struct peer *peer) +{ + char buf1[BUFSIZ]; + + if (peer->fd < 0) + { + zlog_err ("bgp_connect_success peer's fd is negative value %d", + peer->fd); + return -1; + } + BGP_READ_ON (peer->t_read, bgp_read, peer->fd); + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + bgp_getsockname (peer); + + if (BGP_DEBUG (normal, NORMAL)) + { + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + zlog_info ("%s open active, local address %s", peer->host, + sockunion2str (peer->su_local, buf1, SU_ADDRSTRLEN)); + else + zlog_info ("%s passive open", peer->host); + } + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + bgp_open_send (peer); + + return 0; +} + +/* TCP connect fail */ +int +bgp_connect_fail (struct peer *peer) +{ + bgp_stop (peer); + return 0; +} + +/* This function is the first starting point of all BGP connection. It + try to connect to remote peer with non-blocking IO. */ +int +bgp_start (struct peer *peer) +{ + int status; + + status = bgp_connect (peer); + + switch (status) + { + case connect_error: + if (BGP_DEBUG (fsm, FSM)) + plog_info (peer->log, "%s [FSM] Connect error", peer->host); + BGP_EVENT_ADD (peer, TCP_connection_open_failed); + break; + case connect_success: + if (BGP_DEBUG (fsm, FSM)) + plog_info (peer->log, "%s [FSM] Connect immediately success", + peer->host); + BGP_EVENT_ADD (peer, TCP_connection_open); + break; + case connect_in_progress: + /* To check nonblocking connect, we wait until socket is + readable or writable. */ + if (BGP_DEBUG (fsm, FSM)) + plog_info (peer->log, "%s [FSM] Non blocking connect waiting result", + peer->host); + if (peer->fd < 0) + { + zlog_err ("bgp_start peer's fd is negative value %d", + peer->fd); + return -1; + } + BGP_READ_ON (peer->t_read, bgp_read, peer->fd); + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + break; + } + return 0; +} + +/* Connect retry timer is expired when the peer status is Connect. */ +int +bgp_reconnect (struct peer *peer) +{ + bgp_stop (peer); + bgp_start (peer); + return 0; +} + +int +bgp_fsm_open (struct peer *peer) +{ + /* Send keepalive and make keepalive timer */ + bgp_keepalive_send (peer); + + /* Reset holdtimer value. */ + BGP_TIMER_OFF (peer->t_holdtime); + + return 0; +} + +/* Called after event occured, this function change status and reset + read/write and timer thread. */ +void +bgp_fsm_change_status (struct peer *peer, int status) +{ + bgp_dump_state (peer, peer->status, status); + + /* Preserve old status and change into new status. */ + peer->ostatus = peer->status; + peer->status = status; + + if (BGP_DEBUG (normal, NORMAL)) + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + zlog_info ("%s went from %s to %s", peer->host, + LOOKUP (bgp_status_msg, peer->ostatus), + LOOKUP (bgp_status_msg, peer->status)); +} + +/* Keepalive send to peer. */ +int +bgp_fsm_keepalive_expire (struct peer *peer) +{ + bgp_keepalive_send (peer); + return 0; +} + +/* Hold timer expire. This is error of BGP connection. So cut the + peer and change to Idle status. */ +int +bgp_fsm_holdtime_expire (struct peer *peer) +{ + if (BGP_DEBUG (fsm, FSM)) + zlog (peer->log, LOG_DEBUG, "%s [FSM] Hold timer expire", peer->host); + + /* Send notify to remote peer. */ + bgp_notify_send (peer, BGP_NOTIFY_HOLD_ERR, 0); + + /* Sweep if it is temporary peer. */ + if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host); + peer_delete (peer); + return -1; + } + + return 0; +} + +/* Status goes to Established. Send keepalive packet then make first + update information. */ +int +bgp_establish (struct peer *peer) +{ + struct bgp_notify *notify; + afi_t afi; + safi_t safi; + int nsf_af_count = 0; + + /* Reset capability open status flag. */ + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN)) + SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); + + /* Clear last notification data. */ + notify = &peer->notify; + if (notify->data) + XFREE (MTYPE_TMP, notify->data); + memset (notify, 0, sizeof (struct bgp_notify)); + + /* Clear active delay timer value to default. */ + peer->v_active_delay = BGP_ACTIVE_DELAY_TIMER; + + /* Increment established count. */ + peer->established++; + bgp_fsm_change_status (peer, Established); + + /* bgp log-neighbor-changes of neighbor Up */ + if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) + zlog_info ("%%ADJCHANGE: neighbor %s Up", peer->host); + + /* graceful restart */ + UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) + { + if (peer->afc_nego[afi][safi] + && CHECK_FLAG (peer->cap, PEER_CAP_RESTART_ADV) + && CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV)) + { + if (peer->nsf[afi][safi] + && ! CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV)) + bgp_clear_stale_route (peer, afi, safi); + + peer->nsf[afi][safi] = 1; + nsf_af_count++; + } + else + { + if (peer->nsf[afi][safi]) + bgp_clear_stale_route (peer, afi, safi); + peer->nsf[afi][safi] = 0; + } + } + + if (nsf_af_count) + SET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); + else + { + UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); + if (peer->t_gr_stale) + { + BGP_TIMER_OFF (peer->t_gr_stale); + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s graceful restart stalepath timer stopped", peer->host); + } + } + + if (peer->t_gr_restart) + { + BGP_TIMER_OFF (peer->t_gr_restart); + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s graceful restart timer stopped", peer->host); + } + +#ifdef HAVE_SNMP + bgpTrapEstablished (peer); +#endif /* HAVE_SNMP */ + + /* Reset uptime, send keepalive, send current table. */ + bgp_uptime_reset (peer); + + /* Send route-refresh when ORF is enabled */ + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)) + { + if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)) + bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX, + REFRESH_IMMEDIATE, 0); + else if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) + bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX_OLD, + REFRESH_IMMEDIATE, 0); + } + + if (peer->v_keepalive) + bgp_keepalive_send (peer); + + /* First update is deferred until ORF or ROUTE-REFRESH is received */ + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV)) + if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) + || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV)) + SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH); + + bgp_announce_route_all (peer); + return 0; +} + +/* Keepalive packet is received. */ +int +bgp_fsm_keepalive (struct peer *peer) +{ + /* peer count update */ + peer->keepalive_in++; + + BGP_TIMER_OFF (peer->t_holdtime); + return 0; +} + +/* Update packet is received. */ +int +bgp_fsm_update (struct peer *peer) +{ + BGP_TIMER_OFF (peer->t_holdtime); + return 0; +} + +/* This is empty event. */ +int +bgp_ignore (struct peer *peer) +{ + if (BGP_DEBUG (fsm, FSM)) + zlog (peer->log, LOG_DEBUG, "%s [FSM] bgp_ignore called", peer->host); + return 0; +} + +/* Finite State Machine structure */ +struct { + int (*func) (); + int next_state; +} FSM [BGP_STATUS_MAX - 1][BGP_EVENTS_MAX - 1] = +{ + { + /* Idle state: In Idle state, all events other than BGP_Start is + ignored. With BGP_Start event, finite state machine calls + bgp_start(). */ + {bgp_ignore, Active}, /* BGP_Start */ + {bgp_stop, Idle}, /* BGP_Stop */ + {bgp_stop, Idle}, /* TCP_connection_open */ + {bgp_stop, Idle}, /* TCP_connection_closed */ + {bgp_ignore, Idle}, /* TCP_connection_open_failed */ + {bgp_stop, Idle}, /* TCP_fatal_error */ + {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */ + {bgp_ignore, Idle}, /* Hold_Timer_expired */ + {bgp_ignore, Idle}, /* KeepAlive_timer_expired */ + {bgp_ignore, Idle}, /* Receive_OPEN_message */ + {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ + {bgp_ignore, Idle}, /* Receive_UPDATE_message */ + {bgp_ignore, Idle}, /* Receive_NOTIFICATION_message */ + }, + { + /* Connect */ + {bgp_ignore, Connect}, /* BGP_Start */ + {bgp_stop, Idle}, /* BGP_Stop */ + {bgp_connect_success, OpenSent}, /* TCP_connection_open */ + {bgp_stop, Idle}, /* TCP_connection_closed */ + {bgp_connect_fail, Active}, /* TCP_connection_open_failed */ + {bgp_connect_fail, Idle}, /* TCP_fatal_error */ + {bgp_reconnect, Connect}, /* ConnectRetry_timer_expired */ + {bgp_ignore, Idle}, /* Hold_Timer_expired */ + {bgp_ignore, Idle}, /* KeepAlive_timer_expired */ + {bgp_ignore, Idle}, /* Receive_OPEN_message */ + {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ + {bgp_ignore, Idle}, /* Receive_UPDATE_message */ + {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */ + }, + { + /* Active, */ + {bgp_ignore, Active}, /* BGP_Start */ + {bgp_stop, Idle}, /* BGP_Stop */ + {bgp_connect_success, OpenSent}, /* TCP_connection_open */ + {bgp_stop, Idle}, /* TCP_connection_closed */ + {bgp_ignore, Active}, /* TCP_connection_open_failed */ + {bgp_ignore, Idle}, /* TCP_fatal_error */ + {bgp_start, Connect}, /* ConnectRetry_timer_expired */ + {bgp_ignore, Idle}, /* Hold_Timer_expired */ + {bgp_ignore, Idle}, /* KeepAlive_timer_expired */ + {bgp_ignore, Idle}, /* Receive_OPEN_message */ + {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ + {bgp_ignore, Idle}, /* Receive_UPDATE_message */ + {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ + }, + { + /* OpenSent, */ + {bgp_ignore, OpenSent}, /* BGP_Start */ + {bgp_stop, Idle}, /* BGP_Stop */ + {bgp_stop, Idle}, /* TCP_connection_open */ + {bgp_stop, Active}, /* TCP_connection_closed */ + {bgp_ignore, Idle}, /* TCP_connection_open_failed */ + {bgp_stop, Idle}, /* TCP_fatal_error */ + {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */ + {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ + {bgp_ignore, Idle}, /* KeepAlive_timer_expired */ + {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */ + {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ + {bgp_ignore, Idle}, /* Receive_UPDATE_message */ + {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ + }, + { + /* OpenConfirm, */ + {bgp_ignore, OpenConfirm}, /* BGP_Start */ + {bgp_stop, Idle}, /* BGP_Stop */ + {bgp_stop, Idle}, /* TCP_connection_open */ + {bgp_stop, Idle}, /* TCP_connection_closed */ + {bgp_stop, Idle}, /* TCP_connection_open_failed */ + {bgp_stop, Idle}, /* TCP_fatal_error */ + {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */ + {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ + {bgp_ignore, OpenConfirm}, /* KeepAlive_timer_expired */ + {bgp_ignore, Idle}, /* Receive_OPEN_message */ + {bgp_establish, Established}, /* Receive_KEEPALIVE_message */ + {bgp_ignore, Idle}, /* Receive_UPDATE_message */ + {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ + }, + { + /* Established, */ + {bgp_ignore, Established}, /* BGP_Start */ + {bgp_stop, Idle}, /* BGP_Stop */ + {bgp_stop, Idle}, /* TCP_connection_open */ + {bgp_stop, Idle}, /* TCP_connection_closed */ + {bgp_ignore, Idle}, /* TCP_connection_open_failed */ + {bgp_stop, Idle}, /* TCP_fatal_error */ + {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */ + {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ + {bgp_fsm_keepalive_expire, Established}, /* KeepAlive_timer_expired */ + {bgp_stop, Idle}, /* Receive_OPEN_message */ + {bgp_fsm_keepalive, Established}, /* Receive_KEEPALIVE_message */ + {bgp_fsm_update, Established}, /* Receive_UPDATE_message */ + {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ + }, +}; + +static char *bgp_event_str[] = +{ + NULL, + "BGP_Start", + "BGP_Stop", + "TCP_connection_open", + "TCP_connection_closed", + "TCP_connection_open_failed", + "TCP_fatal_error", + "ConnectRetry_timer_expired", + "Hold_Timer_expired", + "KeepAlive_timer_expired", + "Receive_OPEN_message", + "Receive_KEEPALIVE_message", + "Receive_UPDATE_message", + "Receive_NOTIFICATION_message" +}; + +/* Execute event process. */ +int +bgp_event (struct thread *thread) +{ + int ret; + int event; + int next; + struct peer *peer; + + peer = THREAD_ARG (thread); + event = THREAD_VAL (thread); + + /* Logging this event. */ + next = FSM [peer->status -1][event - 1].next_state; + + if (BGP_DEBUG (fsm, FSM)) + plog_info (peer->log, "%s [FSM] %s (%s->%s)", peer->host, + bgp_event_str[event], + LOOKUP (bgp_status_msg, peer->status), + LOOKUP (bgp_status_msg, next)); + + /* Call function. */ + ret = (*(FSM [peer->status - 1][event - 1].func))(peer); + + /* When function do not want proceed next job return -1. */ + if (ret < 0) + return ret; + + /* If status is changed. */ + if (next != peer->status) + bgp_fsm_change_status (peer, next); + + /* Make sure timer is set. */ + bgp_timer_set (peer); + + return 0; +} diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h new file mode 100644 index 0000000..7d662aa --- /dev/null +++ b/bgpd/bgp_fsm.h @@ -0,0 +1,45 @@ +/* BGP-4 Finite State Machine + From RFC1771 [A Border Gateway Protocol 4 (BGP-4)] + Copyright (C) 1998 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Macro for BGP read, write and timer thread. */ +#define BGP_READ_ON(T,F,V) THREAD_READ_ON(master,T,F,peer,V) +#define BGP_READ_OFF(X) THREAD_READ_OFF(X) + +#define BGP_WRITE_ON(T,F,V) THREAD_WRITE_ON(master,T,F,peer,V) +#define BGP_WRITE_OFF(X) THREAD_WRITE_OFF(X) + +#define BGP_TIMER_ON(T,F,V) THREAD_TIMER_ON(master,T,F,peer,V) +#define BGP_TIMER_OFF(X) THREAD_TIMER_OFF(X) + +#define BGP_EVENT_ADD(P,E) \ + thread_add_event (master, bgp_event, (P), (E)) + +#define BGP_EVENT_DELETE(P) \ + thread_cancel_event (master, (P)) + +/* Prototypes. */ +int bgp_event (struct thread *); +int bgp_stop (struct peer *peer); +int bgp_stop_with_error (struct peer *peer); +void bgp_timer_set (struct peer *); +void bgp_fsm_change_status (struct peer *peer, int status); +extern char *peer_down_str[]; +void bgp_routeadv_timer (struct peer *, afi_t, safi_t); diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c new file mode 100644 index 0000000..749a270 --- /dev/null +++ b/bgpd/bgp_main.c @@ -0,0 +1,285 @@ +/* Main routine of bgpd. + Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "getopt.h" +#include "thread.h" +#include "version.h" +#include "memory.h" +#include "prefix.h" +#include "log.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_mplsvpn.h" + +/* bgpd options, we use GNU getopt library. */ +struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "bgp_port", required_argument, NULL, 'p'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "retain", no_argument, NULL, 'r'}, + { "no_kernel", no_argument, NULL, 'n'}, + { "version", no_argument, NULL, 'v'}, + { "help", no_argument, NULL, 'h'}, + { 0 } +}; + +/* Configuration file and directory. */ +char config_current[] = BGP_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR BGP_DEFAULT_CONFIG; + +/* Route retain mode flag. */ +int retain_mode = 0; + +/* Master of threads. */ +struct thread_master *master; + +/* Manually specified configuration file name. */ +char *config_file = NULL; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_BGPD_PID; + +/* VTY port number and address. */ +int vty_port = BGP_VTY_PORT; +char *vty_addr = NULL; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\n\ +Daemon which manages kernel routing table management and \ +redistribution between different routing protocols.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-p, --bgp_port Set bgp protocol's port number\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-r, --retain When program terminates, retain added route by bgpd.\n\ +-n, --no_kernel Do not install route to kernel.\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + + exit (status); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog (NULL, LOG_INFO, "SIGHUP received"); + + /* Terminate all thread. */ + bgp_terminate (); + bgp_reset (); + zlog_info ("bgpd restarting!"); + + /* Reload config file. */ + vty_read_config (config_file, config_current, config_default); + + /* Create VTY's socket */ + vty_serv_sock (vty_addr, vty_port ? vty_port : BGP_VTY_PORT, BGP_VTYSH_PATH); + + /* Try to return to normal operation. */ +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + zlog (NULL, LOG_INFO, "Terminating on signal"); + + if (! retain_mode) + bgp_terminate (); + + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_rotate (NULL); +} + +/* Signale wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigint); + signal_set (SIGPIPE, SIG_IGN); + signal_set (SIGUSR1, sigusr1); +} + +/* Main routine of bgpd. Treatment of argument and start bgp finite + state machine is handled at here. */ +int +main (int argc, char **argv) +{ + char *p; + int opt; + int daemon_mode = 0; + char *progname; + struct thread thread; + + /* Set umask before anything for security */ + umask (0027); + + /* Preserve name of myself. */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_BGP, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + /* BGP master init. */ + bgp_master_init (); + + /* Command line argument treatment. */ + while (1) + { + opt = getopt_long (argc, argv, "df:hp:A:P:rnv", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'd': + daemon_mode = 1; + break; + case 'f': + config_file = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'p': + bm->port = atoi (optarg); + break; + case 'A': + vty_addr = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'r': + retain_mode = 1; + break; + case 'n': + bgp_option_set (BGP_OPT_NO_FIB); + break; + case 'v': + print_version (progname); + exit (0); + break; + case 'h': + usage (progname, 0); + break; + default: + usage (progname, 1); + break; + } + } + + /* Make thread master. */ + master = bm->master; + + /* Initializations. */ + srand (time (NULL)); + signal_init (); + cmd_init (1); + vty_init (); + memory_init (); + + /* BGP related initialization. */ + bgp_init (); + + /* Sort CLI commands. */ + sort_node (); + + /* Parse config file. */ + vty_read_config (config_file, config_current, config_default); + + /* Turn into daemon if daemon_mode is set. */ + if (daemon_mode) + daemon (0, 0); + + /* Process ID file creation. */ + pid_output (pid_file); + + /* Make bgp vty socket. */ + vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH); + + /* Print banner. */ + zlog_info ("BGPd %s starting: vty@%d, bgp@%d", ZEBRA_BGPD_VERSION, + vty_port, bm->port); + + /* Start finite state machine, here we go! */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Not reached. */ + exit (0); +} diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c new file mode 100644 index 0000000..e820cab --- /dev/null +++ b/bgpd/bgp_mplsvpn.c @@ -0,0 +1,741 @@ +/* MPLS-VPN + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "command.h" +#include "prefix.h" +#include "log.h" +#include "memory.h" +#include "stream.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_mplsvpn.h" + +int route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int, safi_t); +int route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t); +void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t); + +u_int16_t +decode_rd_type (u_char *pnt) +{ + u_int16_t v; + + v = ((u_int16_t) *pnt++ << 8); + v |= (u_int16_t) *pnt; + return v; +} + +u_int32_t +decode_label (u_char *pnt) +{ + u_int32_t l; + + l = ((u_int32_t) *pnt++ << 12); + l |= (u_int32_t) *pnt++ << 4; + l |= (u_int32_t) ((*pnt & 0xf0) >> 4); + return l; +} + +void +decode_rd_as (u_char *pnt, struct rd_as *rd_as) +{ + rd_as->as = (u_int16_t) *pnt++ << 8; + rd_as->as |= (u_int16_t) *pnt++; + + rd_as->val = ((u_int32_t) *pnt++ << 24); + rd_as->val |= ((u_int32_t) *pnt++ << 16); + rd_as->val |= ((u_int32_t) *pnt++ << 8); + rd_as->val |= (u_int32_t) *pnt; +} + +void +decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) +{ + memcpy (&rd_ip->ip, pnt, 4); + pnt += 4; + + rd_ip->val = ((u_int16_t) *pnt++ << 8); + rd_ip->val |= (u_int16_t) *pnt; +} + +int bgp_update (struct peer *, struct prefix *, struct attr *, + afi_t, safi_t, int, int, struct prefix_rd *, u_char *); + +int bgp_withdraw (struct peer *, struct prefix *, struct attr *, + int, int, int, int, struct prefix_rd *, u_char *); +int +bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, + struct bgp_nlri *packet) +{ + u_char *pnt; + u_char *lim; + struct prefix p; + int psize; + int prefixlen; + u_int32_t label; + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + struct prefix_rd prd; + u_char *tagpnt; + + /* Check peer status. */ + if (peer->status != Established) + return 0; + + /* Make prefix_rd */ + prd.family = AF_UNSPEC; + prd.prefixlen = 64; + + pnt = packet->nlri; + lim = pnt + packet->length; + + for (; pnt < lim; pnt += psize) + { + /* Clear prefix structure. */ + memset (&p, 0, sizeof (struct prefix)); + + /* Fetch prefix length. */ + prefixlen = *pnt++; + p.family = AF_INET; + psize = PSIZE (prefixlen); + + if (prefixlen < 88) + { + zlog_err ("prefix length is less than 88: %d", prefixlen); + return -1; + } + + label = decode_label (pnt); + + /* Copyr label to prefix. */ + tagpnt = pnt;; + + /* Copy routing distinguisher to rd. */ + memcpy (&prd.val, pnt + 3, 8); + + /* Decode RD type. */ + type = decode_rd_type (pnt + 3); + + /* Decode RD value. */ + if (type == RD_TYPE_AS) + decode_rd_as (pnt + 5, &rd_as); + else if (type == RD_TYPE_IP) + decode_rd_ip (pnt + 5, &rd_ip); + else + { + zlog_err ("Invalid RD type %d", type); + return -1; + } + + p.prefixlen = prefixlen - 88; + memcpy (&p.u.prefix, pnt + 11, psize - 11); + +#if 0 + if (type == RD_TYPE_AS) + zlog_info ("prefix %ld:%ld:%ld:%s/%d", label, rd_as.as, rd_as.val, + inet_ntoa (p.u.prefix4), p.prefixlen); + else if (type == RD_TYPE_IP) + zlog_info ("prefix %ld:%s:%ld:%s/%d", label, inet_ntoa (rd_ip.ip), + rd_ip.val, inet_ntoa (p.u.prefix4), p.prefixlen); +#endif /* 0 */ + + if (pnt + psize > lim) + return -1; + + if (attr) + bgp_update (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); + else + bgp_withdraw (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); + } + + /* Packet length consistency check. */ + if (pnt != lim) + return -1; + + return 0; +} + +int +str2prefix_rd (u_char *str, struct prefix_rd *prd) +{ + int ret; + u_char *p; + u_char *p2; + struct stream *s; + u_char *half; + struct in_addr addr; + + s = stream_new (8); + + prd->family = AF_UNSPEC; + prd->prefixlen = 64; + + p = strchr (str, ':'); + if (! p) + return 0; + + if (! all_digit (p + 1)) + return 0; + + half = XMALLOC (MTYPE_TMP, (p - str) + 1); + memcpy (half, str, (p - str)); + half[p - str] = '\0'; + + p2 = strchr (str, '.'); + + if (! p2) + { + if (! all_digit (half)) + { + XFREE (MTYPE_TMP, half); + return 0; + } + stream_putw (s, RD_TYPE_AS); + stream_putw (s, atoi (half)); + stream_putl (s, atol (p + 1)); + } + else + { + ret = inet_aton (half, &addr); + if (! ret) + { + XFREE (MTYPE_TMP, half); + return 0; + } + stream_putw (s, RD_TYPE_IP); + stream_put_in_addr (s, &addr); + stream_putw (s, atol (p + 1)); + } + memcpy (prd->val, s->data, 8); + + return 1; +} + +int +str2tag (u_char *str, u_char *tag) +{ + u_int32_t l; + + l = atol (str); + + tag[0] = (u_char)(l >> 12); + tag[1] = (u_char)(l >> 4); + tag[2] = (u_char)(l << 4); + + return 1; +} + +char * +prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size) +{ + u_char *pnt; + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + + if (size < RD_ADDRSTRLEN) + return NULL; + + pnt = prd->val; + + type = decode_rd_type (pnt); + + if (type == RD_TYPE_AS) + { + decode_rd_as (pnt + 2, &rd_as); + snprintf (buf, size, "%d:%d", rd_as.as, rd_as.val); + return buf; + } + else if (type == RD_TYPE_IP) + { + decode_rd_ip (pnt + 2, &rd_ip); + snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + return buf; + } + + return NULL; +} + +/* For testing purpose, static route of MPLS-VPN. */ +DEFUN (vpnv4_network, + vpnv4_network_cmd, + "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "BGP tag\n" + "tag value\n") +{ + return bgp_static_set_vpnv4 (vty, argv[0], argv[1], argv[2]); +} + +/* For testing purpose, static route of MPLS-VPN. */ +DEFUN (no_vpnv4_network, + no_vpnv4_network_cmd, + "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "BGP tag\n" + "tag value\n") +{ + return bgp_static_unset_vpnv4 (vty, argv[0], argv[1], argv[2]); +} + +int +show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd) +{ + struct bgp *bgp; + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_node *rm; + struct attr *attr; + int rd_header; + int header = 1; + char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; + + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; + rn = bgp_route_next (rn)) + { + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + { + rd_header = 1; + + for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) + if ((attr = rm->info) != NULL) + { + if (header) + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", + inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", + VTY_NEWLINE); + vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, v4_header, VTY_NEWLINE); + header = 0; + } + + if (rd_header) + { + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + u_char *pnt; + + pnt = rn->p.u.val; + + /* Decode RD type. */ + type = decode_rd_type (pnt); + /* Decode RD value. */ + if (type == RD_TYPE_AS) + decode_rd_as (pnt + 2, &rd_as); + else if (type == RD_TYPE_IP) + decode_rd_ip (pnt + 2, &rd_ip); + + vty_out (vty, "Route Distinguisher: "); + + if (type == RD_TYPE_AS) + vty_out (vty, "%d:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_IP) + vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + + vty_out (vty, "%s", VTY_NEWLINE); + rd_header = 0; + } + route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN); + } + } + } + return CMD_SUCCESS; +} + +enum bgp_show_type +{ + bgp_show_type_normal, + bgp_show_type_regexp, + bgp_show_type_prefix_list, + bgp_show_type_filter_list, + bgp_show_type_neighbor, + bgp_show_type_cidr_only, + bgp_show_type_prefix_longer, + bgp_show_type_community_all, + bgp_show_type_community, + bgp_show_type_community_exact, + bgp_show_type_community_list, + bgp_show_type_community_list_exact +}; + +int +bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type, + void *output_arg, int tags) +{ + struct bgp *bgp; + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_node *rm; + struct bgp_info *ri; + int rd_header; + int header = 1; + char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; + char v4_header_tag[] = " Network Next Hop In tag/Out tag%s"; + + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) + { + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + { + rd_header = 1; + + for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) + for (ri = rm->info; ri; ri = ri->next) + { + if (type == bgp_show_type_neighbor) + { + union sockunion *su = output_arg; + + if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) + continue; + } + if (header) + { + if (tags) + vty_out (vty, v4_header_tag, VTY_NEWLINE); + else + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", + inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", + VTY_NEWLINE); + vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, v4_header, VTY_NEWLINE); + } + header = 0; + } + + if (rd_header) + { + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + u_char *pnt; + + pnt = rn->p.u.val; + + /* Decode RD type. */ + type = decode_rd_type (pnt); + /* Decode RD value. */ + if (type == RD_TYPE_AS) + decode_rd_as (pnt + 2, &rd_as); + else if (type == RD_TYPE_IP) + decode_rd_ip (pnt + 2, &rd_ip); + + vty_out (vty, "Route Distinguisher: "); + + if (type == RD_TYPE_AS) + vty_out (vty, "%d:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_IP) + vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + + vty_out (vty, "%s", VTY_NEWLINE); + rd_header = 0; + } + if (tags) + route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_MPLS_VPN); + else + route_vty_out (vty, &rm->p, ri, 0, SAFI_MPLS_VPN); + } + } + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_vpnv4_all, + show_ip_bgp_vpnv4_all_cmd, + "show ip bgp vpnv4 all", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n") +{ + return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 0); +} + +DEFUN (show_ip_bgp_vpnv4_rd, + show_ip_bgp_vpnv4_rd_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 0); +} + +DEFUN (show_ip_bgp_vpnv4_all_tags, + show_ip_bgp_vpnv4_all_tags_cmd, + "show ip bgp vpnv4 all tags", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Display BGP tags for prefixes\n") +{ + return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 1); +} + +DEFUN (show_ip_bgp_vpnv4_rd_tags, + show_ip_bgp_vpnv4_rd_tags_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn tags", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Display BGP tags for prefixes\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 1); +} + +DEFUN (show_ip_bgp_vpnv4_all_neighbor_routes, + show_ip_bgp_vpnv4_all_neighbor_routes_cmd, + "show ip bgp vpnv4 all neighbors A.B.C.D routes", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + union sockunion *su; + struct peer *peer; + + su = sockunion_str2su (argv[0]); + if (su == NULL) + { + vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, su); + if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_neighbor, su, 0); +} + +DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes, + show_ip_bgp_vpnv4_rd_neighbor_routes_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + int ret; + union sockunion *su; + struct peer *peer; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + su = sockunion_str2su (argv[1]); + if (su == NULL) + { + vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, su); + if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_neighbor, su, 0); +} + +DEFUN (show_ip_bgp_vpnv4_all_neighbor_advertised_routes, + show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd, + "show ip bgp vpnv4 all neighbors A.B.C.D advertised-routes", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + int ret; + struct peer *peer; + union sockunion su; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_vpn (vty, peer, NULL); +} + +DEFUN (show_ip_bgp_vpnv4_rd_neighbor_advertised_routes, + show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + int ret; + struct peer *peer; + struct prefix_rd prd; + union sockunion su; + + ret = str2sockunion (argv[1], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_vpn (vty, peer, &prd); +} + +void +bgp_mplsvpn_init () +{ + install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd); + install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd); + + + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_tags_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd); + + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_tags_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd); +} diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h new file mode 100644 index 0000000..cd861a8 --- /dev/null +++ b/bgpd/bgp_mplsvpn.h @@ -0,0 +1,45 @@ +/* MPLS-VPN + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#define RD_TYPE_AS 0 +#define RD_TYPE_IP 1 + +#define RD_ADDRSTRLEN 28 + +struct rd_as +{ + u_int16_t type; + as_t as; + u_int32_t val; +}; + +struct rd_ip +{ + u_int16_t type; + struct in_addr ip; + u_int16_t val; +}; + +void bgp_mplsvpn_init (); +int bgp_nlri_parse_vpnv4 (struct peer *, struct attr *, struct bgp_nlri *); +u_int32_t decode_label (u_char *); +int str2prefix_rd (u_char *, struct prefix_rd *); +int str2tag (u_char *, u_char *); +char *prefix_rd2str (struct prefix_rd *, char *, size_t); diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c new file mode 100644 index 0000000..a22b7a1 --- /dev/null +++ b/bgpd/bgp_network.c @@ -0,0 +1,410 @@ +/* BGP network related fucntions + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "thread.h" +#include "sockunion.h" +#include "memory.h" +#include "log.h" +#include "if.h" +#include "prefix.h" +#include "command.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_network.h" + +#ifdef HAVE_TCP_SIGNATURE +#include "bgpd/bgp_tcpsig.h" +#endif /* HAVE_TCP_SIGNATURE */ + + +/* Accept bgp connection. */ +static int +bgp_accept (struct thread *thread) +{ + int bgp_sock; + int accept_sock; + union sockunion su; + struct peer *peer; + struct peer *peer1; + struct bgp *bgp; + char buf[SU_ADDRSTRLEN]; + + /* Regiser accept thread. */ + accept_sock = THREAD_FD (thread); + bgp = THREAD_ARG (thread); + + if (accept_sock < 0) + { + zlog_err ("accept_sock is nevative value %d", accept_sock); + return -1; + } + thread_add_read (master, bgp_accept, bgp, accept_sock); + + /* Accept client connection. */ + bgp_sock = sockunion_accept (accept_sock, &su); + if (bgp_sock < 0) + { + zlog_err ("[Error] BGP socket accept failed (%s)", strerror (errno)); + return -1; + } + + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); + + /* Check remote IP address */ + peer1 = peer_lookup (bgp, &su); + if (! peer1 || peer1->status == Idle) + { + if (BGP_DEBUG (events, EVENTS)) + { + if (! peer1) + zlog_info ("[Event] BGP connection IP address %s is not configured", + inet_sutop (&su, buf)); + else + zlog_info ("[Event] BGP connection IP address %s is Idle state", + inet_sutop (&su, buf)); + } + close (bgp_sock); + return -1; + } + + /* In case of peer is EBGP, we should set TTL for this connection. */ + if (peer_sort (peer1) == BGP_PEER_EBGP) + sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl); + + if (! bgp) + bgp = peer1->bgp; + + /* Make dummy peer until read Open packet. */ + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("[Event] Make dummy peer structure until read Open packet"); + + { + char buf[SU_ADDRSTRLEN + 1]; + + peer = peer_create_accept (bgp); + SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); + peer->su = su; + peer->fd = bgp_sock; + peer->status = Active; + peer->local_id = peer1->local_id; + + /* Make peer's address string. */ + sockunion2str (&su, buf, SU_ADDRSTRLEN); + peer->host = strdup (buf); + } + + BGP_EVENT_ADD (peer, TCP_connection_open); + + return 0; +} + +/* BGP socket bind. */ +int +bgp_bind (struct peer *peer) +{ +#ifdef SO_BINDTODEVICE + int ret; + struct ifreq ifreq; + + if (! peer->ifname) + return 0; + + strncpy ((char *)&ifreq.ifr_name, peer->ifname, sizeof (ifreq.ifr_name)); + + ret = setsockopt (peer->fd, SOL_SOCKET, SO_BINDTODEVICE, + &ifreq, sizeof (ifreq)); + if (ret < 0) + { + zlog (peer->log, LOG_INFO, "bind to interface %s failed", peer->ifname); + return ret; + } +#endif /* SO_BINDTODEVICE */ + return 0; +} + +int +bgp_bind_address (int sock, struct in_addr *addr) +{ + int ret; + struct sockaddr_in local; + + memset (&local, 0, sizeof (struct sockaddr_in)); + local.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + local.sin_len = sizeof(struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + memcpy (&local.sin_addr, addr, sizeof (struct in_addr)); + + ret = bind (sock, (struct sockaddr *)&local, sizeof (struct sockaddr_in)); + if (ret < 0) + ; + return 0; +} + +struct in_addr * +bgp_update_address (struct interface *ifp) +{ + struct prefix_ipv4 *p; + struct connected *connected; + listnode node; + + for (node = listhead (ifp->connected); node; nextnode (node)) + { + connected = getdata (node); + + p = (struct prefix_ipv4 *) connected->address; + + if (p->family == AF_INET) + return &p->prefix; + } + return NULL; +} + +/* Update source selection. */ +void +bgp_update_source (struct peer *peer) +{ + struct interface *ifp; + struct in_addr *addr; + + /* Source is specified with interface name. */ + if (peer->update_if) + { + ifp = if_lookup_by_name (peer->update_if); + if (! ifp) + return; + + addr = bgp_update_address (ifp); + if (! addr) + return; + + bgp_bind_address (peer->fd, addr); + } + + /* Source is specified with IP address. */ + if (peer->update_source) + sockunion_bind (peer->fd, peer->update_source, 0, peer->update_source); +} + +/* BGP try to connect to the peer. */ +int +bgp_connect (struct peer *peer) +{ + unsigned int ifindex = 0; + + /* Make socket for the peer. */ + peer->fd = sockunion_socket (&peer->su); + if (peer->fd < 0) + return -1; + + /* If we can get socket for the peer, adjest TTL and make connection. */ + if (peer_sort (peer) == BGP_PEER_EBGP) + sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); + + sockopt_reuseaddr (peer->fd); + sockopt_reuseport (peer->fd); + + /* Bind socket. */ + bgp_bind (peer); + + /* Update source bind. */ + bgp_update_source (peer); + +#ifdef HAVE_IPV6 + if (peer->ifname) + ifindex = if_nametoindex (peer->ifname); +#endif /* HAVE_IPV6 */ + + if (BGP_DEBUG (events, EVENTS)) + plog_info (peer->log, "%s [Event] Connect start to %s fd %d", + peer->host, peer->host, peer->fd); + +#ifdef HAVE_TCP_SIGNATURE + if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD)) + bgp_tcpsig_set (peer->fd, peer); +#endif /* HAVE_TCP_SIGNATURE */ + + /* Connect to the remote peer. */ + return sockunion_connect (peer->fd, &peer->su, htons (peer->port), ifindex); +} + +/* After TCP connection is established. Get local address and port. */ +void +bgp_getsockname (struct peer *peer) +{ + if (peer->su_local) + { + XFREE (MTYPE_TMP, peer->su_local); + peer->su_local = NULL; + } + + if (peer->su_remote) + { + XFREE (MTYPE_TMP, peer->su_remote); + peer->su_remote = NULL; + } + + peer->su_local = sockunion_getsockname (peer->fd); + peer->su_remote = sockunion_getpeername (peer->fd); + + bgp_nexthop_set (peer->su_local, peer->su_remote, &peer->nexthop, peer); +} + +/* IPv6 supported version of BGP server socket setup. */ +#if defined (HAVE_IPV6) && ! defined (NRL) +int +bgp_socket (struct bgp *bgp, unsigned short port) +{ + int ret; + struct addrinfo req; + struct addrinfo *ainfo; + struct addrinfo *ainfo_save; + int sock = 0; + char port_str[BUFSIZ]; + + memset (&req, 0, sizeof (struct addrinfo)); + + req.ai_flags = AI_PASSIVE; + req.ai_family = AF_UNSPEC; + req.ai_socktype = SOCK_STREAM; + sprintf (port_str, "%d", port); + port_str[sizeof (port_str) - 1] = '\0'; + + ret = getaddrinfo (NULL, port_str, &req, &ainfo); + if (ret != 0) + { + zlog_err ("getaddrinfo: %s", gai_strerror (ret)); + return -1; + } + + ainfo_save = ainfo; + + do + { + if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6) + continue; + + sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); + if (sock < 0) + { + zlog_err ("socket: %s", strerror (errno)); + continue; + } + + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); + + ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen); + if (ret < 0) + { + zlog_err ("bind: %s", strerror (errno)); + close (sock); + continue; + } + ret = listen (sock, 3); + if (ret < 0) + { + zlog_err ("listen: %s", strerror (errno)); + close (sock); + continue; + } + +#ifdef HAVE_TCP_SIGNATURE +#ifdef HAVE_LINUX_TCP_SIGNATURE + bm->sock = sock; +#endif /* HAVE_LINUX_TCP_SIGNATURE */ +#ifdef HAVE_OPENBSD_TCP_SIGNATURE + bgp_tcpsig_set (sock, 0); + bm->sock = -1; +#endif /* HAVE_OPENBSD_TCP_SIGNATURE */ +#endif /* HAVE_TCP_SIGNATURE */ + + thread_add_read (master, bgp_accept, bgp, sock); + } + while ((ainfo = ainfo->ai_next) != NULL); + + freeaddrinfo (ainfo_save); + + return sock; +} +#else +/* Traditional IPv4 only version. */ +int +bgp_socket (struct bgp *bgp, unsigned short port) +{ + int sock; + int socklen; + struct sockaddr_in sin; + int ret; + + sock = socket (AF_INET, SOCK_STREAM, 0); + if (sock < 0) + { + zlog_err ("socket: %s", strerror (errno)); + return sock; + } + + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); + + memset (&sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = htons (port); + socklen = sizeof (struct sockaddr_in); +#ifdef HAVE_SIN_LEN + sin.sin_len = socklen; +#endif /* HAVE_SIN_LEN */ + + ret = bind (sock, (struct sockaddr *) &sin, socklen); + if (ret < 0) + { + zlog_err ("bind: %s", strerror (errno)); + close (sock); + return ret; + } + ret = listen (sock, 3); + if (ret < 0) + { + zlog_err ("listen: %s", strerror (errno)); + close (sock); + return ret; + } +#ifdef HAVE_TCP_SIGNATURE +#ifdef HAVE_LINUX_TCP_SIGNATURE + bm->sock = sock; +#endif /* HAVE_LINUX_TCP_SIGNATURE */ +#ifdef HAVE_OPENBSD_TCP_SIGNATURE + bgp_tcpsig_set (sock, 0); + bm->sock = -1; +#endif /* HAVE_OPENBSD_TCP_SIGNATURE */ +#endif /* HAVE_TCP_SIGNATURE */ + + thread_add_read (bm->master, bgp_accept, bgp, sock); + + return sock; +} +#endif /* HAVE_IPV6 && !NRL */ diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h new file mode 100644 index 0000000..52e7836 --- /dev/null +++ b/bgpd/bgp_network.h @@ -0,0 +1,39 @@ +/* BGP network related header + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifdef HAVE_LINUX_TCP_SIGNATURE +/* setsockopt Number */ +#define TCP_MD5_AUTH 13 + +/* Commands (used in the structure passed from userland) */ +#define TCP_MD5_AUTH_ADD 1 +#define TCP_MD5_AUTH_DEL 2 + +struct tcp_rfc2385_cmd { + u_int8_t command; /* Command - Add/Delete */ + u_int32_t address; /* IPV4 address associated */ + u_int8_t keylen; /* MD5 Key len (do NOT assume 0 terminated ascii) */ + void *key; /* MD5 Key */ +}; +#endif /* HAVE_LINUX_TCP_SIGNATURE */ + +int bgp_socket (struct bgp *, unsigned short); +int bgp_connect (struct peer *); +void bgp_getsockname (struct peer *); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c new file mode 100644 index 0000000..d4b5ec6 --- /dev/null +++ b/bgpd/bgp_nexthop.c @@ -0,0 +1,1412 @@ +/* BGP nexthop scan + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "command.h" +#include "thread.h" +#include "prefix.h" +#include "zclient.h" +#include "stream.h" +#include "network.h" +#include "log.h" +#include "memory.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_damp.h" +#include "zebra/rib.h" +#include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */ + +struct bgp_nexthop_cache *zlookup_query (struct in_addr); +#ifdef HAVE_IPV6 +struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *); +#endif /* HAVE_IPV6 */ + +/* Only one BGP scan thread are activated at the same time. */ +struct thread *bgp_scan_thread = NULL; + +/* BGP import thread */ +struct thread *bgp_import_thread = NULL; + +/* BGP scan interval. */ +int bgp_scan_interval; + +/* BGP import interval. */ +int bgp_import_interval; + +/* Route table for next-hop lookup cache. */ +struct bgp_table *bgp_nexthop_cache_ipv4; +struct bgp_table *cache1; +struct bgp_table *cache2; + +/* Route table for next-hop lookup cache. */ +struct bgp_table *bgp_nexthop_cache_ipv6; +struct bgp_table *cache6_1; +struct bgp_table *cache6_2; + +/* Route table for connected route. */ +struct bgp_table *bgp_connected_ipv4; + +/* Route table for connected route. */ +struct bgp_table *bgp_connected_ipv6; + +/* BGP nexthop lookup query client. */ +static struct zclient *zlookup = NULL; + +/* BGP process function. */ +int bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t); + +/* Add nexthop to the end of the list. */ +void +bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop) +{ + struct nexthop *last; + + for (last = bnc->nexthop; last && last->next; last = last->next) + ; + if (last) + last->next = nexthop; + else + bnc->nexthop = nexthop; + nexthop->prev = last; +} + +void +bnc_nexthop_free (struct bgp_nexthop_cache *bnc) +{ + struct nexthop *nexthop; + struct nexthop *next = NULL; + + for (nexthop = bnc->nexthop; nexthop; nexthop = next) + { + next = nexthop->next; + XFREE (MTYPE_NEXTHOP, nexthop); + } +} + +struct bgp_nexthop_cache * +bnc_new () +{ + struct bgp_nexthop_cache *new; + + new = XMALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache)); + memset (new, 0, sizeof (struct bgp_nexthop_cache)); + return new; +} + +void +bnc_free (struct bgp_nexthop_cache *bnc) +{ + bnc_nexthop_free (bnc); + XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc); +} + +int +bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2) +{ + if (next1->type != next2->type) + return 0; + + switch (next1->type) + { + case ZEBRA_NEXTHOP_IPV4: + if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4)) + return 0; + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + if (next1->ifindex != next2->ifindex) + return 0; + break; +#ifdef HAVE_IPV6 + case ZEBRA_NEXTHOP_IPV6: + if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) + return 0; + break; + case ZEBRA_NEXTHOP_IPV6_IFINDEX: + case ZEBRA_NEXTHOP_IPV6_IFNAME: + if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) + return 0; + if (next1->ifindex != next2->ifindex) + return 0; + break; +#endif /* HAVE_IPV6 */ + } + return 1; +} + +int +bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1, + struct bgp_nexthop_cache *bnc2) +{ + int i; + struct nexthop *next1, *next2; + + if (bnc1->nexthop_num != bnc2->nexthop_num) + return 1; + + next1 = bnc1->nexthop; + next2 = bnc2->nexthop; + + for (i = 0; i < bnc1->nexthop_num; i++) + { + if (! bgp_nexthop_same (next1, next2)) + return 1; + + next1 = next1->next; + next2 = next2->next; + } + return 0; +} + +/* If nexthop exists on connected network return 1. */ +int +bgp_nexthop_check_ebgp (afi_t afi, struct attr *attr) +{ + struct bgp_node *rn; + + /* If zebra is not enabled return */ + if (zlookup->sock < 0) + return 1; + + /* Lookup the address is onlink or not. */ + if (afi == AFI_IP) + { + rn = bgp_node_match_ipv4 (bgp_connected_ipv4, &attr->nexthop); + if (rn) + { + bgp_unlock_node (rn); + return 1; + } + } +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + { + if (attr->mp_nexthop_len == 32) + return 1; + else if (attr->mp_nexthop_len == 16) + { + if (IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_global)) + return 1; + + rn = bgp_node_match_ipv6 (bgp_connected_ipv6, + &attr->mp_nexthop_global); + if (rn) + { + bgp_unlock_node (rn); + return 1; + } + } + } +#endif /* HAVE_IPV6 */ + return 0; +} + +#ifdef HAVE_IPV6 +/* Check specified next-hop is reachable or not. */ +int +bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, + int *metricchanged) +{ + struct bgp_node *rn; + struct prefix p; + struct bgp_nexthop_cache *bnc; + struct attr *attr; + + /* If lookup is not enabled, return valid. */ + if (zlookup->sock < 0) + { + ri->igpmetric = 0; + return 1; + } + + /* Only check IPv6 global address only nexthop. */ + attr = ri->attr; + + if (attr->mp_nexthop_len != 16 + || IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_global)) + return 1; + + memset (&p, 0, sizeof (struct prefix)); + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_BITLEN; + p.u.prefix6 = attr->mp_nexthop_global; + + /* IBGP or ebgp-multihop */ + rn = bgp_node_get (bgp_nexthop_cache_ipv6, &p); + + if (rn->info) + { + bnc = rn->info; + bgp_unlock_node (rn); + } + else + { + bnc = zlookup_query_ipv6 (&attr->mp_nexthop_global); + if (bnc) + { + struct bgp_table *old; + struct bgp_node *oldrn; + struct bgp_nexthop_cache *oldbnc; + + if (changed) + { + if (bgp_nexthop_cache_ipv6 == cache6_1) + old = cache6_2; + else + old = cache6_1; + + oldrn = bgp_node_lookup (old, &p); + if (oldrn) + { + oldbnc = oldrn->info; + + bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); + + if (bnc->metric != oldbnc->metric) + bnc->metricchanged = 1; + } + } + } + else + { + bnc = bnc_new (); + bnc->valid = 0; + } + rn->info = bnc; + } + + if (changed) + *changed = bnc->changed; + + if (metricchanged) + *metricchanged = bnc->metricchanged; + + if (bnc->valid) + ri->igpmetric = bnc->metric; + else + ri->igpmetric = 0; + + return bnc->valid; +} +#endif /* HAVE_IPV6 */ + +/* Check specified next-hop is reachable or not. */ +int +bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, + int *changed, int *metricchanged) +{ + struct bgp_node *rn; + struct prefix p; + struct bgp_nexthop_cache *bnc; + struct in_addr addr; + + /* If lookup is not enabled, return valid. */ + if (zlookup->sock < 0) + { + ri->igpmetric = 0; + return 1; + } + +#ifdef HAVE_IPV6 + if (afi == AFI_IP6) + return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged); +#endif /* HAVE_IPV6 */ + + addr = ri->attr->nexthop; + + memset (&p, 0, sizeof (struct prefix)); + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = addr; + + /* IBGP or ebgp-multihop */ + rn = bgp_node_get (bgp_nexthop_cache_ipv4, &p); + + if (rn->info) + { + bnc = rn->info; + bgp_unlock_node (rn); + } + else + { + bnc = zlookup_query (addr); + if (bnc) + { + struct bgp_table *old; + struct bgp_node *oldrn; + struct bgp_nexthop_cache *oldbnc; + + if (changed) + { + if (bgp_nexthop_cache_ipv4 == cache1) + old = cache2; + else + old = cache1; + + oldrn = bgp_node_lookup (old, &p); + if (oldrn) + { + oldbnc = oldrn->info; + + bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); + + if (bnc->metric != oldbnc->metric) + bnc->metricchanged = 1; + } + } + } + else + { + bnc = bnc_new (); + bnc->valid = 0; + } + rn->info = bnc; + } + + if (changed) + *changed = bnc->changed; + + if (metricchanged) + *metricchanged = bnc->metricchanged; + + if (bnc->valid) + ri->igpmetric = bnc->metric; + else + ri->igpmetric = 0; + + return bnc->valid; +} + +/* Reset and free all BGP nexthop cache. */ +void +bgp_nexthop_cache_reset (struct bgp_table *table) +{ + struct bgp_node *rn; + struct bgp_nexthop_cache *bnc; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + if ((bnc = rn->info) != NULL) + { + bnc_free (bnc); + rn->info = NULL; + bgp_unlock_node (rn); + } +} + +void +bgp_scan_ipv4 () +{ + struct bgp_node *rn; + struct bgp *bgp; + struct bgp_info *bi; + struct bgp_info *next; + struct peer *peer; + struct listnode *nn; + int valid; + int current; + int changed; + int metricchanged; + + /* Change cache. */ + if (bgp_nexthop_cache_ipv4 == cache1) + bgp_nexthop_cache_ipv4 = cache2; + else + bgp_nexthop_cache_ipv4 = cache1; + + /* Get default bgp. */ + bgp = bgp_get_default (); + if (bgp == NULL) + return; + + /* Maximum prefix check */ + LIST_LOOP (bgp->peer, peer, nn) + { + if (peer->status != Established) + continue; + + if (peer->afc[AFI_IP][SAFI_UNICAST]) + bgp_maximum_prefix_overflow (peer, AFI_IP, SAFI_UNICAST, 1); + if (peer->afc[AFI_IP][SAFI_MULTICAST]) + bgp_maximum_prefix_overflow (peer, AFI_IP, SAFI_MULTICAST, 1); + if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) + bgp_maximum_prefix_overflow (peer, AFI_IP, SAFI_MPLS_VPN, 1); + } + + for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_UNICAST]); rn; + rn = bgp_route_next (rn)) + { + for (bi = rn->info; bi; bi = next) + { + next = bi->next; + + if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL) + { + changed = 0; + metricchanged = 0; + + if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1) + valid = bgp_nexthop_check_ebgp (AFI_IP, bi->attr); + else + valid = bgp_nexthop_lookup (AFI_IP, bi->peer, bi, + &changed, &metricchanged); + + current = CHECK_FLAG (bi->flags, BGP_INFO_VALID) ? 1 : 0; + + if (changed) + SET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); + else + UNSET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); + + if (valid != current) + { + if (CHECK_FLAG (bi->flags, BGP_INFO_VALID)) + { + bgp_aggregate_decrement (bgp, &rn->p, bi, + AFI_IP, SAFI_UNICAST); + UNSET_FLAG (bi->flags, BGP_INFO_VALID); + } + else + { + SET_FLAG (bi->flags, BGP_INFO_VALID); + bgp_aggregate_increment (bgp, &rn->p, bi, + AFI_IP, SAFI_UNICAST); + } + } + + if (CHECK_FLAG (bgp->af_flags[AFI_IP][SAFI_UNICAST], + BGP_CONFIG_DAMPENING) + && bi->damp_info ) + if (bgp_damp_scan (bi, AFI_IP, SAFI_UNICAST)) + bgp_aggregate_increment (bgp, &rn->p, bi, + AFI_IP, SAFI_UNICAST); + } + } + bgp_process (bgp, rn, AFI_IP, SAFI_UNICAST); + } + + /* Flash old cache. */ + if (bgp_nexthop_cache_ipv4 == cache1) + bgp_nexthop_cache_reset (cache2); + else + bgp_nexthop_cache_reset (cache1); + + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("scanning IPv4 Unicast routing tables"); +} + +#ifdef HAVE_IPV6 +void +bgp_scan_ipv6 () +{ + struct bgp_node *rn; + struct bgp *bgp; + struct bgp_info *bi; + struct bgp_info *next; + struct peer *peer; + struct listnode *nn; + int valid; + int current; + int changed; + int metricchanged; + + /* Change cache. */ + if (bgp_nexthop_cache_ipv6 == cache6_1) + bgp_nexthop_cache_ipv6 = cache6_2; + else + bgp_nexthop_cache_ipv6 = cache6_1; + + /* Get default bgp. */ + bgp = bgp_get_default (); + if (bgp == NULL) + return; + + /* Maximum prefix check */ + LIST_LOOP (bgp->peer, peer, nn) + { + if (peer->status != Established) + continue; + + if (peer->afc[AFI_IP6][SAFI_UNICAST]) + bgp_maximum_prefix_overflow (peer, AFI_IP6, SAFI_UNICAST, 1); + if (peer->afc[AFI_IP6][SAFI_MULTICAST]) + bgp_maximum_prefix_overflow (peer, AFI_IP6, SAFI_MULTICAST, 1); + } + + for (rn = bgp_table_top (bgp->rib[AFI_IP6][SAFI_UNICAST]); rn; + rn = bgp_route_next (rn)) + { + for (bi = rn->info; bi; bi = next) + { + next = bi->next; + + if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL) + { + changed = 0; + metricchanged = 0; + + if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1) + valid = 1; + else + valid = bgp_nexthop_lookup_ipv6 (bi->peer, bi, + &changed, &metricchanged); + + current = CHECK_FLAG (bi->flags, BGP_INFO_VALID) ? 1 : 0; + + if (changed) + SET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); + else + UNSET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); + + if (valid != current) + { + if (CHECK_FLAG (bi->flags, BGP_INFO_VALID)) + { + bgp_aggregate_decrement (bgp, &rn->p, bi, + AFI_IP6, SAFI_UNICAST); + UNSET_FLAG (bi->flags, BGP_INFO_VALID); + } + else + { + SET_FLAG (bi->flags, BGP_INFO_VALID); + bgp_aggregate_increment (bgp, &rn->p, bi, + AFI_IP6, SAFI_UNICAST); + } + } + + if (CHECK_FLAG (bgp->af_flags[AFI_IP6][SAFI_UNICAST], + BGP_CONFIG_DAMPENING) + && bi->damp_info ) + if (bgp_damp_scan (bi, AFI_IP6, SAFI_UNICAST)) + bgp_aggregate_increment (bgp, &rn->p, bi, + AFI_IP6, SAFI_UNICAST); + } + } + bgp_process (bgp, rn, AFI_IP6, SAFI_UNICAST); + } + + /* Flash old cache. */ + if (bgp_nexthop_cache_ipv6 == cache6_1) + bgp_nexthop_cache_reset (cache6_2); + else + bgp_nexthop_cache_reset (cache6_1); + + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("scanning IPv6 Unicast routing tables"); +} +#endif /* HAVE_IPV6 */ + +/* BGP scan thread. This thread check nexthop reachability. */ +int +bgp_scan (struct thread *t) +{ + bgp_scan_thread = + thread_add_timer (master, bgp_scan, NULL, bgp_scan_interval); + + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("Performing BGP general scanning"); + + bgp_scan_ipv4 (); + +#ifdef HAVE_IPV6 + bgp_scan_ipv6 (); +#endif /* HAVE_IPV6 */ + + return 0; +} + +struct bgp_connected +{ + unsigned int refcnt; +}; + +void +bgp_connected_add (struct connected *ifc) +{ + struct prefix p; + struct prefix *addr; + struct prefix *dest; + struct interface *ifp; + struct bgp_node *rn; + struct bgp_connected *bc; + + ifp = ifc->ifp; + + if (! ifp) + return; + + if (if_is_loopback (ifp)) + return; + + addr = ifc->address; + dest = ifc->destination; + + if (addr->family == AF_INET) + { + memset (&p, 0, sizeof (struct prefix)); + p.family = AF_INET; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp)) + p.u.prefix4 = dest->u.prefix4; + else + p.u.prefix4 = addr->u.prefix4; + + apply_mask_ipv4 ((struct prefix_ipv4 *) &p); + + if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) + return; + + rn = bgp_node_get (bgp_connected_ipv4, (struct prefix *) &p); + if (rn->info) + { + bc = rn->info; + bc->refcnt++; + } + else + { + bc = XMALLOC (0, sizeof (struct bgp_connected)); + memset (bc, 0, sizeof (struct bgp_connected)); + bc->refcnt = 1; + rn->info = bc; + } + } +#ifdef HAVE_IPV6 + if (addr->family == AF_INET6) + { + memset (&p, 0, sizeof (struct prefix)); + p.family = AF_INET6; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp)) + p.u.prefix6 = dest->u.prefix6; + else + p.u.prefix6 = addr->u.prefix6; + + apply_mask_ipv6 ((struct prefix_ipv6 *) &p); + + if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) + return; + + if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) + return; + + rn = bgp_node_get (bgp_connected_ipv6, (struct prefix *) &p); + if (rn->info) + { + bc = rn->info; + bc->refcnt++; + } + else + { + bc = XMALLOC (0, sizeof (struct bgp_connected)); + memset (bc, 0, sizeof (struct bgp_connected)); + bc->refcnt = 1; + rn->info = bc; + } + } +#endif /* HAVE_IPV6 */ +} + +void +bgp_connected_delete (struct connected *ifc) +{ + struct prefix p; + struct prefix *addr; + struct prefix *dest; + struct interface *ifp; + struct bgp_node *rn; + struct bgp_connected *bc; + + ifp = ifc->ifp; + + if (if_is_loopback (ifp)) + return; + + addr = ifc->address; + dest = ifc->destination; + + if (addr->family == AF_INET) + { + memset (&p, 0, sizeof (struct prefix)); + p.family = AF_INET; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp)) + p.u.prefix4 = dest->u.prefix4; + else + p.u.prefix4 = addr->u.prefix4; + + apply_mask_ipv4 ((struct prefix_ipv4 *) &p); + + if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) + return; + + rn = bgp_node_lookup (bgp_connected_ipv4, &p); + if (! rn) + return; + + bc = rn->info; + bc->refcnt--; + if (bc->refcnt == 0) + { + XFREE (0, bc); + rn->info = NULL; + } + bgp_unlock_node (rn); + bgp_unlock_node (rn); + } +#ifdef HAVE_IPV6 + else if (addr->family == AF_INET6) + { + memset (&p, 0, sizeof (struct prefix)); + p.family = AF_INET6; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp)) + p.u.prefix6 = dest->u.prefix6; + else + p.u.prefix6 = addr->u.prefix6; + + apply_mask_ipv6 ((struct prefix_ipv6 *) &p); + + if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) + return; + + if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) + return; + + rn = bgp_node_lookup (bgp_connected_ipv6, (struct prefix *) &p); + if (! rn) + return; + + bc = rn->info; + bc->refcnt--; + if (bc->refcnt == 0) + { + XFREE (0, bc); + rn->info = NULL; + } + bgp_unlock_node (rn); + bgp_unlock_node (rn); + } +#endif /* HAVE_IPV6 */ +} + +int +bgp_nexthop_self (afi_t afi, struct attr *attr) +{ + listnode node; + listnode node2; + struct interface *ifp; + struct connected *ifc; + struct prefix *p; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + for (node2 = listhead (ifp->connected); node2; nextnode (node2)) + { + ifc = getdata (node2); + p = ifc->address; + + if (p && p->family == AF_INET + && IPV4_ADDR_SAME (&p->u.prefix4, &attr->nexthop)) + return 1; + } + } + return 0; +} + +struct bgp_nexthop_cache * +zlookup_read () +{ + struct stream *s; + u_int16_t length; + u_char command; + int nbytes; + struct in_addr raddr; + u_int32_t metric; + int i; + u_char nexthop_num; + struct nexthop *nexthop; + struct bgp_nexthop_cache *bnc; + + s = zlookup->ibuf; + stream_reset (s); + + nbytes = stream_read (s, zlookup->sock, 2); + length = stream_getw (s); + + nbytes = stream_read (s, zlookup->sock, length - 2); + command = stream_getc (s); + raddr.s_addr = stream_get_ipv4 (s); + metric = stream_getl (s); + nexthop_num = stream_getc (s); + + if (nexthop_num) + { + bnc = bnc_new (); + bnc->valid = 1; + bnc->metric = metric; + bnc->nexthop_num = nexthop_num; + + for (i = 0; i < nexthop_num; i++) + { + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = stream_getc (s); + switch (nexthop->type) + { + case ZEBRA_NEXTHOP_IPV4: + nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + nexthop->ifindex = stream_getl (s); + break; + } + bnc_nexthop_add (bnc, nexthop); + } + } + else + return NULL; + + return bnc; +} + +struct bgp_nexthop_cache * +zlookup_query (struct in_addr addr) +{ + int ret; + struct stream *s; + + /* Check socket. */ + if (zlookup->sock < 0) + return NULL; + + s = zlookup->obuf; + stream_reset (s); + stream_putw (s, 7); + stream_putc (s, ZEBRA_IPV4_NEXTHOP_LOOKUP); + stream_put_in_addr (s, &addr); + + ret = writen (zlookup->sock, s->data, 7); + if (ret < 0) + { + zlog_err ("can't write to zlookup->sock"); + close (zlookup->sock); + zlookup->sock = -1; + return NULL; + } + if (ret == 0) + { + zlog_err ("zlookup->sock connection closed"); + close (zlookup->sock); + zlookup->sock = -1; + return NULL; + } + + return zlookup_read (); +} + +#ifdef HAVE_IPV6 +struct bgp_nexthop_cache * +zlookup_read_ipv6 () +{ + struct stream *s; + u_int16_t length; + u_char command; + int nbytes; + struct in6_addr raddr; + u_int32_t metric; + int i; + u_char nexthop_num; + struct nexthop *nexthop; + struct bgp_nexthop_cache *bnc; + + s = zlookup->ibuf; + stream_reset (s); + + nbytes = stream_read (s, zlookup->sock, 2); + length = stream_getw (s); + + nbytes = stream_read (s, zlookup->sock, length - 2); + command = stream_getc (s); + + stream_get (&raddr, s, 16); + + metric = stream_getl (s); + nexthop_num = stream_getc (s); + + if (nexthop_num) + { + bnc = bnc_new (); + bnc->valid = 1; + bnc->metric = metric; + bnc->nexthop_num = nexthop_num; + + for (i = 0; i < nexthop_num; i++) + { + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = stream_getc (s); + switch (nexthop->type) + { + case ZEBRA_NEXTHOP_IPV6: + stream_get (&nexthop->gate.ipv6, s, 16); + break; + case ZEBRA_NEXTHOP_IPV6_IFINDEX: + case ZEBRA_NEXTHOP_IPV6_IFNAME: + stream_get (&nexthop->gate.ipv6, s, 16); + nexthop->ifindex = stream_getl (s); + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + nexthop->ifindex = stream_getl (s); + break; + } + bnc_nexthop_add (bnc, nexthop); + } + } + else + return NULL; + + return bnc; +} + +struct bgp_nexthop_cache * +zlookup_query_ipv6 (struct in6_addr *addr) +{ + int ret; + struct stream *s; + + /* Check socket. */ + if (zlookup->sock < 0) + return NULL; + + s = zlookup->obuf; + stream_reset (s); + stream_putw (s, 19); + stream_putc (s, ZEBRA_IPV6_NEXTHOP_LOOKUP); + stream_put (s, addr, 16); + + ret = writen (zlookup->sock, s->data, 19); + if (ret < 0) + { + zlog_err ("can't write to zlookup->sock"); + close (zlookup->sock); + zlookup->sock = -1; + return NULL; + } + if (ret == 0) + { + zlog_err ("zlookup->sock connection closed"); + close (zlookup->sock); + zlookup->sock = -1; + return NULL; + } + + return zlookup_read_ipv6 (); +} +#endif /* HAVE_IPV6 */ + +int +bgp_import_check (struct prefix *p, u_int32_t *igpmetric, struct in_addr *igpnexthop) +{ + struct stream *s; + int ret; + u_int16_t length; + u_char command; + int nbytes; + struct in_addr addr; + struct in_addr nexthop; + u_int32_t metric = 0; + u_char nexthop_num; + u_char nexthop_type; + + /* If lookup connection is not available return valid. */ + if (zlookup->sock < 0) + { + if (igpmetric) + *igpmetric = 0; + return 1; + } + + /* Send query to the lookup connection */ + s = zlookup->obuf; + stream_reset (s); + stream_putw (s, 8); + stream_putc (s, ZEBRA_IPV4_IMPORT_LOOKUP); + stream_putc (s, p->prefixlen); + stream_put_in_addr (s, &p->u.prefix4); + + /* Write the packet. */ + ret = writen (zlookup->sock, s->data, 8); + + if (ret < 0) + { + zlog_err ("can't write to zlookup->sock"); + close (zlookup->sock); + zlookup->sock = -1; + return 1; + } + if (ret == 0) + { + zlog_err ("zlookup->sock connection closed"); + close (zlookup->sock); + zlookup->sock = -1; + return 1; + } + + /* Get result. */ + stream_reset (s); + + /* Fetch length. */ + nbytes = stream_read (s, zlookup->sock, 2); + length = stream_getw (s); + + /* Fetch whole data. */ + nbytes = stream_read (s, zlookup->sock, length - 2); + command = stream_getc (s); + addr.s_addr = stream_get_ipv4 (s); + metric = stream_getl (s); + nexthop_num = stream_getc (s); + + /* Set IGP metric value. */ + if (igpmetric) + *igpmetric = metric; + + /* If there is nexthop then this is active route. */ + if (nexthop_num) + { + nexthop.s_addr = 0; + nexthop_type = stream_getc (s); + if (nexthop_type == ZEBRA_NEXTHOP_IPV4) + { + nexthop.s_addr = stream_get_ipv4 (s); + if (igpnexthop) + *igpnexthop = nexthop; + } + else + *igpnexthop = nexthop; + + return 1; + } + else + return 0; +} + +/* Scan all configured BGP route then check the route exists in IGP or + not. */ +int +bgp_import (struct thread *t) +{ + struct bgp *bgp; + struct bgp_node *rn; + struct bgp_static *bgp_static; + struct listnode *nn; + int valid; + u_int32_t metric; + struct in_addr nexthop; + afi_t afi; + safi_t safi; + + bgp_import_thread = + thread_add_timer (master, bgp_import, NULL, bgp_import_interval); + + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("Import timer expired."); + + LIST_LOOP (bm->bgp, bgp, nn) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MPLS_VPN; safi++) + for (rn = bgp_table_top (bgp->route[afi][safi]); rn; + rn = bgp_route_next (rn)) + if ((bgp_static = rn->info) != NULL) + { + if (bgp_static->backdoor) + continue; + + valid = bgp_static->valid; + metric = bgp_static->igpmetric; + nexthop = bgp_static->igpnexthop; + + if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK) + && afi == AFI_IP && safi == SAFI_UNICAST) + bgp_static->valid = bgp_import_check (&rn->p, &bgp_static->igpmetric, + &bgp_static->igpnexthop); + else + { + bgp_static->valid = 1; + bgp_static->igpmetric = 0; + bgp_static->igpnexthop.s_addr = 0; + } + + if (bgp_static->valid != valid) + { + if (bgp_static->valid) + bgp_static_update (bgp, &rn->p, bgp_static, afi, safi); + else + bgp_static_withdraw (bgp, &rn->p, afi, safi); + } + else if (bgp_static->valid) + { + if (bgp_static->igpmetric != metric + || bgp_static->igpnexthop.s_addr != nexthop.s_addr + || bgp_static->rmap.name) + bgp_static_update (bgp, &rn->p, bgp_static, afi, safi); + } + } + } + return 0; +} + +/* Connect to zebra for nexthop lookup. */ +int +zlookup_connect (struct thread *t) +{ + struct zclient *zlookup; + + zlookup = THREAD_ARG (t); + zlookup->t_connect = NULL; + + if (zlookup->sock != -1) + return 0; + +#ifdef HAVE_TCP_ZEBRA + zlookup->sock = zclient_socket (); +#else + zlookup->sock = zclient_socket_un (ZEBRA_SERV_PATH); +#endif /* HAVE_TCP_ZEBRA */ + if (zlookup->sock < 0) + return -1; + + return 0; +} + +/* Check specified multiaccess next-hop. */ +int +bgp_multiaccess_check_v4 (struct in_addr nexthop, char *peer) +{ + struct bgp_node *rn1; + struct bgp_node *rn2; + struct prefix p1; + struct prefix p2; + struct in_addr addr; + int ret; + + ret = inet_aton (peer, &addr); + if (! ret) + return 0; + + memset (&p1, 0, sizeof (struct prefix)); + p1.family = AF_INET; + p1.prefixlen = IPV4_MAX_BITLEN; + p1.u.prefix4 = nexthop; + memset (&p2, 0, sizeof (struct prefix)); + p2.family = AF_INET; + p2.prefixlen = IPV4_MAX_BITLEN; + p2.u.prefix4 = addr; + + /* If bgp scan is not enabled, return invalid. */ + if (zlookup->sock < 0) + return 0; + + rn1 = bgp_node_match (bgp_connected_ipv4, &p1); + if (! rn1) + return 0; + + rn2 = bgp_node_match (bgp_connected_ipv4, &p2); + if (! rn2) + return 0; + + if (rn1 == rn2) + return 1; + + return 0; +} + +DEFUN (bgp_scan_time, + bgp_scan_time_cmd, + "bgp scan-time <5-60>", + "BGP specific commands\n" + "Configure background scanner interval\n" + "Scanner interval (seconds)\n") +{ + bgp_scan_interval = atoi (argv[0]); + + if (bgp_scan_thread) + { + thread_cancel (bgp_scan_thread); + bgp_scan_thread = + thread_add_timer (master, bgp_scan, NULL, bgp_scan_interval); + } + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_scan_time, + no_bgp_scan_time_cmd, + "no bgp scan-time", + NO_STR + "BGP specific commands\n" + "Configure background scanner interval\n") +{ + bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; + + if (bgp_scan_thread) + { + thread_cancel (bgp_scan_thread); + bgp_scan_thread = + thread_add_timer (master, bgp_scan, NULL, bgp_scan_interval); + } + + return CMD_SUCCESS; +} + +ALIAS (no_bgp_scan_time, + no_bgp_scan_time_val_cmd, + "no bgp scan-time <5-60>", + NO_STR + "BGP specific commands\n" + "Configure background scanner interval\n" + "Scanner interval (seconds)\n"); + +DEFUN (show_ip_bgp_scan, + show_ip_bgp_scan_cmd, + "show ip bgp scan", + SHOW_STR + IP_STR + BGP_STR + "BGP scan status\n") +{ + struct bgp_node *rn; + struct bgp_nexthop_cache *bnc; + + if (bgp_scan_thread) + vty_out (vty, "BGP scan is running%s", VTY_NEWLINE); + else + vty_out (vty, "BGP scan is not running%s", VTY_NEWLINE); + vty_out (vty, "BGP scan interval is %d%s", bgp_scan_interval, VTY_NEWLINE); + + vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE); + for (rn = bgp_table_top (bgp_nexthop_cache_ipv4); rn; rn = bgp_route_next (rn)) + if ((bnc = rn->info) != NULL) + { + if (bnc->valid) + vty_out (vty, " %s valid [IGP metric %d]%s", + inet_ntoa (rn->p.u.prefix4), bnc->metric, VTY_NEWLINE); + else + vty_out (vty, " %s invalid%s", + inet_ntoa (rn->p.u.prefix4), VTY_NEWLINE); + } + +#ifdef HAVE_IPV6 + { + char buf[BUFSIZ]; + for (rn = bgp_table_top (bgp_nexthop_cache_ipv6); rn; rn = bgp_route_next (rn)) + if ((bnc = rn->info) != NULL) + { + if (bnc->valid) + vty_out (vty, " %s valid [IGP metric %d]%s", + inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), + bnc->metric, VTY_NEWLINE); + else + vty_out (vty, " %s invalid%s", + inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), + VTY_NEWLINE); + } + } +#endif /* HAVE_IPV6 */ + + vty_out (vty, "BGP connected route:%s", VTY_NEWLINE); + for (rn = bgp_table_top (bgp_connected_ipv4); rn; rn = bgp_route_next (rn)) + if (rn->info != NULL) + vty_out (vty, " %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + VTY_NEWLINE); + +#ifdef HAVE_IPV6 + { + char buf[BUFSIZ]; + + for (rn = bgp_table_top (bgp_connected_ipv6); rn; rn = bgp_route_next (rn)) + if (rn->info != NULL) + vty_out (vty, " %s/%d%s", + inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), + rn->p.prefixlen, + VTY_NEWLINE); + } +#endif /* HAVE_IPV6 */ + + return CMD_SUCCESS; +} + +int +bgp_config_write_scan_time (struct vty *vty) +{ + if (bgp_scan_interval != BGP_SCAN_INTERVAL_DEFAULT) + vty_out (vty, " bgp scan-time %d%s", bgp_scan_interval, VTY_NEWLINE); + return CMD_SUCCESS; +} + +void +bgp_scan_init () +{ + zlookup = zclient_new (); + zlookup->sock = -1; + zlookup->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); + zlookup->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); + zlookup->t_connect = thread_add_event (master, zlookup_connect, zlookup, 0); + + bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; + bgp_import_interval = BGP_IMPORT_INTERVAL_DEFAULT; + + cache1 = bgp_table_init (); + cache2 = bgp_table_init (); + bgp_nexthop_cache_ipv4 = cache1; + + bgp_connected_ipv4 = bgp_table_init (); + +#ifdef HAVE_IPV6 + cache6_1 = bgp_table_init (); + cache6_2 = bgp_table_init (); + bgp_nexthop_cache_ipv6 = cache6_1; + bgp_connected_ipv6 = bgp_table_init (); +#endif /* HAVE_IPV6 */ + + /* Make BGP scan thread. */ + bgp_scan_thread = thread_add_timer (master, bgp_scan, NULL, bgp_scan_interval); + /* Make BGP import there. */ + bgp_import_thread = thread_add_timer (master, bgp_import, NULL, 0); + + install_element (BGP_NODE, &bgp_scan_time_cmd); + install_element (BGP_NODE, &no_bgp_scan_time_cmd); + install_element (BGP_NODE, &no_bgp_scan_time_val_cmd); + install_element (VIEW_NODE, &show_ip_bgp_scan_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd); +} diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h new file mode 100644 index 0000000..5f4255d --- /dev/null +++ b/bgpd/bgp_nexthop.h @@ -0,0 +1,52 @@ +/* BGP nexthop scan + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#define BGP_SCAN_INTERVAL_DEFAULT 60 +#define BGP_IMPORT_INTERVAL_DEFAULT 15 + +/* BGP nexthop cache value structure. */ +struct bgp_nexthop_cache +{ + /* This nexthop exists in IGP. */ + u_char valid; + + /* Nexthop is changed. */ + u_char changed; + + /* Nexthop is changed. */ + u_char metricchanged; + + /* IGP route's metric. */ + u_int32_t metric; + + /* Nexthop number and nexthop linked list.*/ + u_char nexthop_num; + struct nexthop *nexthop; +}; + +void bgp_scan_init (); +int bgp_nexthop_lookup (afi_t, struct peer *peer, struct bgp_info *, + int *, int *); +void bgp_connected_add (struct connected *c); +void bgp_connected_delete (struct connected *c); +int bgp_multiaccess_check_v4 (struct in_addr, char *); +int bgp_config_write_scan_time (struct vty *); +int bgp_nexthop_check_ebgp (afi_t, struct attr *); +int bgp_nexthop_self (afi_t, struct attr *); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c new file mode 100644 index 0000000..8047eea --- /dev/null +++ b/bgpd/bgp_open.c @@ -0,0 +1,854 @@ +/* BGP open message handling + Copyright (C) 1998, 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "linklist.h" +#include "prefix.h" +#include "stream.h" +#include "thread.h" +#include "log.h" +#include "command.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_open.h" +#include "bgpd/bgp_vty.h" + +/* BGP-4 Multiprotocol Extentions lead us to the complex world. We can + negotiate remote peer supports extentions or not. But if + remote-peer doesn't supports negotiation process itself. We would + like to do manual configuration. + + So there is many configurable point. First of all we want set each + peer whether we send capability negotiation to the peer or not. + Next, if we send capability to the peer we want to set my capabilty + inforation at each peer. */ + +void +bgp_capability_vty_out (struct vty *vty, struct peer *peer) +{ + u_char *pnt; + u_char *end; + struct capability cap; + + pnt = peer->notify.data; + end = pnt + peer->notify.length; + + while (pnt < end) + { + memcpy(&cap, pnt, sizeof(struct capability)); + + if (pnt + 2 > end) + return; + if (pnt + (cap.length + 2) > end) + return; + + if (cap.code == CAPABILITY_CODE_MP) + { + vty_out (vty, " Capability error for: Multi protocol "); + + switch (ntohs (cap.mpc.afi)) + { + case AFI_IP: + vty_out (vty, "AFI IPv4, "); + break; + case AFI_IP6: + vty_out (vty, "AFI IPv6, "); + break; + default: + vty_out (vty, "AFI Unknown %d, ", ntohs (cap.mpc.afi)); + break; + } + switch (cap.mpc.safi) + { + case SAFI_UNICAST: + vty_out (vty, "SAFI Unicast"); + break; + case SAFI_MULTICAST: + vty_out (vty, "SAFI Multicast"); + break; + case SAFI_UNICAST_MULTICAST: + vty_out (vty, "SAFI Unicast Multicast"); + break; + case BGP_SAFI_VPNV4: + vty_out (vty, "SAFI MPLS-VPN"); + break; + default: + vty_out (vty, "SAFI Unknown %d ", cap.mpc.safi); + break; + } + vty_out (vty, "%s", VTY_NEWLINE); + } + else if (cap.code >= 128) + vty_out (vty, " Capability error: vendor specific capability code %d", + cap.code); + else + vty_out (vty, " Capability error: unknown capability code %d", + cap.code); + + pnt += cap.length + 2; + } +} + +/* Set negotiated capability value. */ +int +bgp_capability_mp (struct peer *peer, struct capability *cap) +{ + if (ntohs (cap->mpc.afi) == AFI_IP) + { + if (cap->mpc.safi == SAFI_UNICAST) + { + peer->afc_recv[AFI_IP][SAFI_UNICAST] = 1; + + if (peer->afc[AFI_IP][SAFI_UNICAST]) + peer->afc_nego[AFI_IP][SAFI_UNICAST] = 1; + else + return -1; + } + else if (cap->mpc.safi == SAFI_MULTICAST) + { + peer->afc_recv[AFI_IP][SAFI_MULTICAST] = 1; + + if (peer->afc[AFI_IP][SAFI_MULTICAST]) + peer->afc_nego[AFI_IP][SAFI_MULTICAST] = 1; + else + return -1; + } + else if (cap->mpc.safi == BGP_SAFI_VPNV4) + { + peer->afc_recv[AFI_IP][SAFI_MPLS_VPN] = 1; + + if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) + peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] = 1; + else + return -1; + } + else + return -1; + } +#ifdef HAVE_IPV6 + else if (ntohs (cap->mpc.afi) == AFI_IP6) + { + if (cap->mpc.safi == SAFI_UNICAST) + { + peer->afc_recv[AFI_IP6][SAFI_UNICAST] = 1; + + if (peer->afc[AFI_IP6][SAFI_UNICAST]) + peer->afc_nego[AFI_IP6][SAFI_UNICAST] = 1; + else + return -1; + } + else if (cap->mpc.safi == SAFI_MULTICAST) + { + peer->afc_recv[AFI_IP6][SAFI_MULTICAST] = 1; + + if (peer->afc[AFI_IP6][SAFI_MULTICAST]) + peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = 1; + else + return -1; + } + else + return -1; + } +#endif /* HAVE_IPV6 */ + else + { + /* Unknown Address Family. */ + return -1; + } + + return 0; +} + +void +bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi, + u_char type, u_char mode) +{ + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported", + peer->host, afi, safi, type, mode); +} + +int +bgp_capability_orf (struct peer *peer, struct capability *cap, + u_char *pnt) +{ + afi_t afi = ntohs(cap->mpc.afi); + safi_t safi = cap->mpc.safi; + u_char number_of_orfs; + u_char type; + u_char mode; + u_int16_t sm_cap = 0; /* capability send-mode receive */ + u_int16_t rm_cap = 0; /* capability receive-mode receive */ + int i; + + /* Check length. */ + if (cap->length < 7) + { + zlog_info ("%s ORF Capability length error %d", + peer->host, cap->length); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + return -1; + } + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s OPEN has ORF CAP(%s) for afi/safi: %u/%u", + peer->host, (cap->code == CAPABILITY_CODE_ORF ? + "new" : "old"), afi, safi); + + /* Check AFI and SAFI. */ + if ((afi != AFI_IP && afi != AFI_IP6) + || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST + && safi != BGP_SAFI_VPNV4)) + { + zlog_info ("%s Addr-family %d/%d not supported. Ignoring the ORF capability", + peer->host, afi, safi); + return -1; + } + + number_of_orfs = *pnt++; + + for (i = 0 ; i < number_of_orfs ; i++) + { + type = *pnt++; + mode = *pnt++; + + /* ORF Mode error check */ + if (mode != ORF_MODE_BOTH && mode != ORF_MODE_SEND + && mode != ORF_MODE_RECEIVE) + { + bgp_capability_orf_not_support (peer, afi, safi, type, mode); + continue; + } + + /* ORF Type and afi/safi error check */ + if (cap->code == CAPABILITY_CODE_ORF) + { + if (type == ORF_TYPE_PREFIX && + ((afi == AFI_IP && safi == SAFI_UNICAST) + || (afi == AFI_IP && safi == SAFI_MULTICAST) + || (afi == AFI_IP6 && safi == SAFI_UNICAST))) + { + sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV; + rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV; + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s OPEN has Prefixlist ORF(%d) capability as %s for afi/safi: %d/%d", + peer->host, ORF_TYPE_PREFIX, (mode == ORF_MODE_SEND ? "SEND" : + mode == ORF_MODE_RECEIVE ? "RECEIVE" : "BOTH") , afi, safi); + } + else + { + bgp_capability_orf_not_support (peer, afi, safi, type, mode); + continue; + } + } + else if (cap->code == CAPABILITY_CODE_ORF_OLD) + { + if (type == ORF_TYPE_PREFIX_OLD && + ((afi == AFI_IP && safi == SAFI_UNICAST) + || (afi == AFI_IP && safi == SAFI_MULTICAST) + || (afi == AFI_IP6 && safi == SAFI_UNICAST))) + { + sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV; + rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV; + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s OPEN has Prefixlist ORF(%d) capability as %s for afi/safi: %d/%d", + peer->host, ORF_TYPE_PREFIX_OLD, (mode == ORF_MODE_SEND ? "SEND" : + mode == ORF_MODE_RECEIVE ? "RECEIVE" : "BOTH") , afi, safi); + } + else + { + bgp_capability_orf_not_support (peer, afi, safi, type, mode); + continue; + } + } + else + { + bgp_capability_orf_not_support (peer, afi, safi, type, mode); + continue; + } + + switch (mode) + { + case ORF_MODE_BOTH: + SET_FLAG (peer->af_cap[afi][safi], sm_cap); + SET_FLAG (peer->af_cap[afi][safi], rm_cap); + break; + case ORF_MODE_SEND: + SET_FLAG (peer->af_cap[afi][safi], sm_cap); + break; + case ORF_MODE_RECEIVE: + SET_FLAG (peer->af_cap[afi][safi], rm_cap); + break; + } + } + return 0; +} + +/* Parse given capability. */ +int +bgp_capability_parse (struct peer *peer, u_char *pnt, u_char length, + u_char **error) +{ + int ret; + u_char *end; + struct capability cap; + + end = pnt + length; + + while (pnt < end) + { + afi_t afi; + safi_t safi; + + /* Fetch structure to the byte stream. */ + memcpy (&cap, pnt, sizeof (struct capability)); + + afi = ntohs(cap.mpc.afi); + safi = cap.mpc.safi; + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s OPEN has CAPABILITY code: %d, length %d", + peer->host, cap.code, cap.length); + + /* We need at least capability code and capability length. */ + if (pnt + 2 > end) + { + zlog_info ("%s Capability length error", peer->host); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + return -1; + } + + /* Capability length check. */ + if (pnt + (cap.length + 2) > end) + { + zlog_info ("%s Capability length error", peer->host); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + return -1; + } + + /* We know MP Capability Code. */ + if (cap.code == CAPABILITY_CODE_MP) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u", + peer->host, afi, safi); + + /* Ignore capability when override-capability is set. */ + if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) + { + /* Set negotiated value. */ + ret = bgp_capability_mp (peer, &cap); + + /* Unsupported Capability. */ + if (ret < 0) + { + /* Store return data. */ + memcpy (*error, &cap, cap.length + 2); + *error += cap.length + 2; + } + } + } + else if (cap.code == CAPABILITY_CODE_REFRESH + || cap.code == CAPABILITY_CODE_REFRESH_OLD) + { + /* Check length. */ + if (cap.length != CAPABILITY_CODE_REFRESH_LEN) + { + zlog_info ("%s Route Refresh Capability length error %d", + peer->host, cap.length); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + return -1; + } + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s OPEN has ROUTE-REFRESH capability(%s) for all address-families", + peer->host, + cap.code == CAPABILITY_CODE_REFRESH_OLD ? "old" : "new"); + + /* BGP refresh capability */ + if (cap.code == CAPABILITY_CODE_REFRESH_OLD) + SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); + else + SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); + } + else if (cap.code == CAPABILITY_CODE_ORF + || cap.code == CAPABILITY_CODE_ORF_OLD) + bgp_capability_orf (peer, &cap, pnt + sizeof (struct capability)); + else if (cap.code == CAPABILITY_CODE_RESTART) + { + struct graceful_restart_af graf; + u_int16_t restart_flag_time; + int restart_bit = 0; + u_char *restart_pnt; + u_char *restart_end; + + /* Check length. */ + if (cap.length < CAPABILITY_CODE_RESTART_LEN) + { + zlog_info ("%s Graceful Restart Capability length error %d", + peer->host, cap.length); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + return -1; + } + + SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV); + restart_flag_time = ntohs(cap.mpc.afi); + if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT)) + restart_bit = 1; + UNSET_FLAG (restart_flag_time, 0xF000); + peer->v_gr_restart = restart_flag_time; + + if (BGP_DEBUG (normal, NORMAL)) + { + zlog_info ("%s OPEN has Graceful Restart capability", peer->host); + zlog_info ("%s Peer has%srestarted. Restart Time : %d", + peer->host, restart_bit ? " " : " not ", + peer->v_gr_restart); + } + + restart_pnt = pnt + 4; + restart_end = pnt + cap.length + 2; + + while (restart_pnt < restart_end) + { + memcpy (&graf, restart_pnt, sizeof (struct graceful_restart_af)); + + afi = ntohs(graf.afi); + safi = graf.safi; + + if (CHECK_FLAG (graf.flag, RESTART_F_BIT)) + SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV); + + if (strcmp (afi_safi_print (afi, safi), "Unknown") == 0) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s Addr-family %d/%d(afi/safi) not supported. Ignore the Graceful Restart capability", + peer->host, afi, safi); + } + else if (! peer->afc[afi][safi]) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s Addr-family %d/%d(afi/safi) not enabled. Ignore the Graceful Restart capability", + peer->host, afi, safi); + } + else + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s Address family %s is%spreserved", peer->host, + afi_safi_print (afi, safi), + CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV) + ? " " : " not "); + + SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV); + } + restart_pnt += 4; + } + } + else if (cap.code == CAPABILITY_CODE_DYNAMIC) + { + /* Check length. */ + if (cap.length != CAPABILITY_CODE_DYNAMIC_LEN) + { + zlog_info ("%s Dynamic Capability length error %d", + peer->host, cap.length); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + return -1; + } + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s OPEN has DYNAMIC capability", peer->host); + + SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV); + } + else if (cap.code > 128) + { + /* We don't send Notification for unknown vendor specific + capabilities. It seems reasonable for now... */ + zlog_warn ("%s Vendor specific capability %d", + peer->host, cap.code); + } + else + { + zlog_warn ("%s unrecognized capability code: %d - ignored", + peer->host, cap.code); + memcpy (*error, &cap, cap.length + 2); + *error += cap.length + 2; + } + + pnt += cap.length + 2; + } + return 0; +} + +int +bgp_auth_parse (struct peer *peer, u_char *pnt, size_t length) +{ + bgp_notify_send (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_AUTH_FAILURE); + return -1; +} + +int +strict_capability_same (struct peer *peer) +{ + int i, j; + + for (i = AFI_IP; i < AFI_MAX; i++) + for (j = SAFI_UNICAST; j < SAFI_MAX; j++) + if (peer->afc[i][j] != peer->afc_nego[i][j]) + return 0; + return 1; +} + +/* Parse open option */ +int +bgp_open_option_parse (struct peer *peer, u_char length, int *capability) +{ + int ret; + u_char *end; + u_char opt_type; + u_char opt_length; + u_char *pnt; + u_char *error; + u_char error_data[BGP_MAX_PACKET_SIZE]; + + /* Fetch pointer. */ + pnt = stream_pnt (peer->ibuf); + + ret = 0; + opt_type = 0; + opt_length = 0; + end = pnt + length; + error = error_data; + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s rcv OPEN w/ OPTION parameter len: %u", + peer->host, length); + + while (pnt < end) + { + /* Check the length. */ + if (pnt + 2 > end) + { + zlog_info ("%s Option length error", peer->host); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + return -1; + } + + /* Fetch option type and length. */ + opt_type = *pnt++; + opt_length = *pnt++; + + /* Option length check. */ + if (pnt + opt_length > end) + { + zlog_info ("%s Option length error", peer->host); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + return -1; + } + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u", + peer->host, opt_type, + opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" : + opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown", + opt_length); + + switch (opt_type) + { + case BGP_OPEN_OPT_AUTH: + ret = bgp_auth_parse (peer, pnt, opt_length); + break; + case BGP_OPEN_OPT_CAP: + ret = bgp_capability_parse (peer, pnt, opt_length, &error); + *capability = 1; + break; + default: + bgp_notify_send (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNSUP_PARAM); + ret = -1; + break; + } + + /* Parse error. To accumulate all unsupported capability codes, + bgp_capability_parse does not return -1 when encounter + unsupported capability code. To detect that, please check + error and erro_data pointer, like below. */ + if (ret < 0) + return -1; + + /* Forward pointer. */ + pnt += opt_length; + } + + /* All OPEN option is parsed. Check capability when strict compare + flag is enabled.*/ + if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) + { + /* If Unsupported Capability exists. */ + if (error != error_data) + { + bgp_notify_send_with_data (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNSUP_CAPBL, + error_data, error - error_data); + return -1; + } + + /* Check local capability does not negotiated with remote + peer. */ + if (! strict_capability_same (peer)) + { + bgp_notify_send (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNSUP_CAPBL); + return -1; + } + } + + /* Check there is no common capability send Unsupported Capability + error. */ + if (*capability && ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) + { + if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] + && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST] + && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] + && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] + && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) + { + plog_err (peer->log, "%s [Error] No common capability", peer->host); + + if (error != error_data) + + bgp_notify_send_with_data (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNSUP_CAPBL, + error_data, error - error_data); + else + bgp_notify_send (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNSUP_CAPBL); + return -1; + } + } + return 0; +} + +void +bgp_open_capability_orf (struct stream *s, struct peer *peer, + afi_t afi, safi_t safi, u_char code) +{ + u_char cap_len; + u_char orf_len; + unsigned long capp; + unsigned long orfp; + unsigned long numberp; + int number_of_orfs = 0; + + if (safi == SAFI_MPLS_VPN) + safi = BGP_SAFI_VPNV4; + + stream_putc (s, BGP_OPEN_OPT_CAP); + capp = stream_get_putp (s); /* Set Capability Len Pointer */ + stream_putc (s, 0); /* Capability Length */ + stream_putc (s, code); /* Capability Code */ + orfp = stream_get_putp (s); /* Set ORF Len Pointer */ + stream_putc (s, 0); /* ORF Length */ + stream_putw (s, afi); + stream_putc (s, 0); + stream_putc (s, safi); + numberp = stream_get_putp (s); /* Set Number Pointer */ + stream_putc (s, 0); /* Number of ORFs */ + + /* Address Prefix ORF */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) + || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) + { + stream_putc (s, (code == CAPABILITY_CODE_ORF ? + ORF_TYPE_PREFIX : ORF_TYPE_PREFIX_OLD)); + + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) + && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) + { + SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV); + SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV); + stream_putc (s, ORF_MODE_BOTH); + } + else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)) + { + SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV); + stream_putc (s, ORF_MODE_SEND); + } + else + { + SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV); + stream_putc (s, ORF_MODE_RECEIVE); + } + number_of_orfs++; + } + + /* Total Number of ORFs. */ + stream_putc_at (s, numberp, number_of_orfs); + + /* Total ORF Len. */ + orf_len = stream_get_putp (s) - orfp - 1; + stream_putc_at (s, orfp, orf_len); + + /* Total Capability Len. */ + cap_len = stream_get_putp (s) - capp - 1; + stream_putc_at (s, capp, cap_len); +} + +/* Fill in capability open option to the packet. */ +void +bgp_open_capability (struct stream *s, struct peer *peer) +{ + u_char len; + unsigned long cp; + afi_t afi; + safi_t safi; + + /* Remember current pointer for Opt Parm Len. */ + cp = stream_get_putp (s); + + /* Opt Parm Len. */ + stream_putc (s, 0); + + /* Do not send capability. */ + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN) + || CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY)) + return; + + /* IPv4 unicast. */ + if (peer->afc[AFI_IP][SAFI_UNICAST]) + { + peer->afc_adv[AFI_IP][SAFI_UNICAST] = 1; + stream_putc (s, BGP_OPEN_OPT_CAP); + stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); + stream_putc (s, CAPABILITY_CODE_MP); + stream_putc (s, CAPABILITY_CODE_MP_LEN); + stream_putw (s, AFI_IP); + stream_putc (s, 0); + stream_putc (s, SAFI_UNICAST); + } + /* IPv4 multicast. */ + if (peer->afc[AFI_IP][SAFI_MULTICAST]) + { + peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 1; + stream_putc (s, BGP_OPEN_OPT_CAP); + stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); + stream_putc (s, CAPABILITY_CODE_MP); + stream_putc (s, CAPABILITY_CODE_MP_LEN); + stream_putw (s, AFI_IP); + stream_putc (s, 0); + stream_putc (s, SAFI_MULTICAST); + } + /* IPv4 VPN */ + if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) + { + peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 1; + stream_putc (s, BGP_OPEN_OPT_CAP); + stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); + stream_putc (s, CAPABILITY_CODE_MP); + stream_putc (s, CAPABILITY_CODE_MP_LEN); + stream_putw (s, AFI_IP); + stream_putc (s, 0); + stream_putc (s, BGP_SAFI_VPNV4); + } +#ifdef HAVE_IPV6 + /* IPv6 unicast. */ + if (peer->afc[AFI_IP6][SAFI_UNICAST]) + { + peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 1; + stream_putc (s, BGP_OPEN_OPT_CAP); + stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); + stream_putc (s, CAPABILITY_CODE_MP); + stream_putc (s, CAPABILITY_CODE_MP_LEN); + stream_putw (s, AFI_IP6); + stream_putc (s, 0); + stream_putc (s, SAFI_UNICAST); + } + /* IPv6 multicast. */ + if (peer->afc[AFI_IP6][SAFI_MULTICAST]) + { + peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 1; + stream_putc (s, BGP_OPEN_OPT_CAP); + stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); + stream_putc (s, CAPABILITY_CODE_MP); + stream_putc (s, CAPABILITY_CODE_MP_LEN); + stream_putw (s, AFI_IP6); + stream_putc (s, 0); + stream_putc (s, SAFI_MULTICAST); + } +#endif /* HAVE_IPV6 */ + + /* Route refresh. */ + SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV); + stream_putc (s, BGP_OPEN_OPT_CAP); + stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2); + stream_putc (s, CAPABILITY_CODE_REFRESH_OLD); + stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); + stream_putc (s, BGP_OPEN_OPT_CAP); + stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2); + stream_putc (s, CAPABILITY_CODE_REFRESH); + stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); + + /* ORF capability. */ + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) + || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) + { + bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF_OLD); + bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF); + } + + /* Dynamic capability. */ + if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) + { + SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV); + stream_putc (s, BGP_OPEN_OPT_CAP); + stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN + 2); + stream_putc (s, CAPABILITY_CODE_DYNAMIC); + stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN); + } + + /* Graceful restart capability */ + if (bgp_flag_check (peer->bgp, BGP_FLAG_GRACEFUL_RESTART)) + { + SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV); + stream_putc (s, BGP_OPEN_OPT_CAP); + stream_putc (s, CAPABILITY_CODE_RESTART_LEN + 2); + stream_putc (s, CAPABILITY_CODE_RESTART); + stream_putc (s, CAPABILITY_CODE_RESTART_LEN); + stream_putw (s, peer->bgp->restart_time); + } + + /* Total Opt Parm Len. */ + len = stream_get_putp (s) - cp - 1; + stream_putc_at (s, cp, len); +} diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h new file mode 100644 index 0000000..b4ddfad --- /dev/null +++ b/bgpd/bgp_open.h @@ -0,0 +1,83 @@ +/* BGP open message handling + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* MP Capability information. */ +struct capability_mp +{ + u_int16_t afi; + u_char reserved; + u_char safi; +}; + +/* BGP open message capability. */ +struct capability +{ + u_char code; + u_char length; + struct capability_mp mpc; +}; + +struct graceful_restart_af +{ + u_int16_t afi; + u_char safi; + u_char flag; +}; + +/* Capability Code */ +#define CAPABILITY_CODE_MP 1 /* Multiprotocol Extensions */ +#define CAPABILITY_CODE_REFRESH 2 /* Route Refresh Capability */ +#define CAPABILITY_CODE_ORF 3 /* Cooperative Route Filtering Capability */ +#define CAPABILITY_CODE_RESTART 64 /* Graceful Restart Capability */ +#define CAPABILITY_CODE_4BYTE_AS 65 /* 4-octet AS number Capability */ +#define CAPABILITY_CODE_DYNAMIC 66 /* Dynamic Capability */ +#define CAPABILITY_CODE_REFRESH_OLD 128 /* Route Refresh Capability(cisco) */ +#define CAPABILITY_CODE_ORF_OLD 130 /* Cooperative Route Filtering Capability(cisco) */ + +/* Capability Length */ +#define CAPABILITY_CODE_MP_LEN 4 +#define CAPABILITY_CODE_REFRESH_LEN 0 +#define CAPABILITY_CODE_DYNAMIC_LEN 0 +#define CAPABILITY_CODE_RESTART_LEN 2 /* Receiving only case */ + +/* Cooperative Route Filtering Capability. */ + +/* ORF Type */ +#define ORF_TYPE_PREFIX 64 +#define ORF_TYPE_PREFIX_OLD 128 + +/* ORF Mode */ +#define ORF_MODE_RECEIVE 1 +#define ORF_MODE_SEND 2 +#define ORF_MODE_BOTH 3 + +/* Dynamic capability */ + +/* Capability Message Action. */ +#define CAPABILITY_ACTION_SET 0 +#define CAPABILITY_ACTION_UNSET 1 + +/* Graceful Restart */ +#define RESTART_R_BIT 0x8000 +#define RESTART_F_BIT 0x80 + +int bgp_open_option_parse (struct peer *, u_char, int *); +void bgp_open_capability (struct stream *, struct peer *); +void bgp_capability_vty_out (struct vty *, struct peer *); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c new file mode 100644 index 0000000..a1274d1 --- /dev/null +++ b/bgpd/bgp_packet.c @@ -0,0 +1,2390 @@ +/* BGP packet management routine. + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "thread.h" +#include "stream.h" +#include "network.h" +#include "prefix.h" +#include "command.h" +#include "log.h" +#include "memory.h" +#include "sockunion.h" /* for inet_ntop () */ +#include "linklist.h" +#include "plist.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_dump.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_open.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_network.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_advertise.h" +#include "bgpd/bgp_vty.h" + +int stream_put_prefix (struct stream *, struct prefix *); + +/* Set up BGP packet marker and packet type. */ +static int +bgp_packet_set_marker (struct stream *s, u_char type) +{ + int i; + + /* Fill in marker. */ + for (i = 0; i < BGP_MARKER_SIZE; i++) + stream_putc (s, 0xff); + + /* Dummy total length. This field is should be filled in later on. */ + stream_putw (s, 0); + + /* BGP packet type. */ + stream_putc (s, type); + + /* Return current stream size. */ + return stream_get_putp (s); +} + +/* Set BGP packet header size entry. If size is zero then use current + stream size. */ +static int +bgp_packet_set_size (struct stream *s) +{ + int cp; + + /* Preserve current pointer. */ + cp = stream_get_putp (s); + stream_set_putp (s, BGP_MARKER_SIZE); + stream_putw (s, cp); + + /* Write back current pointer. */ + stream_set_putp (s, cp); + + return cp; +} + +/* Add new packet to the peer. */ +void +bgp_packet_add (struct peer *peer, struct stream *s) +{ + /* Add packet to the end of list. */ + stream_fifo_push (peer->obuf, s); +} + +/* Free first packet. */ +void +bgp_packet_delete (struct peer *peer) +{ + stream_free (stream_fifo_pop (peer->obuf)); +} + +/* Duplicate packet. */ +struct stream * +bgp_packet_dup (struct stream *s) +{ + struct stream *new; + + new = stream_new (stream_get_endp (s)); + + new->endp = s->endp; + new->putp = s->putp; + new->getp = s->getp; + + memcpy (new->data, s->data, stream_get_endp (s)); + + return new; +} + +/* Check file descriptor whether connect is established. */ +static void +bgp_connect_check (struct peer *peer) +{ + int status; + int slen; + int ret; + + /* Anyway I have to reset read and write thread. */ + BGP_READ_OFF (peer->t_read); + BGP_WRITE_OFF (peer->t_write); + + /* Check file descriptor. */ + slen = sizeof (status); + ret = getsockopt(peer->fd, SOL_SOCKET, SO_ERROR, (void *) &status, &slen); + + /* If getsockopt is fail, this is fatal error. */ + if (ret < 0) + { + zlog (peer->log, LOG_INFO, "can't get sockopt for nonblocking connect"); + BGP_EVENT_ADD (peer, TCP_fatal_error); + return; + } + + /* When status is 0 then TCP connection is established. */ + if (status == 0) + { + BGP_EVENT_ADD (peer, TCP_connection_open); + } + else + { + if (BGP_DEBUG (events, EVENTS)) + plog_info (peer->log, "%s [Event] Connect failed (%s)", + peer->host, strerror (errno)); + BGP_EVENT_ADD (peer, TCP_connection_open_failed); + } +} + +/* Make BGP update packet. */ +struct stream * +bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) +{ + struct stream *s; + struct bgp_adj_out *adj; + struct bgp_advertise *adv; + struct stream *packet; + struct bgp_node *rn = NULL; + struct bgp_info *binfo = NULL; + bgp_size_t total_attr_len = 0; + unsigned long pos; + char buf[BUFSIZ]; + struct prefix_rd *prd = NULL; + char *tag = NULL; + + s = peer->work; + stream_reset (s); + + adv = FIFO_HEAD (&peer->sync[afi][safi]->update); + + while (adv) + { + if (adv->rn) + rn = adv->rn; + adj = adv->adj; + if (adv->binfo) + binfo = adv->binfo; +#ifdef MPLS_VPN + if (rn) + prd = (struct prefix_rd *) &rn->prn->p; + if (binfo) + tag = binfo->tag; +#endif /* MPLS_VPN */ + + /* When remaining space can't include NLRI and it's length. */ + if (rn && STREAM_REMAIN (s) <= BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen)) + break; + + /* If packet is empty, set attribute. */ + if (stream_empty (s)) + { + bgp_packet_set_marker (s, BGP_MSG_UPDATE); + stream_putw (s, 0); + pos = stream_get_putp (s); + stream_putw (s, 0); + total_attr_len = bgp_packet_attribute (NULL, peer, s, + adv->baa->attr, + &rn->p, afi, safi, + binfo->peer, prd, tag); + stream_putw_at (s, pos, total_attr_len); + } + + if (afi == AFI_IP && safi == SAFI_UNICAST) + stream_put_prefix (s, &rn->p); + + if (BGP_DEBUG (update, UPDATE_OUT)) + zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d", + peer->host, + inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, BUFSIZ), + rn->p.prefixlen); + + /* Synchnorize attribute. */ + if (adj->attr) + bgp_attr_unintern (adj->attr); + else + peer->scount[afi][safi]++; + + adj->attr = bgp_attr_intern (adv->baa->attr); + + adv = bgp_advertise_clean (peer, adj, afi, safi); + + if (! (afi == AFI_IP && safi == SAFI_UNICAST)) + break; + } + + if (! stream_empty (s)) + { + bgp_packet_set_size (s); + packet = bgp_packet_dup (s); + bgp_packet_add (peer, packet); + stream_reset (s); + return packet; + } + return NULL; +} + +struct stream * +bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) +{ + struct stream *s; + struct stream *packet; + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("Send End-of-RIB for AF %s to neighbor %s", + afi_safi_print(afi, safi), peer->host); + + s = stream_new (BGP_MAX_PACKET_SIZE); + + /* Make BGP update packet. */ + bgp_packet_set_marker (s, BGP_MSG_UPDATE); + + /* Unfeasible Routes Length */ + stream_putw (s, 0); + + if (afi == AFI_IP && safi == SAFI_UNICAST) + { + /* Total Path Attribute Length */ + stream_putw (s, 0); + } + else + { + /* Total Path Attribute Length */ + stream_putw (s, 6); + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); + stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI); + stream_putc (s, 3); + stream_putw (s, afi); + stream_putc (s, safi); + } + + bgp_packet_set_size (s); + packet = bgp_packet_dup (s); + bgp_packet_add (peer, packet); + stream_free (s); + return packet; +} + +/* Make BGP withdraw packet. */ +struct stream * +bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) +{ + struct stream *s; + struct stream *packet; + struct bgp_adj_out *adj; + struct bgp_advertise *adv; + struct bgp_node *rn; + unsigned long pos; + bgp_size_t unfeasible_len; + bgp_size_t total_attr_len; + char buf[BUFSIZ]; + struct prefix_rd *prd = NULL; + + s = peer->work; + stream_reset (s); + + while ((adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL) + { + adj = adv->adj; + rn = adv->rn; +#ifdef MPLS_VPN + prd = (struct prefix_rd *) &rn->prn->p; +#endif /* MPLS_VPN */ + + if (STREAM_REMAIN (s) + < (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen))) + break; + + if (stream_empty (s)) + { + bgp_packet_set_marker (s, BGP_MSG_UPDATE); + stream_putw (s, 0); + } + + if (afi == AFI_IP && safi == SAFI_UNICAST) + stream_put_prefix (s, &rn->p); + else + { + pos = stream_get_putp (s); + stream_putw (s, 0); + total_attr_len + = bgp_packet_withdraw (peer, s, &rn->p, afi, safi, prd, NULL); + + /* Set total path attribute length. */ + stream_putw_at (s, pos, total_attr_len); + } + + if (BGP_DEBUG (update, UPDATE_OUT)) + zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d -- unreachable", + peer->host, + inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, BUFSIZ), + rn->p.prefixlen); + + peer->scount[afi][safi]--; + + bgp_adj_out_remove (rn, adj, peer, afi, safi); + bgp_unlock_node (rn); + + if (! (afi == AFI_IP && safi == SAFI_UNICAST)) + break; + } + + if (! stream_empty (s)) + { + if (afi == AFI_IP && safi == SAFI_UNICAST) + { + unfeasible_len + = stream_get_putp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN; + stream_putw_at (s, BGP_HEADER_SIZE, unfeasible_len); + stream_putw (s, 0); + } + bgp_packet_set_size (s); + packet = bgp_packet_dup (s); + bgp_packet_add (peer, packet); + stream_reset (s); + return packet; + } + + return NULL; +} + +void +bgp_default_update_send (struct peer *peer, struct attr *attr, + afi_t afi, safi_t safi, struct peer *from) +{ + struct stream *s; + struct stream *packet; + struct prefix p; + unsigned long pos; + bgp_size_t total_attr_len; + char attrstr[BUFSIZ]; + char buf[BUFSIZ]; + +#ifdef DISABLE_BGP_ANNOUNCE + return; +#endif /* DISABLE_BGP_ANNOUNCE */ + + if (afi == AFI_IP) + str2prefix ("0.0.0.0/0", &p); +#ifdef HAVE_IPV6 + else + str2prefix ("::/0", &p); +#endif /* HAVE_IPV6 */ + + /* Logging the attribute. */ + if (BGP_DEBUG (update, UPDATE_OUT)) + { + bgp_dump_attr (peer, attr, attrstr, BUFSIZ); + zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d %s", + peer->host, inet_ntop(p.family, &(p.u.prefix), buf, BUFSIZ), + p.prefixlen, attrstr); + } + + s = stream_new (BGP_MAX_PACKET_SIZE); + + /* Make BGP update packet. */ + bgp_packet_set_marker (s, BGP_MSG_UPDATE); + + /* Unfeasible Routes Length. */ + stream_putw (s, 0); + + /* Make place for total attribute length. */ + pos = stream_get_putp (s); + stream_putw (s, 0); + total_attr_len = bgp_packet_attribute (NULL, peer, s, attr, &p, afi, safi, from, NULL, NULL); + + /* Set Total Path Attribute Length. */ + stream_putw_at (s, pos, total_attr_len); + + /* NLRI set. */ + if (p.family == AF_INET && safi == SAFI_UNICAST) + stream_put_prefix (s, &p); + + /* Set size. */ + bgp_packet_set_size (s); + + packet = bgp_packet_dup (s); + stream_free (s); + + /* Dump packet if debug option is set. */ +#ifdef DEBUG + bgp_packet_dump (packet); +#endif /* DEBUG */ + + /* Add packet to the peer. */ + bgp_packet_add (peer, packet); + + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +} + +void +bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) +{ + struct stream *s; + struct stream *packet; + struct prefix p; + unsigned long pos; + unsigned long cp; + bgp_size_t unfeasible_len; + bgp_size_t total_attr_len; + char buf[BUFSIZ]; + +#ifdef DISABLE_BGP_ANNOUNCE + return; +#endif /* DISABLE_BGP_ANNOUNCE */ + + if (afi == AFI_IP) + str2prefix ("0.0.0.0/0", &p); +#ifdef HAVE_IPV6 + else + str2prefix ("::/0", &p); +#endif /* HAVE_IPV6 */ + + total_attr_len = 0; + pos = 0; + + if (BGP_DEBUG (update, UPDATE_OUT)) + zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d -- unreachable", + peer->host, inet_ntop(p.family, &(p.u.prefix), buf, BUFSIZ), + p.prefixlen); + + s = stream_new (BGP_MAX_PACKET_SIZE); + + /* Make BGP update packet. */ + bgp_packet_set_marker (s, BGP_MSG_UPDATE); + + /* Unfeasible Routes Length. */; + cp = stream_get_putp (s); + stream_putw (s, 0); + + /* Withdrawn Routes. */ + if (p.family == AF_INET && safi == SAFI_UNICAST) + { + stream_put_prefix (s, &p); + + unfeasible_len = stream_get_putp (s) - cp - 2; + + /* Set unfeasible len. */ + stream_putw_at (s, cp, unfeasible_len); + + /* Set total path attribute length. */ + stream_putw (s, 0); + } + else + { + pos = stream_get_putp (s); + stream_putw (s, 0); + total_attr_len = bgp_packet_withdraw (peer, s, &p, afi, safi, NULL, NULL); + + /* Set total path attribute length. */ + stream_putw_at (s, pos, total_attr_len); + } + + bgp_packet_set_size (s); + + packet = bgp_packet_dup (s); + stream_free (s); + + /* Add packet to the peer. */ + bgp_packet_add (peer, packet); + + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +} + +/* Get next packet to be written. */ +struct stream * +bgp_write_packet (struct peer *peer) +{ + afi_t afi; + safi_t safi; + struct stream *s = NULL; + struct bgp_advertise *adv; + + s = stream_fifo_head (peer->obuf); + if (s) + return s; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw); + if (adv) + { + s = bgp_withdraw_packet (peer, afi, safi); + if (s) + return s; + } + } + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + adv = FIFO_HEAD (&peer->sync[afi][safi]->update); + if (adv) + { + if (adv->binfo && adv->binfo->uptime < peer->synctime[afi][safi]) + { + if (CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_RCV) + && CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_ADV) + && ! CHECK_FLAG (adv->binfo->flags, BGP_INFO_STALE) + && safi != SAFI_MPLS_VPN) + { + if (CHECK_FLAG (adv->binfo->peer->af_sflags[afi][safi], + PEER_STATUS_EOR_RECEIVED)) + s = bgp_update_packet (peer, afi, safi); + } + else + s = bgp_update_packet (peer, afi, safi); + } + + if (s) + return s; + } + + if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV)) + { + if (peer->afc_nego[afi][safi] && peer->synctime[afi][safi] + && ! CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND) + && safi != SAFI_MPLS_VPN) + { + SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND); + return bgp_update_packet_eor (peer, afi, safi); + } + } + } + + return NULL; +} + +/* Is there partially written packet or updates we can send right + now. */ +int +bgp_write_proceed (struct peer *peer) +{ + afi_t afi; + safi_t safi; + struct bgp_advertise *adv; + + if (stream_fifo_head (peer->obuf)) + return 1; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + if (FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) + return 1; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + if ((adv = FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL) + if (adv->binfo->uptime < peer->synctime[afi][safi]) + return 1; + + return 0; +} + +/* Write packet to the peer. */ +int +bgp_write (struct thread *thread) +{ + struct peer *peer; + u_char type; + struct stream *s; + int num; + int count = 0; + int write_errno; + + /* Yes first of all get peer pointer. */ + peer = THREAD_ARG (thread); + peer->t_write = NULL; + + /* For non-blocking IO check. */ + if (peer->status == Connect) + { + bgp_connect_check (peer); + return 0; + } + + /* Nonblocking write until TCP output buffer is full. */ + while (1) + { + int writenum; + + s = bgp_write_packet (peer); + if (! s) + return 0; + + /* Number of bytes to be sent. */ + writenum = stream_get_endp (s) - stream_get_getp (s); + + /* Call write() system call. */ + num = write (peer->fd, STREAM_PNT (s), writenum); + write_errno = errno; + if (num <= 0) + { + /* Partial write. */ + if (write_errno == EWOULDBLOCK || write_errno == EAGAIN) + break; + + bgp_stop (peer); + peer->status = Idle; + bgp_timer_set (peer); + return 0; + } + if (num != writenum) + { + stream_forward (s, num); + + if (write_errno == EAGAIN) + break; + + continue; + } + + /* Retrieve BGP packet type. */ + stream_set_getp (s, BGP_MARKER_SIZE + 2); + type = stream_getc (s); + + switch (type) + { + case BGP_MSG_OPEN: + peer->open_out++; + break; + case BGP_MSG_UPDATE: + peer->update_out++; + break; + case BGP_MSG_NOTIFY: + peer->notify_out++; + + /* BGP_EVENT_ADD (peer, BGP_Stop); */ + bgp_stop_with_error (peer); + bgp_fsm_change_status (peer, Idle); + bgp_timer_set (peer); + return 0; + break; + case BGP_MSG_KEEPALIVE: + peer->keepalive_out++; + break; + case BGP_MSG_ROUTE_REFRESH_NEW: + case BGP_MSG_ROUTE_REFRESH_OLD: + peer->refresh_out++; + break; + case BGP_MSG_CAPABILITY: + peer->dynamic_cap_out++; + break; + } + + /* OK we send packet so delete it. */ + bgp_packet_delete (peer); + + if (++count >= BGP_WRITE_PACKET_MAX) + break; + } + + if (bgp_write_proceed (peer)) + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + + return 0; +} + +/* This is only for sending NOTIFICATION message to neighbor. */ +int +bgp_write_notify (struct peer *peer) +{ + int ret; + u_char type; + struct stream *s; + + /* There should be at least one packet. */ + s = stream_fifo_head (peer->obuf); + if (!s) + return 0; + assert (stream_get_endp (s) >= BGP_HEADER_SIZE); + + /* I'm not sure fd is writable. */ + ret = writen (peer->fd, STREAM_DATA (s), stream_get_endp (s)); + if (ret <= 0) + { + bgp_stop (peer); + peer->status = Idle; + bgp_timer_set (peer); + return 0; + } + + /* Retrieve BGP packet type. */ + stream_set_getp (s, BGP_MARKER_SIZE + 2); + type = stream_getc (s); + + assert (type == BGP_MSG_NOTIFY); + + /* Type should be notify. */ + peer->notify_out++; + + /* We don't call event manager at here for avoiding other events. */ + if (peer->status == Established) + bgp_stop (peer); + else + { + bgp_stop_with_error (peer); + bgp_fsm_change_status (peer, Idle); + } + bgp_timer_set (peer); + + return 0; +} + +/* Make keepalive packet and send it to the peer. */ +void +bgp_keepalive_send (struct peer *peer) +{ + struct stream *s; + int length; + + s = stream_new (BGP_MAX_PACKET_SIZE); + + /* Make keepalive packet. */ + bgp_packet_set_marker (s, BGP_MSG_KEEPALIVE); + + /* Set packet size. */ + length = bgp_packet_set_size (s); + + /* Dump packet if debug option is set. */ + /* bgp_packet_dump (s); */ + + if (BGP_DEBUG (keepalive, KEEPALIVE)) + zlog_info ("%s sending KEEPALIVE", peer->host); + + /* Add packet to the peer. */ + bgp_packet_add (peer, s); + + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +} + +/* Make open packet and send it to the peer. */ +void +bgp_open_send (struct peer *peer) +{ + struct stream *s; + int length; + u_int16_t send_holdtime; + as_t local_as; + + if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) + send_holdtime = peer->holdtime; + else + send_holdtime = peer->bgp->default_holdtime; + + /* local-as Change */ + if (peer->change_local_as) + local_as = peer->change_local_as; + else + local_as = peer->local_as; + + s = stream_new (BGP_MAX_PACKET_SIZE); + + /* Make open packet. */ + bgp_packet_set_marker (s, BGP_MSG_OPEN); + + /* Set open packet values. */ + stream_putc (s, BGP_VERSION_4); /* BGP version */ + stream_putw (s, local_as); /* My Autonomous System*/ + stream_putw (s, send_holdtime); /* Hold Time */ + stream_put_in_addr (s, &peer->local_id); /* BGP Identifier */ + + /* Set capability code. */ + bgp_open_capability (s, peer); + + /* Set BGP packet length. */ + length = bgp_packet_set_size (s); + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s sending OPEN, version %d, my as %d, holdtime %d, id %s", + peer->host, BGP_VERSION_4, local_as, + send_holdtime, inet_ntoa (peer->local_id)); + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s send message type %d, length (incl. header) %d", + peer->host, BGP_MSG_OPEN, length); + + /* Dump packet if debug option is set. */ + /* bgp_packet_dump (s); */ + + /* Add packet to the peer. */ + bgp_packet_add (peer, s); + + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +} + +/* Send BGP notify packet with data potion. */ +void +bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code, + u_char *data, size_t datalen) +{ + struct stream *s; + int length; + + /* Allocate new stream. */ + s = stream_new (BGP_MAX_PACKET_SIZE); + + /* Make nitify packet. */ + bgp_packet_set_marker (s, BGP_MSG_NOTIFY); + + /* Set notify packet values. */ + stream_putc (s, code); /* BGP notify code */ + stream_putc (s, sub_code); /* BGP notify sub_code */ + + /* If notify data is present. */ + if (data) + stream_write (s, data, datalen); + + /* Set BGP packet length. */ + length = bgp_packet_set_size (s); + + /* Add packet to the peer. */ + stream_fifo_clean (peer->obuf); + bgp_packet_add (peer, s); + + /* For debug */ + { + struct bgp_notify bgp_notify; + int first = 0; + int i; + char c[4]; + + bgp_notify.code = code; + bgp_notify.subcode = sub_code; + bgp_notify.data = NULL; + bgp_notify.length = length - BGP_MSG_NOTIFY_MIN_SIZE; + + if (bgp_notify.length) + { + bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3); + for (i = 0; i < bgp_notify.length; i++) + if (first) + { + sprintf (c, " %02x", data[i]); + strcat (bgp_notify.data, c); + } + else + { + first = 1; + sprintf (c, "%02x", data[i]); + strcpy (bgp_notify.data, c); + } + } + bgp_notify_print (peer, &bgp_notify, "sending"); + if (bgp_notify.data) + XFREE (MTYPE_TMP, bgp_notify.data); + } + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s send message type %d, length (incl. header) %d", + peer->host, BGP_MSG_NOTIFY, length); + + /* peer reset cause */ + if (sub_code != BGP_NOTIFY_CEASE_CONFIG_CHANGE) + { + if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET) + peer->last_reset = PEER_DOWN_USER_RESET; + else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) + peer->last_reset = PEER_DOWN_USER_SHUTDOWN; + else if (sub_code == BGP_NOTIFY_CEASE_PEER_UNCONFIG) + peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; + else + peer->last_reset = PEER_DOWN_NOTIFY_SEND; + } + /* Call imidiately. */ + BGP_WRITE_OFF (peer->t_write); + + bgp_write_notify (peer); +} + +/* Send BGP notify packet. */ +void +bgp_notify_send (struct peer *peer, u_char code, u_char sub_code) +{ + bgp_notify_send_with_data (peer, code, sub_code, NULL, 0); +} + +char * +afi2str (afi_t afi) +{ + if (afi == AFI_IP) + return "AFI_IP"; + else if (afi == AFI_IP6) + return "AFI_IP6"; + else + return "Unknown AFI"; +} + +char * +safi2str (safi_t safi) +{ + if (safi == SAFI_UNICAST) + return "SAFI_UNICAST"; + else if (safi == SAFI_MULTICAST) + return "SAFI_MULTICAST"; + else if (safi == SAFI_MPLS_VPN || safi == BGP_SAFI_VPNV4) + return "SAFI_MPLS_VPN"; + else + return "Unknown SAFI"; +} + +/* Send route refresh message to the peer. */ +void +bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, + u_char orf_type, u_char when_to_refresh, int remove) +{ + struct stream *s; + struct stream *packet; + int length; + struct bgp_filter *filter; + int orf_refresh = 0; + int msg_type; + +#ifdef DISABLE_BGP_ANNOUNCE + return; +#endif /* DISABLE_BGP_ANNOUNCE */ + + if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV)) + msg_type = BGP_MSG_ROUTE_REFRESH_NEW; + else + msg_type = BGP_MSG_ROUTE_REFRESH_OLD; + filter = &peer->filter[afi][safi]; + + /* Adjust safi code. */ + if (safi == SAFI_MPLS_VPN) + safi = BGP_SAFI_VPNV4; + + s = stream_new (BGP_MAX_PACKET_SIZE); + + /* Make BGP update packet. */ + bgp_packet_set_marker (s, msg_type); + + /* Encode Route Refresh message. */ + stream_putw (s, afi); + stream_putc (s, 0); + stream_putc (s, safi); + + if (orf_type == ORF_TYPE_PREFIX + || orf_type == ORF_TYPE_PREFIX_OLD) + if (remove || filter->plist[FILTER_IN].plist) + { + u_int16_t orf_len; + unsigned long orfp; + + orf_refresh = 1; + stream_putc (s, when_to_refresh); + stream_putc (s, orf_type); + orfp = stream_get_putp (s); + stream_putw (s, 0); + + if (remove) + { + UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); + stream_putc (s, ORF_COMMON_PART_REMOVE_ALL); + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s sending REFRESH_REQ to remove ORF(%d) (%s) for afi/safi: %d/%d", + peer->host, orf_type, + (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"), + afi, safi); + } + else + { + SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); + prefix_bgp_orf_entry (s, filter->plist[FILTER_IN].plist, + ORF_COMMON_PART_ADD, ORF_COMMON_PART_PERMIT, + ORF_COMMON_PART_DENY); + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s sending REFRESH_REQ with pfxlist ORF(%d) (%s) for afi/safi: %d/%d", + peer->host, orf_type, + (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"), + afi, safi); + } + + /* Total ORF Entry Len. */ + orf_len = stream_get_putp (s) - orfp - 2; + stream_putw_at (s, orfp, orf_len); + } + + /* Set packet size. */ + length = bgp_packet_set_size (s); + + if (BGP_DEBUG (normal, NORMAL)) + { + if (! orf_refresh) + zlog_info ("%s sending REFRESH_REQ(%d) for afi/safi: %d/%d", + peer->host, msg_type, afi, safi); + zlog_info ("%s send message type %d, length (incl. header) %d", + peer->host, msg_type, length); + } + + /* Make real packet. */ + packet = bgp_packet_dup (s); + stream_free (s); + + /* Add packet to the peer. */ + bgp_packet_add (peer, packet); + + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +} + +/* Send capability message to the peer. */ +void +bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, + int capability_code, int action) +{ + struct stream *s; + struct stream *packet; + int length; + + /* Adjust safi code. */ + if (safi == SAFI_MPLS_VPN) + safi = BGP_SAFI_VPNV4; + + s = stream_new (BGP_MAX_PACKET_SIZE); + + /* Make BGP update packet. */ + bgp_packet_set_marker (s, BGP_MSG_CAPABILITY); + + /* Encode MP_EXT capability. */ + if (capability_code == CAPABILITY_CODE_MP) + { + stream_putc (s, action); + stream_putc (s, CAPABILITY_CODE_MP); + stream_putc (s, CAPABILITY_CODE_MP_LEN); + stream_putw (s, afi); + stream_putc (s, 0); + stream_putc (s, safi); + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s sending CAPABILITY has %s MP_EXT CAP for afi/safi: %d/%d", + peer->host, action == CAPABILITY_ACTION_SET ? + "Advertising" : "Removing", afi, safi); + } + + /* Set packet size. */ + length = bgp_packet_set_size (s); + + /* Make real packet. */ + packet = bgp_packet_dup (s); + stream_free (s); + + /* Add packet to the peer. */ + bgp_packet_add (peer, packet); + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s send message type %d, length (incl. header) %d", + peer->host, BGP_MSG_CAPABILITY, length); + + BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +} + +/* RFC1771 6.8 Connection collision detection. */ +int +bgp_collision_detect (struct peer *new, struct in_addr remote_id) +{ + struct peer *peer; + struct listnode *nn; + struct bgp *bgp; + + bgp = bgp_get_default (); + if (! bgp) + return 0; + + /* Upon receipt of an OPEN message, the local system must examine + all of its connections that are in the OpenConfirm state. A BGP + speaker may also examine connections in an OpenSent state if it + knows the BGP Identifier of the peer by means outside of the + protocol. If among these connections there is a connection to a + remote BGP speaker whose BGP Identifier equals the one in the + OPEN message, then the local system performs the following + collision resolution procedure: */ + + LIST_LOOP (bgp->peer, peer, nn) + { + /* Under OpenConfirm status, local peer structure already hold + remote router ID. */ + + if (peer != new + && (peer->status == OpenConfirm || peer->status == OpenSent) + && sockunion_same (&peer->su, &new->su)) + { + /* 1. The BGP Identifier of the local system is compared to + the BGP Identifier of the remote system (as specified in + the OPEN message). */ + + if (ntohl (peer->local_id.s_addr) < ntohl (remote_id.s_addr)) + { + /* 2. If the value of the local BGP Identifier is less + than the remote one, the local system closes BGP + connection that already exists (the one that is + already in the OpenConfirm state), and accepts BGP + connection initiated by the remote system. */ + + if (peer->fd >= 0) + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONNECT_COLLISION); + return 1; + } + else + { + /* 3. Otherwise, the local system closes newly created + BGP connection (the one associated with the newly + received OPEN message), and continues to use the + existing one (the one that is already in the + OpenConfirm state). */ + + if (new->fd >= 0) + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONNECT_COLLISION); + return -1; + } + } + } + return 0; +} + +int +bgp_open_receive (struct peer *peer, bgp_size_t size) +{ + int ret; + u_char version; + u_char optlen; + u_int16_t holdtime; + u_int16_t send_holdtime; + as_t remote_as; + struct peer *realpeer; + struct in_addr remote_id; + int capability; + char notify_data_remote_as[2]; + char notify_data_remote_id[4]; + + realpeer = NULL; + + /* Parse open packet. */ + version = stream_getc (peer->ibuf); + memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2); + remote_as = stream_getw (peer->ibuf); + holdtime = stream_getw (peer->ibuf); + memcpy (notify_data_remote_id, stream_pnt (peer->ibuf), 4); + remote_id.s_addr = stream_get_ipv4 (peer->ibuf); + + /* Receive OPEN message log */ + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s rcv OPEN, version %d, remote-as %d, holdtime %d, id %s", + peer->host, version, remote_as, holdtime, + inet_ntoa (remote_id)); + + /* Lookup peer from Open packet. */ + if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + int as = 0; + + realpeer = peer_lookup_with_open (&peer->su, remote_as, &remote_id, &as); + + if (! realpeer) + { + /* Peer's source IP address is check in bgp_accept(), so this + must be AS number mismatch or remote-id configuration + mismatch. */ + if (as) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s bad OPEN, wrong router identifier %s", + peer->host, inet_ntoa (remote_id)); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_BAD_BGP_IDENT, + notify_data_remote_id, 4); + } + else + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s bad OPEN, remote AS is %d, expected %d", + peer->host, remote_as, peer->as); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_BAD_PEER_AS, + notify_data_remote_as, 2); + } + return -1; + } + } + + /* When collision is detected and this peer is closed. Retrun + immidiately. */ + ret = bgp_collision_detect (peer, remote_id); + if (ret < 0) + return ret; + + /* Hack part. */ + if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + if (CHECK_FLAG (realpeer->flags, PEER_FLAG_CONNECT_MODE_ACTIVE)) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s passive open failed - TCP session must be opened actively", + realpeer->host); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONNECT_REJECT); + return -1; + } + + if (realpeer->status == Established + && CHECK_FLAG (realpeer->sflags, PEER_STATUS_NSF_MODE)) + { + realpeer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; + SET_FLAG (realpeer->sflags, PEER_STATUS_NSF_WAIT); + } + else if (ret == 0 && realpeer->status != Active + && realpeer->status != OpenSent + && realpeer->status != OpenConfirm) + { + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s peer status is %s close connection", + realpeer->host, LOOKUP (bgp_status_msg, realpeer->status)); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONNECT_REJECT); + return -1; + } + + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s [Event] Transfer temporary BGP peer to existing one", + peer->host); + + bgp_stop (realpeer); + + /* Transfer file descriptor. */ + realpeer->fd = peer->fd; + peer->fd = -1; + + /* Transfer input buffer. */ + stream_free (realpeer->ibuf); + realpeer->ibuf = peer->ibuf; + realpeer->packet_size = peer->packet_size; + peer->ibuf = NULL; + + /* Transfer status. */ + bgp_fsm_change_status (realpeer, peer->status); + bgp_stop (peer); + + /* peer pointer change. Open packet send to neighbor. */ + peer = realpeer; + bgp_open_send (peer); + if (peer->fd < 0) + { + zlog_err ("bgp_open_receive peer's fd is negative value %d", + peer->fd); + return -1; + } + BGP_READ_ON (peer->t_read, bgp_read, peer->fd); + } + + /* remote router-id check. */ + if (remote_id.s_addr == 0 + || ntohl (remote_id.s_addr) >= 0xe0000000 + || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr)) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s bad OPEN, wrong router identifier %s", + peer->host, inet_ntoa (remote_id)); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_BAD_BGP_IDENT, + notify_data_remote_id, 4); + return -1; + } + + /* Set remote router-id */ + peer->remote_id = remote_id; + + /* Peer BGP version check. */ + if (version != BGP_VERSION_4) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s bad protocol version, remote requested %d, local request %d", + peer->host, version, BGP_VERSION_4); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNSUP_VERSION, + "\x04", 1); + return -1; + } + + /* Check neighbor as number. */ + if (remote_as != peer->as) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s bad OPEN, remote AS is %d, expected %d", + peer->host, remote_as, peer->as); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_BAD_PEER_AS, + notify_data_remote_as, 2); + return -1; + } + + /* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST + calculate the value of the Hold Timer by using the smaller of its + configured Hold Time and the Hold Time received in the OPEN message. + The Hold Time MUST be either zero or at least three seconds. An + implementation may reject connections on the basis of the Hold Time. */ + + if (holdtime < 3 && holdtime != 0) + { + bgp_notify_send (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); + return -1; + } + + /* From the rfc: A reasonable maximum time between KEEPALIVE messages + would be one third of the Hold Time interval. KEEPALIVE messages + MUST NOT be sent more frequently than one per second. An + implementation MAY adjust the rate at which it sends KEEPALIVE + messages as a function of the Hold Time interval. */ + + if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) + send_holdtime = peer->holdtime; + else + send_holdtime = peer->bgp->default_holdtime; + + if (holdtime < send_holdtime) + peer->v_holdtime = holdtime; + else + peer->v_holdtime = send_holdtime; + + peer->v_keepalive = peer->v_holdtime / 3; + + /* Open option part parse. */ + capability = 0; + optlen = stream_getc (peer->ibuf); + if (optlen != 0) + { + ret = bgp_open_option_parse (peer, optlen, &capability); + if (ret < 0) + return ret; + + stream_forward (peer->ibuf, optlen); + } + else + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s rcvd OPEN w/ OPTION parameter len: 0", + peer->host); + } + + /* Override capability. */ + if (! capability || CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) + { + peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST]; + peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST]; + peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST]; + peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST]; + } + + /* Get sockname. */ + bgp_getsockname (peer); + + BGP_EVENT_ADD (peer, Receive_OPEN_message); + + peer->packet_size = 0; + if (peer->ibuf) + stream_reset (peer->ibuf); + + return 0; +} + +/* Parse BGP Update packet and make attribute object. */ +int +bgp_update_receive (struct peer *peer, bgp_size_t size) +{ + int ret; + u_char *end; + struct stream *s; + struct attr attr; + bgp_size_t attribute_len; + bgp_size_t update_len; + bgp_size_t withdraw_len; + struct bgp_nlri update; + struct bgp_nlri withdraw; + struct bgp_nlri mp_update; + struct bgp_nlri mp_withdraw; + char attrstr[BUFSIZ] = ""; + + /* Status must be Established. */ + if (peer->status != Established) + { + zlog_err ("%s [FSM] Update packet received under status %s", + peer->host, LOOKUP (bgp_status_msg, peer->status)); + bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); + return -1; + } + + /* Set initial values. */ + memset (&attr, 0, sizeof (struct attr)); + memset (&update, 0, sizeof (struct bgp_nlri)); + memset (&withdraw, 0, sizeof (struct bgp_nlri)); + memset (&mp_update, 0, sizeof (struct bgp_nlri)); + memset (&mp_withdraw, 0, sizeof (struct bgp_nlri)); + + s = peer->ibuf; + end = stream_pnt (s) + size; + + /* RFC1771 6.3 If the Unfeasible Routes Length or Total Attribute + Length is too large (i.e., if Unfeasible Routes Length + Total + Attribute Length + 23 exceeds the message Length), then the Error + Subcode is set to Malformed Attribute List. */ + if (stream_pnt (s) + 2 > end) + { + zlog_err ("%s [Error] Update packet error" + " (packet length is short for unfeasible length)", + peer->host); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); + return -1; + } + + /* Unfeasible Route Length. */ + withdraw_len = stream_getw (s); + + /* Unfeasible Route Length check. */ + if (stream_pnt (s) + withdraw_len > end) + { + zlog_err ("%s [Error] Update packet error" + " (packet unfeasible length overflow %d)", + peer->host, withdraw_len); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); + return -1; + } + + /* Unfeasible Route packet format check. */ + if (withdraw_len > 0) + { + ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), withdraw_len); + if (ret < 0) + return -1; + + if (BGP_DEBUG (packet, PACKET_RECV)) + zlog_info ("%s [Update:RECV] Unfeasible NLRI received", peer->host); + + withdraw.afi = AFI_IP; + withdraw.safi = SAFI_UNICAST; + withdraw.nlri = stream_pnt (s); + withdraw.length = withdraw_len; + stream_forward (s, withdraw_len); + } + + /* Attribute total length check. */ + if (stream_pnt (s) + 2 > end) + { + zlog_warn ("%s [Error] Packet Error" + " (update packet is short for attribute length)", + peer->host); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); + return -1; + } + + /* Fetch attribute total length. */ + attribute_len = stream_getw (s); + + /* Attribute length check. */ + if (stream_pnt (s) + attribute_len > end) + { + zlog_warn ("%s [Error] Packet Error" + " (update packet attribute length overflow %d)", + peer->host, attribute_len); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); + return -1; + } + + /* Parse attribute when it exists. */ + if (attribute_len) + { + ret = bgp_attr_parse (peer, &attr, attribute_len, + &mp_update, &mp_withdraw); + if (ret < 0) + return -1; + } + + /* Logging the attribute. */ + if (BGP_DEBUG (update, UPDATE_IN)) + { + ret= bgp_dump_attr (peer, &attr, attrstr, BUFSIZ); + + if (ret) + zlog (peer->log, LOG_INFO, "%s rcvd UPDATE w/ attr: %s", + peer->host, attrstr); + } + + /* Network Layer Reachability Information. */ + update_len = end - stream_pnt (s); + + if (update_len) + { + /* Check NLRI packet format and prefix length. */ + ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), update_len); + if (ret < 0) + return -1; + + /* Set NLRI portion to structure. */ + update.afi = AFI_IP; + update.safi = SAFI_UNICAST; + update.nlri = stream_pnt (s); + update.length = update_len; + stream_forward (s, update_len); + } + + /* NLRI is processed only when the peer is configured specific + Address Family and Subsequent Address Family. */ + if (peer->afc[AFI_IP][SAFI_UNICAST]) + { + if (withdraw.length) + bgp_nlri_parse (peer, NULL, &withdraw); + + if (update.length) + { + /* We check well-known attribute only for IPv4 unicast + update. */ + ret = bgp_attr_check (peer, &attr); + if (ret < 0) + return -1; + + bgp_nlri_parse (peer, &attr, &update); + } + + if (mp_update.length + && mp_update.afi == AFI_IP + && mp_update.safi == SAFI_UNICAST) + bgp_nlri_parse (peer, &attr, &mp_update); + + if (mp_withdraw.length + && mp_withdraw.afi == AFI_IP + && mp_withdraw.safi == SAFI_UNICAST) + bgp_nlri_parse (peer, NULL, &mp_withdraw); + + if (! attribute_len && ! withdraw_len) + { + /* End-of-RIB received */ + SET_FLAG (peer->af_sflags[AFI_IP][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED); + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("neighbor %s sent End-of-RIB marker for IPv4 Unicast", + peer->host); + + /* NSF delete stale route */ + if (peer->nsf[AFI_IP][SAFI_UNICAST]) + bgp_clear_stale_route (peer, AFI_IP, SAFI_UNICAST); + } + } + if (peer->afc[AFI_IP][SAFI_MULTICAST]) + { + if (mp_update.length + && mp_update.afi == AFI_IP + && mp_update.safi == SAFI_MULTICAST) + bgp_nlri_parse (peer, &attr, &mp_update); + + if (mp_withdraw.length + && mp_withdraw.afi == AFI_IP + && mp_withdraw.safi == SAFI_MULTICAST) + bgp_nlri_parse (peer, NULL, &mp_withdraw); + + if (! withdraw_len + && mp_withdraw.afi == AFI_IP + && mp_withdraw.safi == SAFI_MULTICAST + && mp_withdraw.length == 0) + { + /* End-of-RIB received */ + SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST], PEER_STATUS_EOR_RECEIVED); + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("neighbor %s sent End-of-RIB marker for IPv4 Multicast", + peer->host); + + /* NSF delete stale route */ + if (peer->nsf[AFI_IP][SAFI_MULTICAST]) + bgp_clear_stale_route (peer, AFI_IP, SAFI_MULTICAST); + } + } + if (peer->afc[AFI_IP6][SAFI_UNICAST]) + { + if (mp_update.length + && mp_update.afi == AFI_IP6 + && mp_update.safi == SAFI_UNICAST) + bgp_nlri_parse (peer, &attr, &mp_update); + + if (mp_withdraw.length + && mp_withdraw.afi == AFI_IP6 + && mp_withdraw.safi == SAFI_UNICAST) + bgp_nlri_parse (peer, NULL, &mp_withdraw); + + if (! withdraw_len + && mp_withdraw.afi == AFI_IP6 + && mp_withdraw.safi == SAFI_UNICAST + && mp_withdraw.length == 0) + { + /* End-of-RIB received */ + SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED); + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("neighbor %s sent End-of-RIB marker for IPv6 Unicast", + peer->host); + + /* NSF delete stale route */ + if (peer->nsf[AFI_IP6][SAFI_UNICAST]) + bgp_clear_stale_route (peer, AFI_IP6, SAFI_UNICAST); + } + } + if (peer->afc[AFI_IP6][SAFI_MULTICAST]) + { + if (mp_update.length + && mp_update.afi == AFI_IP6 + && mp_update.safi == SAFI_MULTICAST) + bgp_nlri_parse (peer, &attr, &mp_update); + + if (mp_withdraw.length + && mp_withdraw.afi == AFI_IP6 + && mp_withdraw.safi == SAFI_MULTICAST) + bgp_nlri_parse (peer, NULL, &mp_withdraw); + + if (! withdraw_len + && mp_withdraw.afi == AFI_IP6 + && mp_withdraw.safi == SAFI_MULTICAST + && mp_withdraw.length == 0) + { + /* End-of-RIB received */ + SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_MULTICAST], PEER_STATUS_EOR_RECEIVED); + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("neighbor %s sent End-of-RIB marker for IPv6 Multicast", + peer->host); + + /* NSF delete stale route */ + if (peer->nsf[AFI_IP6][SAFI_MULTICAST]) + bgp_clear_stale_route (peer, AFI_IP6, SAFI_MULTICAST); + } + } + if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) + { + if (mp_update.length + && mp_update.afi == AFI_IP + && mp_update.safi == BGP_SAFI_VPNV4) + bgp_nlri_parse_vpnv4 (peer, &attr, &mp_update); + + if (mp_withdraw.length + && mp_withdraw.afi == AFI_IP + && mp_withdraw.safi == BGP_SAFI_VPNV4) + bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw); + + if (! withdraw_len + && mp_withdraw.afi == AFI_IP + && mp_withdraw.safi == BGP_SAFI_VPNV4 + && mp_withdraw.length == 0) + { + /* End-of-RIB received */ + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("neighbor %s sent End-of-RIB marker for VPNv4 Unicast", + peer->host); + } + } + + /* Everything is done. We unintern temporary structures which + interned in bgp_attr_parse(). */ + if (attr.aspath) + aspath_unintern (attr.aspath); + if (attr.community) + community_unintern (attr.community); + if (attr.ecommunity) + ecommunity_unintern (attr.ecommunity); + if (attr.cluster) + cluster_unintern (attr.cluster); + if (attr.transit) + transit_unintern (attr.transit); + + /* If peering is stopped due to some reason, do not generate BGP + event. */ + if (peer->status != Established) + return 0; + + /* Increment packet counter. */ + peer->update_in++; + peer->update_time = time (NULL); + + /* Generate BGP event. */ + BGP_EVENT_ADD (peer, Receive_UPDATE_message); + + return 0; +} + +/* Notify message treatment function. */ +void +bgp_notify_receive (struct peer *peer, bgp_size_t size) +{ + struct bgp_notify bgp_notify; + + if (peer->notify.data) + { + XFREE (MTYPE_TMP, peer->notify.data); + peer->notify.data = NULL; + peer->notify.length = 0; + } + + bgp_notify.code = stream_getc (peer->ibuf); + bgp_notify.subcode = stream_getc (peer->ibuf); + bgp_notify.length = size - 2; + bgp_notify.data = NULL; + + /* Preserv notify code and sub code. */ + peer->notify.code = bgp_notify.code; + peer->notify.subcode = bgp_notify.subcode; + /* For further diagnostic record returned Data. */ + if (bgp_notify.length) + { + peer->notify.length = size - 2; + peer->notify.data = XMALLOC (MTYPE_TMP, size - 2); + memcpy (peer->notify.data, stream_pnt (peer->ibuf), size - 2); + } + + /* For debug */ + { + int i; + int first = 0; + char c[4]; + + if (bgp_notify.length) + { + bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3); + for (i = 0; i < bgp_notify.length; i++) + if (first) + { + sprintf (c, " %02x", stream_getc (peer->ibuf)); + strcat (bgp_notify.data, c); + } + else + { + first = 1; + sprintf (c, "%02x", stream_getc (peer->ibuf)); + strcpy (bgp_notify.data, c); + } + } + + bgp_notify_print(peer, &bgp_notify, "received"); + if (bgp_notify.data) + XFREE (MTYPE_TMP, bgp_notify.data); + } + + /* peer count update */ + peer->notify_in++; + + if (peer->status == Established) + peer->last_reset = PEER_DOWN_NOTIFY_RECEIVED; + /* We have to check for Notify with Unsupported Optional Parameter. + in that case we fallback to open without the capability option. + But this done in bgp_stop. We just mark it here to avoid changing + the fsm tables. */ + if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR && + bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM ) + UNSET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); + + /* Also apply to Unsupported Capability until remote router support + capability. */ + if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR && + bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_CAPBL) + UNSET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); + + BGP_EVENT_ADD (peer, Receive_NOTIFICATION_message); +} + +/* Keepalive treatment function -- get keepalive send keepalive */ +void +bgp_keepalive_receive (struct peer *peer, bgp_size_t size) +{ + if (BGP_DEBUG (keepalive, KEEPALIVE)) + zlog_info ("%s received KEEPALIVE, length (excl. header) %d", peer->host, size); + + BGP_EVENT_ADD (peer, Receive_KEEPALIVE_message); +} + +/* Route refresh message is received. */ +void +bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) +{ + afi_t afi; + safi_t safi; + u_char reserved; + struct stream *s; + + /* If peer does not have the capability, send notification. */ + if (! CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_ADV)) + { + plog_err (peer->log, "%s [Error] BGP route refresh is not enabled", + peer->host); + bgp_notify_send (peer, + BGP_NOTIFY_HEADER_ERR, + BGP_NOTIFY_HEADER_BAD_MESTYPE); + return; + } + + /* Status must be Established. */ + if (peer->status != Established) + { + plog_err (peer->log, + "%s [Error] Route refresh packet received under status %s", + peer->host, LOOKUP (bgp_status_msg, peer->status)); + bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); + return; + } + + s = peer->ibuf; + + /* Parse packet. */ + afi = stream_getw (s); + reserved = stream_getc (s); + safi = stream_getc (s); + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s rcvd REFRESH_REQ for afi/safi: %d/%d", + peer->host, afi, safi); + + /* Check AFI and SAFI. */ + if ((afi != AFI_IP && afi != AFI_IP6) + || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST + && safi != BGP_SAFI_VPNV4)) + { + if (BGP_DEBUG (normal, NORMAL)) + { + zlog_info ("%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored", + peer->host, afi, safi); + } + return; + } + + /* Adjust safi code. */ + if (safi == BGP_SAFI_VPNV4) + safi = SAFI_MPLS_VPN; + + if (size != BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) + { + u_char *end; + u_char when_to_refresh; + u_char orf_type; + u_int16_t orf_len; + + if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) < 5) + { + zlog_info ("%s ORF route refresh length error", peer->host); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + return; + } + + when_to_refresh = stream_getc (s); + end = stream_pnt (s) + (size - 5); + + while (stream_pnt (s) < end) + { + orf_type = stream_getc (s); + orf_len = stream_getw (s); + + if (orf_type == ORF_TYPE_PREFIX + || orf_type == ORF_TYPE_PREFIX_OLD) + { + u_char *p_pnt = stream_pnt (s); + u_char *p_end = stream_pnt (s) + orf_len; + struct orf_prefix orfp; + u_char common = 0; + u_int32_t seq; + int psize; + char name[BUFSIZ]; + char buf[BUFSIZ]; + int ret; + + if (BGP_DEBUG (normal, NORMAL)) + { + zlog_info ("%s rcvd Prefixlist ORF(%d) length %d", + peer->host, orf_type, orf_len); + } + + /* ORF prefix-list name */ + sprintf (name, "%s.%d.%d", peer->host, afi, safi); + + while (p_pnt < p_end) + { + memset (&orfp, 0, sizeof (struct orf_prefix)); + common = *p_pnt++; + if (common & ORF_COMMON_PART_REMOVE_ALL) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s rcvd Remove-All pfxlist ORF request", peer->host); + prefix_bgp_orf_remove_all (name); + break; + } + memcpy (&seq, p_pnt, sizeof (u_int32_t)); + p_pnt += sizeof (u_int32_t); + orfp.seq = ntohl (seq); + orfp.ge = *p_pnt++; + orfp.le = *p_pnt++; + orfp.p.prefixlen = *p_pnt++; + orfp.p.family = afi2family (afi); + psize = PSIZE (orfp.p.prefixlen); + memcpy (&orfp.p.u.prefix, p_pnt, psize); + p_pnt += psize; + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s rcvd %s %s seq %u %s/%d ge %d le %d", + peer->host, + (common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"), + (common & ORF_COMMON_PART_DENY ? "deny" : "permit"), + orfp.seq, + inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, BUFSIZ), + orfp.p.prefixlen, orfp.ge, orfp.le); + + ret = prefix_bgp_orf_set (name, afi, &orfp, + (common & ORF_COMMON_PART_DENY ? 0 : 1 ), + (common & ORF_COMMON_PART_REMOVE ? 0 : 1)); + + if (ret != CMD_SUCCESS) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s Received misformatted prefixlist ORF. Remove All pfxlist", peer->host); + prefix_bgp_orf_remove_all (name); + break; + } + } + peer->orf_plist[afi][safi] = + prefix_list_lookup (AFI_ORF_PREFIX, name); + } + stream_forward (s, orf_len); + } + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s rcvd Refresh %s ORF request", peer->host, + when_to_refresh == REFRESH_DEFER ? "Defer" : "Immediate"); + if (when_to_refresh == REFRESH_DEFER) + return; + } + + /* First update is deferred until ORF or ROUTE-REFRESH is received */ + if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) + UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH); + + /* Perform route refreshment to the peer */ + bgp_announce_route (peer, afi, safi); +} + +int +bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) +{ + u_char *end; + struct capability cap; + u_char action; + struct bgp *bgp; + afi_t afi; + safi_t safi; + + bgp = peer->bgp; + end = pnt + length; + + while (pnt < end) + { + /* We need at least action, capability code and capability length. */ + if (pnt + 3 > end) + { + zlog_info ("%s Capability length error", peer->host); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + return -1; + } + + action = *pnt; + + /* Fetch structure to the byte stream. */ + memcpy (&cap, pnt + 1, sizeof (struct capability)); + + /* Action value check. */ + if (action != CAPABILITY_ACTION_SET + && action != CAPABILITY_ACTION_UNSET) + { + zlog_info ("%s Capability Action Value error %d", + peer->host, action); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + return -1; + } + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s CAPABILITY has action: %d, code: %u, length %u", + peer->host, action, cap.code, cap.length); + + /* Capability length check. */ + if (pnt + (cap.length + 3) > end) + { + zlog_info ("%s Capability length error", peer->host); + bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); + return -1; + } + + /* We know MP Capability Code. */ + if (cap.code == CAPABILITY_CODE_MP) + { + afi = ntohs (cap.mpc.afi); + safi = cap.mpc.safi; + + /* Ignore capability when override-capability is set. */ + if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) + continue; + + /* Address family check. */ + if ((afi == AFI_IP + || afi == AFI_IP6) + && (safi == SAFI_UNICAST + || safi == SAFI_MULTICAST + || safi == BGP_SAFI_VPNV4)) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u", + peer->host, + action == CAPABILITY_ACTION_SET + ? "Advertising" : "Removing", + ntohs(cap.mpc.afi) , cap.mpc.safi); + + /* Adjust safi code. */ + if (safi == BGP_SAFI_VPNV4) + safi = SAFI_MPLS_VPN; + + if (action == CAPABILITY_ACTION_SET) + { + peer->afc_recv[afi][safi] = 1; + if (peer->afc[afi][safi]) + { + peer->afc_nego[afi][safi] = 1; + bgp_announce_route (peer, afi, safi); + } + } + else + { + peer->afc_recv[afi][safi] = 0; + peer->afc_nego[afi][safi] = 0; + + if (peer_active_nego (peer)) + { + bgp_clear_route (peer, afi, safi); + peer->synctime[afi][safi] = 0; + BGP_TIMER_OFF (peer->t_routeadv[afi][safi]); + peer->af_sflags[afi][safi] = 0; + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + } + } + else + { + zlog_warn ("%s unrecognized capability code: %d - ignored", + peer->host, cap.code); + } + pnt += cap.length + 3; + } + return 0; +} + +/* Dynamic Capability is received. */ +void +bgp_capability_receive (struct peer *peer, bgp_size_t size) +{ + u_char *pnt; + int ret; + + /* Fetch pointer. */ + pnt = stream_pnt (peer->ibuf); + + if (BGP_DEBUG (normal, NORMAL)) + zlog_info ("%s rcv CAPABILITY", peer->host); + + /* If peer does not have the capability, send notification. */ + if (! CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV)) + { + plog_err (peer->log, "%s [Error] BGP dynamic capability is not enabled", + peer->host); + bgp_notify_send (peer, + BGP_NOTIFY_HEADER_ERR, + BGP_NOTIFY_HEADER_BAD_MESTYPE); + return; + } + + /* Status must be Established. */ + if (peer->status != Established) + { + plog_err (peer->log, + "%s [Error] Dynamic capability packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); + bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); + return; + } + + /* Parse packet. */ + ret = bgp_capability_msg_parse (peer, pnt, size); +} + +/* BGP read utility function. */ +int +bgp_read_packet (struct peer *peer) +{ + int nbytes; + int readsize; + + readsize = peer->packet_size - peer->ibuf->putp; + + /* If size is zero then return. */ + if (! readsize) + return 0; + + /* Read packet from fd. */ + nbytes = stream_read_unblock (peer->ibuf, peer->fd, readsize); + + /* If read byte is smaller than zero then error occured. */ + if (nbytes < 0) + { + if (errno == EAGAIN) + return -1; + + plog_err (peer->log, "%s [Error] bgp_read_packet error: %s", + peer->host, strerror (errno)); + + if (peer->status == Established) + { + if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE)) + { + peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; + SET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); + } + else + peer->last_reset = PEER_DOWN_CLOSE_SESSION; + } + + BGP_EVENT_ADD (peer, TCP_fatal_error); + return -1; + } + + /* When read byte is zero : clear bgp peer and return */ + if (nbytes == 0) + { + if (BGP_DEBUG (events, EVENTS)) + plog_info (peer->log, "%s [Event] BGP connection closed fd %d", + peer->host, peer->fd); + + if (peer->status == Established) + { + if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE)) + { + peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; + SET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); + } + else + peer->last_reset = PEER_DOWN_CLOSE_SESSION; + } + + BGP_EVENT_ADD (peer, TCP_connection_closed); + return -1; + } + + /* We read partial packet. */ + if (peer->ibuf->putp != peer->packet_size) + return -1; + + return 0; +} + +/* Marker check. */ +int +bgp_marker_all_one (struct stream *s, int length) +{ + int i; + + for (i = 0; i < length; i++) + if (s->data[i] != 0xff) + return 0; + + return 1; +} + +/* Starting point of packet process function. */ +int +bgp_read (struct thread *thread) +{ + int ret; + u_char type = 0; + struct peer *peer; + bgp_size_t size; + char notify_data_length[2]; + + /* Yes first of all get peer pointer. */ + peer = THREAD_ARG (thread); + peer->t_read = NULL; + + /* For non-blocking IO check. */ + if (peer->status == Connect) + { + bgp_connect_check (peer); + goto done; + } + else + { + if (peer->fd < 0) + { + zlog_err ("bgp_read peer's fd is negative value %d", peer->fd); + return -1; + } + BGP_READ_ON (peer->t_read, bgp_read, peer->fd); + } + + /* Read packet header to determine type of the packet */ + if (peer->packet_size == 0) + peer->packet_size = BGP_HEADER_SIZE; + + if (peer->ibuf->putp < BGP_HEADER_SIZE) + { + ret = bgp_read_packet (peer); + + /* Header read error or partial read packet. */ + if (ret < 0) + goto done; + + /* Get size and type. */ + stream_forward (peer->ibuf, BGP_MARKER_SIZE); + memcpy (notify_data_length, stream_pnt (peer->ibuf), 2); + size = stream_getw (peer->ibuf); + type = stream_getc (peer->ibuf); + + if (BGP_DEBUG (normal, NORMAL)) + if (type && type != BGP_MSG_UPDATE && type != BGP_MSG_KEEPALIVE) + zlog_info ("%s rcv message type %d, length (excl. header) %d", + peer->host, type, size - BGP_HEADER_SIZE); + + /* Marker check */ + if (type == BGP_MSG_OPEN + && ! bgp_marker_all_one (peer->ibuf, BGP_MARKER_SIZE)) + { + bgp_notify_send (peer, + BGP_NOTIFY_HEADER_ERR, + BGP_NOTIFY_HEADER_NOT_SYNC); + goto done; + } + + /* BGP type check. */ + if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE + && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE + && type != BGP_MSG_ROUTE_REFRESH_NEW + && type != BGP_MSG_ROUTE_REFRESH_OLD + && type != BGP_MSG_CAPABILITY) + { + if (BGP_DEBUG (normal, NORMAL)) + plog_err (peer->log, + "%s unknown message type 0x%02x", + peer->host, type); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_HEADER_ERR, + BGP_NOTIFY_HEADER_BAD_MESTYPE, + &type, 1); + goto done; + } + /* Mimimum packet length check. */ + if ((size < BGP_HEADER_SIZE) + || (size > BGP_MAX_PACKET_SIZE) + || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE) + || (type == BGP_MSG_UPDATE && size < BGP_MSG_UPDATE_MIN_SIZE) + || (type == BGP_MSG_NOTIFY && size < BGP_MSG_NOTIFY_MIN_SIZE) + || (type == BGP_MSG_KEEPALIVE && size != BGP_MSG_KEEPALIVE_MIN_SIZE) + || (type == BGP_MSG_ROUTE_REFRESH_NEW && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) + || (type == BGP_MSG_ROUTE_REFRESH_OLD && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) + || (type == BGP_MSG_CAPABILITY && size < BGP_MSG_CAPABILITY_MIN_SIZE)) + { + if (BGP_DEBUG (normal, NORMAL)) + plog_err (peer->log, + "%s bad message length - %d for %s", + peer->host, size, + type == 128 ? "ROUTE-REFRESH" : + bgp_type_str[(int) type]); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_HEADER_ERR, + BGP_NOTIFY_HEADER_BAD_MESLEN, + notify_data_length, 2); + goto done; + } + + /* Adjust size to message length. */ + peer->packet_size = size; + } + + ret = bgp_read_packet (peer); + if (ret < 0) + goto done; + + /* Get size and type again. */ + size = stream_getw_from (peer->ibuf, BGP_MARKER_SIZE); + type = stream_getc_from (peer->ibuf, BGP_MARKER_SIZE + 2); + + /* BGP packet dump function. */ + bgp_dump_packet (peer, type, peer->ibuf); + + size = (peer->packet_size - BGP_HEADER_SIZE); + + /* Read rest of the packet and call each sort of packet routine */ + switch (type) + { + case BGP_MSG_OPEN: + peer->open_in++; + bgp_open_receive (peer, size); + break; + case BGP_MSG_UPDATE: + peer->readtime = time(NULL); /* Last read timer reset */ + bgp_update_receive (peer, size); + break; + case BGP_MSG_NOTIFY: + bgp_notify_receive (peer, size); + break; + case BGP_MSG_KEEPALIVE: + peer->readtime = time(NULL); /* Last read timer reset */ + bgp_keepalive_receive (peer, size); + break; + case BGP_MSG_ROUTE_REFRESH_NEW: + case BGP_MSG_ROUTE_REFRESH_OLD: + peer->refresh_in++; + bgp_route_refresh_receive (peer, size); + break; + case BGP_MSG_CAPABILITY: + peer->dynamic_cap_in++; + bgp_capability_receive (peer, size); + break; + } + + /* Clear input buffer. */ + peer->packet_size = 0; + if (peer->ibuf) + stream_reset (peer->ibuf); + + done: + if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s [Event] Accepting BGP peer delete", peer->host); + peer_delete (peer); + } + return 0; +} diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h new file mode 100644 index 0000000..c1efc8b --- /dev/null +++ b/bgpd/bgp_packet.h @@ -0,0 +1,49 @@ +/* BGP packet management header. + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#define BGP_NLRI_LENGTH 1 +#define BGP_TOTAL_ATTR_LEN 2 +#define BGP_UNFEASIBLE_LEN 2 +#define BGP_WRITE_PACKET_MAX 10 + +/* When to refresh */ +#define REFRESH_IMMEDIATE 1 +#define REFRESH_DEFER 2 + +/* ORF Common part flag */ +#define ORF_COMMON_PART_ADD 0x00 +#define ORF_COMMON_PART_REMOVE 0x80 +#define ORF_COMMON_PART_REMOVE_ALL 0xC0 +#define ORF_COMMON_PART_PERMIT 0x00 +#define ORF_COMMON_PART_DENY 0x20 + +/* Packet send and receive function prototypes. */ +int bgp_read (struct thread *); +int bgp_write (struct thread *); + +void bgp_keepalive_send (struct peer *); +void bgp_open_send (struct peer *); +void bgp_notify_send (struct peer *, u_char, u_char); +void bgp_notify_send_with_data (struct peer *, u_char, u_char, u_char *, size_t); +void bgp_route_refresh_send (struct peer *, afi_t, safi_t, u_char, u_char, int); +void bgp_capability_send (struct peer *, afi_t, safi_t, int, int); +void bgp_default_update_send (struct peer *, struct attr *, + afi_t, safi_t, struct peer *); +void bgp_default_withdraw_send (struct peer *, afi_t, safi_t); diff --git a/bgpd/bgp_regex.c b/bgpd/bgp_regex.c new file mode 100644 index 0000000..a6b6598 --- /dev/null +++ b/bgpd/bgp_regex.c @@ -0,0 +1,93 @@ +/* AS regular expression routine + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "log.h" +#include "command.h" +#include "memory.h" + +#include "bgpd.h" +#include "bgp_aspath.h" +#include "bgp_regex.h" + +/* Character `_' has special mean. It represents [,{}() ] and the + beginning of the line(^) and the end of the line ($). + + (^|[,{}() ]|$) */ + +regex_t * +bgp_regcomp (char *regstr) +{ + /* Convert _ character to generic regular expression. */ + int i, j; + int len; + int magic = 0; + char *magic_str; + char magic_regexp[] = "(^|[,{}() ]|$)"; + int ret; + regex_t *regex; + + len = strlen (regstr); + for (i = 0; i < len; i++) + if (regstr[i] == '_') + magic++; + + magic_str = XMALLOC (MTYPE_TMP, len + (14 * magic) + 1); + + for (i = 0, j = 0; i < len; i++) + { + if (regstr[i] == '_') + { + memcpy (magic_str + j, magic_regexp, strlen (magic_regexp)); + j += strlen (magic_regexp); + } + else + magic_str[j++] = regstr[i]; + } + magic_str[j] = '\0'; + + regex = XMALLOC (MTYPE_BGP_REGEXP, sizeof (regex_t)); + + ret = regcomp (regex, magic_str, REG_EXTENDED); + + XFREE (MTYPE_TMP, magic_str); + + if (ret != 0) + { + XFREE (MTYPE_BGP_REGEXP, regex); + return NULL; + } + + return regex; +} + +int +bgp_regexec (regex_t *regex, struct aspath *aspath) +{ + return regexec (regex, aspath->str, 0, NULL, 0); +} + +void +bgp_regex_free (regex_t *regex) +{ + regfree (regex); + XFREE (MTYPE_BGP_REGEXP, regex); +} diff --git a/bgpd/bgp_regex.h b/bgpd/bgp_regex.h new file mode 100644 index 0000000..0829dd9 --- /dev/null +++ b/bgpd/bgp_regex.h @@ -0,0 +1,31 @@ +/* AS regular expression routine + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#ifdef HAVE_GNU_REGEX +#include +#else +#include "regex-gnu.h" +#endif /* HAVE_GNU_REGEX */ + +void bgp_regex_free (regex_t *regex); +regex_t *bgp_regcomp (char *str); +int bgp_regexec (regex_t *regex, struct aspath *aspath); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c new file mode 100644 index 0000000..2623c7c --- /dev/null +++ b/bgpd/bgp_route.c @@ -0,0 +1,9215 @@ +/* BGP routing information + Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "prefix.h" +#include "linklist.h" +#include "memory.h" +#include "command.h" +#include "stream.h" +#include "filter.h" +#include "str.h" +#include "log.h" +#include "routemap.h" +#include "buffer.h" +#include "sockunion.h" +#include "plist.h" +#include "thread.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_clist.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_filter.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_damp.h" +#include "bgpd/bgp_advertise.h" +#include "bgpd/bgp_zebra.h" +#include "bgpd/bgp_vty.h" + +/* Extern from bgp_dump.c */ +extern char *bgp_origin_str[]; +extern char *bgp_origin_long_str[]; + +struct bgp_node * +bgp_afi_node_get (struct bgp *bgp, afi_t afi, safi_t safi, struct prefix *p, + struct prefix_rd *prd) +{ + struct bgp_node *rn; + struct bgp_node *prn = NULL; + struct bgp_table *table; + + if (safi == SAFI_MPLS_VPN) + { + prn = bgp_node_get (bgp->rib[afi][safi], (struct prefix *) prd); + + if (prn->info == NULL) + prn->info = bgp_table_init (); + else + bgp_unlock_node (prn); + table = prn->info; + } + else + table = bgp->rib[afi][safi]; + + rn = bgp_node_get (table, p); + + if (safi == SAFI_MPLS_VPN) + rn->prn = prn; + + return rn; +} + +/* Allocate new bgp info structure. */ +struct bgp_info * +bgp_info_new () +{ + struct bgp_info *new; + + new = XMALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info)); + memset (new, 0, sizeof (struct bgp_info)); + + return new; +} + +/* Free bgp route information. */ +void +bgp_info_free (struct bgp_info *binfo) +{ + if (binfo->attr) + bgp_attr_unintern (binfo->attr); + + if (binfo->damp_info) + bgp_damp_info_free (binfo->damp_info, 0); + + XFREE (MTYPE_BGP_ROUTE, binfo); +} + +void +bgp_info_add (struct bgp_node *rn, struct bgp_info *ri) +{ + struct bgp_info *top; + + top = rn->info; + + ri->next = rn->info; + ri->prev = NULL; + if (top) + top->prev = ri; + rn->info = ri; +} + +void +bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri) +{ + if (ri->next) + ri->next->prev = ri->prev; + if (ri->prev) + ri->prev->next = ri->next; + else + rn->info = ri->next; +} + +/* Get MED value. If MED value is missing and "bgp bestpath + missing-as-worst" is specified, treat it as the worst value. */ +u_int32_t +bgp_med_value (struct attr *attr, struct bgp *bgp) +{ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) + return attr->med; + else + { + if (bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST)) + return 4294967295ul; + else + return 0; + } +} + +/* Compare two bgp route entity. br is preferable then return 1. */ +int +bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist) +{ + u_int32_t new_pref; + u_int32_t exist_pref; + u_int32_t new_med; + u_int32_t exist_med; + struct in_addr new_id; + struct in_addr exist_id; + int new_cluster; + int exist_cluster; + int internal_as_route = 0; + int confed_as_route = 0; + int cost_community = 0; + int ret; + + /* 0. Null check. */ + if (new == NULL) + return 0; + if (exist == NULL) + return 1; + + /* 1. Weight check. */ + if (new->attr->weight > exist->attr->weight) + return 1; + if (new->attr->weight < exist->attr->weight) + return 0; + + /* 2. Local preference check. */ + if (new->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) + new_pref = new->attr->local_pref; + else + new_pref = bgp->default_local_pref; + + if (exist->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) + exist_pref = exist->attr->local_pref; + else + exist_pref = bgp->default_local_pref; + + if (new_pref > exist_pref) + return 1; + if (new_pref < exist_pref) + return 0; + + /* 3. Local route check. */ + if (new->sub_type == BGP_ROUTE_STATIC) + return 1; + if (exist->sub_type == BGP_ROUTE_STATIC) + return 0; + + if (new->sub_type == BGP_ROUTE_REDISTRIBUTE) + return 1; + if (exist->sub_type == BGP_ROUTE_REDISTRIBUTE) + return 0; + + if (new->sub_type == BGP_ROUTE_AGGREGATE) + return 1; + if (exist->sub_type == BGP_ROUTE_AGGREGATE) + return 0; + + /* 4. AS path length check. */ + if (! bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE)) + { + if (new->attr->aspath->count < exist->attr->aspath->count) + return 1; + if (new->attr->aspath->count > exist->attr->aspath->count) + return 0; + } + + /* 5. Origin check. */ + if (new->attr->origin < exist->attr->origin) + return 1; + if (new->attr->origin > exist->attr->origin) + return 0; + + /* 6. MED check. */ + internal_as_route = (new->attr->aspath->length == 0 + && exist->attr->aspath->length == 0); + confed_as_route = (new->attr->aspath->length > 0 + && exist->attr->aspath->length > 0 + && new->attr->aspath->count == 0 + && exist->attr->aspath->count == 0); + + if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED) + || (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED) + && confed_as_route) + || aspath_cmp_left (new->attr->aspath, exist->attr->aspath) + || aspath_cmp_left_confed (new->attr->aspath, exist->attr->aspath) + || internal_as_route) + { + new_med = bgp_med_value (new->attr, bgp); + exist_med = bgp_med_value (exist->attr, bgp); + + if (new_med < exist_med) + return 1; + if (new_med > exist_med) + return 0; + } + + /* 7. Peer type check. */ + if (peer_sort (new->peer) == BGP_PEER_EBGP + && peer_sort (exist->peer) == BGP_PEER_IBGP) + return 1; + if (peer_sort (new->peer) == BGP_PEER_EBGP + && peer_sort (exist->peer) == BGP_PEER_CONFED) + return 1; + if (peer_sort (new->peer) == BGP_PEER_IBGP + && peer_sort (exist->peer) == BGP_PEER_EBGP) + return 0; + if (peer_sort (new->peer) == BGP_PEER_CONFED + && peer_sort (exist->peer) == BGP_PEER_EBGP) + return 0; + + /* 8. IGP metric check. */ + if (new->igpmetric < exist->igpmetric) + return 1; + if (new->igpmetric > exist->igpmetric) + return 0; + + /* 9. cost community check. */ + if (! bgp_flag_check (bgp, BGP_FLAG_COST_COMMUNITY_IGNORE)) + { + cost_community = ecommunity_cost_cmp (new->attr->ecommunity, + exist->attr->ecommunity, ECOMMUNITY_COST_POI_IGP); + if (cost_community > 0) + return 1; + if (cost_community < 0) + return 0; + } + + /* 10. Maximum path check. */ + + /* 11. If both paths are external, prefer the path that was received + first (the oldest one). This step minimizes route-flap, since a + newer path won't displace an older one, even if it was the + preferred route based on the additional decision criteria below. */ + if (! bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID) + && peer_sort (new->peer) == BGP_PEER_EBGP + && peer_sort (exist->peer) == BGP_PEER_EBGP) + { + if (CHECK_FLAG (new->flags, BGP_INFO_SELECTED)) + return 1; + if (CHECK_FLAG (exist->flags, BGP_INFO_SELECTED)) + return 0; + } + + /* 12. Rourter-ID comparision. */ + if (new->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) + new_id.s_addr = new->attr->originator_id.s_addr; + else + new_id.s_addr = new->peer->remote_id.s_addr; + if (exist->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) + exist_id.s_addr = exist->attr->originator_id.s_addr; + else + exist_id.s_addr = exist->peer->remote_id.s_addr; + + if (ntohl (new_id.s_addr) < ntohl (exist_id.s_addr)) + return 1; + if (ntohl (new_id.s_addr) > ntohl (exist_id.s_addr)) + return 0; + + /* 13. Cluster length comparision. */ + if (new->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) + new_cluster = new->attr->cluster->length; + else + new_cluster = 0; + if (exist->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) + exist_cluster = exist->attr->cluster->length; + else + exist_cluster = 0; + + if (new_cluster < exist_cluster) + return 1; + if (new_cluster > exist_cluster) + return 0; + + /* 14. Neighbor address comparision. */ + ret = sockunion_cmp (new->peer->su_remote, exist->peer->su_remote); + + if (ret == 1) + return 0; + if (ret == -1) + return 1; + + return 1; +} + +enum filter_type +bgp_input_filter (struct peer *peer, struct prefix *p, struct attr *attr, + afi_t afi, safi_t safi) +{ + struct bgp_filter *filter; + + filter = &peer->filter[afi][safi]; + + if (DISTRIBUTE_IN_NAME (filter)) + if (access_list_apply (DISTRIBUTE_IN (filter), p) == FILTER_DENY) + return FILTER_DENY; + + if (PREFIX_LIST_IN_NAME (filter)) + if (prefix_list_apply (PREFIX_LIST_IN (filter), p) == PREFIX_DENY) + return FILTER_DENY; + + if (FILTER_LIST_IN_NAME (filter)) + if (as_list_apply (FILTER_LIST_IN (filter), attr->aspath)== AS_FILTER_DENY) + return FILTER_DENY; + + return FILTER_PERMIT; +} + +enum filter_type +bgp_output_filter (struct peer *peer, struct prefix *p, struct attr *attr, + afi_t afi, safi_t safi) +{ + struct bgp_filter *filter; + + filter = &peer->filter[afi][safi]; + + if (DISTRIBUTE_OUT_NAME (filter)) + if (access_list_apply (DISTRIBUTE_OUT (filter), p) == FILTER_DENY) + return FILTER_DENY; + + if (PREFIX_LIST_OUT_NAME (filter)) + if (prefix_list_apply (PREFIX_LIST_OUT (filter), p) == PREFIX_DENY) + return FILTER_DENY; + + if (FILTER_LIST_OUT_NAME (filter)) + if (as_list_apply (FILTER_LIST_OUT (filter), attr->aspath) == AS_FILTER_DENY) + return FILTER_DENY; + + return FILTER_PERMIT; +} + +/* If community attribute includes no_export then return 1. */ +int +bgp_community_filter (struct peer *peer, struct attr *attr) +{ + if (attr->community) + { + /* NO_ADVERTISE check. */ + if (community_include (attr->community, COMMUNITY_NO_ADVERTISE)) + return 1; + + /* NO_EXPORT check. */ + if (peer_sort (peer) == BGP_PEER_EBGP && + community_include (attr->community, COMMUNITY_NO_EXPORT)) + return 1; + + /* NO_EXPORT_SUBCONFED check. */ + if (peer_sort (peer) == BGP_PEER_EBGP + || peer_sort (peer) == BGP_PEER_CONFED) + if (community_include (attr->community, COMMUNITY_NO_EXPORT_SUBCONFED)) + return 1; + } + return 0; +} + +/* Route reflection loop check. */ +static int +bgp_cluster_filter (struct peer *peer, struct attr *attr) +{ + struct in_addr cluster_id; + + if (attr->cluster) + { + if (peer->bgp->config & BGP_CONFIG_CLUSTER_ID) + cluster_id = peer->bgp->cluster_id; + else + cluster_id = peer->bgp->router_id; + + if (cluster_loop_check (attr->cluster, cluster_id)) + return 1; + } + return 0; +} + +int +bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr, + afi_t afi, safi_t safi) +{ + struct bgp_filter *filter; + struct bgp_info info; + route_map_result_t ret; + + filter = &peer->filter[afi][safi]; + + /* Apply default weight value. */ + if (CHECK_FLAG (peer->af_config[afi][safi], PEER_AF_CONFIG_WEIGHT)) + attr->weight = peer->weight[afi][safi]; + else + attr->weight = 0; + + /* Route map apply. */ + if (ROUTE_MAP_IN_NAME (filter)) + { + /* Duplicate current value to new strucutre for modification. */ + info.peer = peer; + info.attr = attr; + + SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN); + + /* Apply BGP route map to the attribute. */ + ret = route_map_apply (ROUTE_MAP_IN (filter), p, RMAP_BGP, &info); + + peer->rmap_type = 0; + + if (ret == RMAP_DENYMATCH) + { + /* Free newly generated AS path and community by route-map. */ + bgp_attr_flush (attr); + return RMAP_DENY; + } + } + return RMAP_PERMIT; +} + +int +bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, + struct attr *attr, afi_t afi, safi_t safi) +{ + int ret; + char buf[SU_ADDRSTRLEN]; + struct bgp_filter *filter; + struct bgp_info info; + struct peer *from; + struct bgp *bgp; + struct attr dummy_attr; + int transparent; + int reflect; + + from = ri->peer; + filter = &peer->filter[afi][safi]; + bgp = peer->bgp; + +#ifdef DISABLE_BGP_ANNOUNCE + return 0; +#endif + + /* Do not send back route to sender. */ + if (from == peer) + return 0; + + /* Aggregate-address suppress check. */ + if (ri->suppress) + if (! UNSUPPRESS_MAP_NAME (filter)) + return 0; + + /* Default route check. */ + if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) + { + if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY) + return 0; +#ifdef HAVE_IPV6 + else if (p->family == AF_INET6 && p->prefixlen == 0) + return 0; +#endif /* HAVE_IPV6 */ + } + + /* Transparency check. */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) + && CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + transparent = 1; + else + transparent = 0; + + /* If community is not disabled check the no-export and local. */ + if (! transparent && bgp_community_filter (peer, ri->attr)) + return 0; + + /* If the attribute has originator-id and it is same as remote + peer's id. */ + if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) + { + if (IPV4_ADDR_SAME (&peer->remote_id, &ri->attr->originator_id)) + { + if (BGP_DEBUG (filter, FILTER)) + zlog (peer->log, LOG_INFO, + "%s [Update:SEND] %s/%d originator-id is same as remote router-id", + peer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + return 0; + } + } + + /* ORF prefix-list filter check */ + if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) + && (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) + || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))) + if (peer->orf_plist[afi][safi]) + { + if (prefix_list_apply (peer->orf_plist[afi][safi], p) == PREFIX_DENY) + return 0; + } + + /* Output filter check. */ + if (bgp_output_filter (peer, p, ri->attr, afi, safi) == FILTER_DENY) + { + if (BGP_DEBUG (filter, FILTER)) + zlog (peer->log, LOG_INFO, + "%s [Update:SEND] %s/%d is filtered", + peer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + return 0; + } + +#ifdef BGP_SEND_ASPATH_CHECK + /* AS path loop check. */ + if (aspath_loop_check (ri->attr->aspath, peer->as)) + { + if (BGP_DEBUG (filter, FILTER)) + zlog (peer->log, LOG_INFO, + "%s [Update:SEND] suppress announcement to peer AS %d is AS path.", + peer->host, peer->as); + return 0; + } +#endif /* BGP_SEND_ASPATH_CHECK */ + + /* If we're a CONFED we need to loop check the CONFED ID too */ + if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) + { + if (aspath_loop_check(ri->attr->aspath, bgp->confed_id)) + { + if (BGP_DEBUG (filter, FILTER)) + zlog (peer->log, LOG_INFO, + "%s [Update:SEND] suppress announcement to peer AS %d is AS path.", + peer->host, + bgp->confed_id); + return 0; + } + } + + /* Route-Reflect check. */ + if (peer_sort (from) == BGP_PEER_IBGP && peer_sort (peer) == BGP_PEER_IBGP) + reflect = 1; + else + reflect = 0; + + /* IBGP reflection check. */ + if (reflect) + { + /* A route from a Client peer. */ + if (CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) + { + /* Reflect to all the Non-Client peers and also to the + Client peers other than the originator. Originator check + is already done. So there is noting to do. */ + /* no bgp client-to-client reflection check. */ + if (bgp_flag_check (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT)) + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) + return 0; + } + else + { + /* A route from a Non-client peer. Reflect to all other + clients. */ + if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) + return 0; + } + } + + /* For modify attribute, copy it to temporary structure. */ + *attr = *ri->attr; + + /* If local-preference is not set. */ + if ((peer_sort (peer) == BGP_PEER_IBGP + || peer_sort (peer) == BGP_PEER_CONFED) + && (! (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))) + { + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); + attr->local_pref = bgp->default_local_pref; + } + + /* Remove MED if its an EBGP peer - will get overwritten by route-maps */ + if (peer_sort (peer) == BGP_PEER_EBGP + && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) + { + if (ri->peer != bgp->peer_self && ! transparent + && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) + attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)); + } + + /* next-hop-set */ + if (transparent || reflect + || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) + && ((p->family == AF_INET && attr->nexthop.s_addr) +#ifdef HAVE_IPV6 + || (p->family == AF_INET6 && ri->peer != bgp->peer_self) +#endif /* HAVE_IPV6 */ + ))) + { + /* NEXT-HOP Unchanged. */ + } + else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF) + || (p->family == AF_INET && attr->nexthop.s_addr == 0) +#ifdef HAVE_IPV6 + || (p->family == AF_INET6 && ri->peer == bgp->peer_self) +#endif /* HAVE_IPV6 */ + || (peer_sort (peer) == BGP_PEER_EBGP + && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0)) + { + /* Set IPv4 nexthop. */ + if (p->family == AF_INET) + { + if (safi == SAFI_MPLS_VPN) + memcpy (&attr->mp_nexthop_global_in, &peer->nexthop.v4, IPV4_MAX_BYTELEN); + else + memcpy (&attr->nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN); + } +#ifdef HAVE_IPV6 + /* Set IPv6 nexthop. */ + if (p->family == AF_INET6) + { + /* IPv6 global nexthop must be included. */ + memcpy (&attr->mp_nexthop_global, &peer->nexthop.v6_global, + IPV6_MAX_BYTELEN); + attr->mp_nexthop_len = 16; + } +#endif /* HAVE_IPV6 */ + } + +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + { + /* Link-local address should not be transit to different peer. */ + attr->mp_nexthop_len = 16; + + /* Set link-local address for shared network peer. */ + if (peer->shared_network + && ! IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local)) + { + memcpy (&attr->mp_nexthop_local, &peer->nexthop.v6_local, + IPV6_MAX_BYTELEN); + attr->mp_nexthop_len = 32; + } + + /* If bgpd act as BGP-4+ route-reflector, do not send link-local + address.*/ + if (reflect) + attr->mp_nexthop_len = 16; + + /* If BGP-4+ link-local nexthop is not link-local nexthop. */ + if (! IN6_IS_ADDR_LINKLOCAL (&peer->nexthop.v6_local)) + attr->mp_nexthop_len = 16; + } +#endif /* HAVE_IPV6 */ + + /* If this is EBGP peer and remove-private-AS is set. */ + if (peer_sort (peer) == BGP_PEER_EBGP + && peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) + && aspath_private_as_check (attr->aspath)) + attr->aspath = aspath_empty_get (); + + /* Route map & unsuppress-map apply. */ + if (ROUTE_MAP_OUT_NAME (filter) + || ri->suppress) + { + info.peer = peer; + info.attr = attr; + + /* The route reflector is not allowed to modify the attributes + of the reflected IBGP routes. */ + if (peer_sort (from) == BGP_PEER_IBGP + && peer_sort (peer) == BGP_PEER_IBGP) + { + dummy_attr = *attr; + info.attr = &dummy_attr; + } + + SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT); + + if (ri->suppress) + ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info); + else + ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info); + + peer->rmap_type = 0; + + if (ret == RMAP_DENYMATCH) + { + bgp_attr_flush (attr); + return 0; + } + } + return 1; +} + +int +bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) +{ + struct prefix *p; + struct bgp_info *ri; + struct bgp_info *new_select; + struct bgp_info *old_select; + struct listnode *nn; + struct peer *peer; + struct attr attr; + struct bgp_info *ri1; + struct bgp_info *ri2; + + p = &rn->p; + + /* bgp deterministic-med */ + new_select = NULL; + if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) + for (ri1 = rn->info; ri1; ri1 = ri1->next) + { + if (CHECK_FLAG (ri1->flags, BGP_INFO_DMED_CHECK)) + continue; + if (BGP_INFO_HOLDDOWN (ri1)) + continue; + + new_select = ri1; + if (ri1->next) + for (ri2 = ri1->next; ri2; ri2 = ri2->next) + { + if (CHECK_FLAG (ri2->flags, BGP_INFO_DMED_CHECK)) + continue; + if (BGP_INFO_HOLDDOWN (ri2)) + continue; + + if (aspath_cmp_left (ri1->attr->aspath, ri2->attr->aspath) + || aspath_cmp_left_confed (ri1->attr->aspath, + ri2->attr->aspath)) + { + if (bgp_info_cmp (bgp, ri2, new_select)) + { + UNSET_FLAG (new_select->flags, BGP_INFO_DMED_SELECTED); + new_select = ri2; + } + + SET_FLAG (ri2->flags, BGP_INFO_DMED_CHECK); + } + } + SET_FLAG (new_select->flags, BGP_INFO_DMED_CHECK); + SET_FLAG (new_select->flags, BGP_INFO_DMED_SELECTED); + } + + /* Check old selected route and new selected route. */ + old_select = NULL; + new_select = NULL; + for (ri = rn->info; ri; ri = ri->next) + { + if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) + old_select = ri; + + if (BGP_INFO_HOLDDOWN (ri)) + continue; + + if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED) + && (! CHECK_FLAG (ri->flags, BGP_INFO_DMED_SELECTED))) + { + UNSET_FLAG (ri->flags, BGP_INFO_DMED_CHECK); + continue; + } + UNSET_FLAG (ri->flags, BGP_INFO_DMED_CHECK); + UNSET_FLAG (ri->flags, BGP_INFO_DMED_SELECTED); + + if (bgp_info_cmp (bgp, ri, new_select)) + new_select = ri; + } + + /* Nothing to do. */ + if (old_select && old_select == new_select) + { + if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) + { + if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED)) + bgp_zebra_announce (p, old_select, bgp); + return 0; + } + } + + if (old_select) + UNSET_FLAG (old_select->flags, BGP_INFO_SELECTED); + if (new_select) + { + SET_FLAG (new_select->flags, BGP_INFO_SELECTED); + UNSET_FLAG (new_select->flags, BGP_INFO_ATTR_CHANGED); + } + + /* Check each BGP peer. */ + LIST_LOOP (bgp->peer, peer, nn) + { + /* Announce route to Established peer. */ + if (peer->status != Established) + continue; + + /* Address family configuration check. */ + if (! peer->afc_nego[afi][safi]) + continue; + + /* First update is deferred until ORF or ROUTE-REFRESH is received */ + if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) + continue; + + /* Announcement to peer->conf. If the route is filtered, + withdraw it. */ + if (new_select + && bgp_announce_check (new_select, peer, p, &attr, afi, safi)) + bgp_adj_out_set (rn, peer, p, &attr, afi, safi, new_select); + else + bgp_adj_out_unset (rn, peer, p, afi, safi); + } + + /* FIB update. */ + if (safi == SAFI_UNICAST && ! bgp->name && + ! bgp_option_check (BGP_OPT_NO_FIB)) + { + if (new_select + && new_select->type == ZEBRA_ROUTE_BGP + && new_select->sub_type == BGP_ROUTE_NORMAL) + bgp_zebra_announce (p, new_select, bgp); + else + { + /* Withdraw the route from the kernel. */ + if (old_select + && old_select->type == ZEBRA_ROUTE_BGP + && old_select->sub_type == BGP_ROUTE_NORMAL) + bgp_zebra_withdraw (p, old_select); + } + } + return 0; +} + +int +bgp_maximum_prefix_restart_timer (struct thread *thread) +{ + struct peer *peer; + + peer = THREAD_ARG (thread); + peer->t_pmax_restart = NULL; + + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s Maximum-prefix restart timer expired, restore peering", peer->host); + + peer_clear (peer); + + return 0; +} + +int +bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi, safi_t safi, int always) +{ + if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) + return 0; + + if (peer->pcount[afi][safi] > peer->pmax[afi][safi]) + { + if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT) + && ! always) + return 0; + + zlog (peer->log, LOG_INFO, + "%%MAXPFXEXCEED: No. of %s prefix received from %s %ld exceed, limit %ld", + afi_safi_print (afi, safi), peer->host, peer->pcount[afi][safi], + peer->pmax[afi][safi]); + SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT); + + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)) + return 0; + + { + char ndata[7]; + + ndata[0] = (u_char)(afi >> 8); + ndata[1] = (u_char) afi; + ndata[3] = (u_char)(peer->pmax[afi][safi] >> 24); + ndata[4] = (u_char)(peer->pmax[afi][safi] >> 16); + ndata[5] = (u_char)(peer->pmax[afi][safi] >> 8); + ndata[6] = (u_char)(peer->pmax[afi][safi]); + + if (safi == SAFI_MPLS_VPN) + safi = BGP_SAFI_VPNV4; + ndata[2] = (u_char) safi; + + SET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); + bgp_notify_send_with_data (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_MAX_PREFIX, ndata, 7); + } + + /* restart timer start */ + if (peer->pmax_restart[afi][safi]) + { + peer->v_pmax_restart = peer->pmax_restart[afi][safi] * 60; + + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s Maximum-prefix restart timer started for %d secs", + peer->host, peer->v_pmax_restart); + + BGP_TIMER_ON (peer->t_pmax_restart, bgp_maximum_prefix_restart_timer, + peer->v_pmax_restart); + } + + return 1; + } + else + UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT); + + if (peer->pcount[afi][safi] > (peer->pmax[afi][safi] * peer->pmax_threshold[afi][safi] / 100)) + { + if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_THRESHOLD) + && ! always) + return 0; + + zlog (peer->log, LOG_INFO, + "%%MAXPFX: No. of %s prefix received from %s reaches %ld, max %ld", + afi_safi_print (afi, safi), peer->host, peer->pcount[afi][safi], + peer->pmax[afi][safi]); + SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_THRESHOLD); + } + else + UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_THRESHOLD); + + return 0; +} + +void +bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, + afi_t afi, safi_t safi) +{ + if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) + { + if (! CHECK_FLAG (ri->flags, BGP_INFO_STALE)) + peer->pcount[afi][safi]--; + bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); + UNSET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_process (peer->bgp, rn, afi, safi); + } + bgp_info_delete (rn, ri); + bgp_info_free (ri); + bgp_unlock_node (rn); +} + +void +bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, + afi_t afi, safi_t safi, int force) +{ + int valid; + int status = BGP_DAMP_NONE; + + if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) + { + peer->pcount[afi][safi]--; + bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); + } + + if (! force) + { + if (CHECK_FLAG (peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) + && peer_sort (peer) == BGP_PEER_EBGP) + status = bgp_damp_withdraw (ri, rn, afi, safi, 0); + + if (status == BGP_DAMP_SUPPRESSED) + return; + } + + valid = CHECK_FLAG (ri->flags, BGP_INFO_VALID); + UNSET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_process (peer->bgp, rn, afi, safi); + + if (valid) + SET_FLAG (ri->flags, BGP_INFO_VALID); + + if (status != BGP_DAMP_USED) + { + bgp_info_delete (rn, ri); + bgp_info_free (ri); + bgp_unlock_node (rn); + } +} + +int +bgp_update (struct peer *peer, struct prefix *p, struct attr *attr, + afi_t afi, safi_t safi, int type, int sub_type, + struct prefix_rd *prd, u_char *tag, int soft_reconfig) +{ + int ret; + int aspath_loop_count = 0; + struct bgp_node *rn; + struct bgp *bgp; + struct attr new_attr; + struct attr *attr_new; + struct bgp_info *ri; + struct bgp_info *new; + char *reason; + char buf[SU_ADDRSTRLEN]; + + bgp = peer->bgp; + rn = bgp_afi_node_get (bgp, afi, safi, p, prd); + + /* When peer's soft reconfiguration enabled. Record input packet in + Adj-RIBs-In. */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) + && peer != bgp->peer_self && ! soft_reconfig) + bgp_adj_in_set (rn, peer, attr); + + /* Check previously received route. */ + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) + break; + + /* AS path local-as loop check. */ + if (peer->change_local_as) + { + if (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) + aspath_loop_count = 1; + + if (aspath_loop_check (attr->aspath, peer->change_local_as) > aspath_loop_count) + { + reason = "as-path contains our own AS;"; + goto filtered; + } + } + + /* AS path loop check. */ + if (aspath_loop_check (attr->aspath, bgp->as) > peer->allowas_in[afi][safi] + || (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) + && aspath_loop_check(attr->aspath, bgp->confed_id) + > peer->allowas_in[afi][safi])) + { + reason = "as-path contains our own AS;"; + goto filtered; + } + + /* Route reflector originator ID check. */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID) + && IPV4_ADDR_SAME (&bgp->router_id, &attr->originator_id)) + { + reason = "originator is us;"; + goto filtered; + } + + /* Route reflector cluster ID check. */ + if (bgp_cluster_filter (peer, attr)) + { + reason = "reflected from the same cluster;"; + goto filtered; + } + + /* Apply incoming filter. */ + if (bgp_input_filter (peer, p, attr, afi, safi) == FILTER_DENY) + { + reason = "filter;"; + goto filtered; + } + + /* Apply incoming route-map. */ + new_attr = *attr; + + if (bgp_input_modifier (peer, p, &new_attr, afi, safi) == RMAP_DENY) + { + reason = "route-map;"; + goto filtered; + } + + /* IPv4 unicast next hop check. */ + if (afi == AFI_IP && safi == SAFI_UNICAST) + { + /* If the peer is EBGP and nexthop is not on connected route, + discard it. */ + if (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl == 1 + && ! bgp_nexthop_check_ebgp (afi, &new_attr) + && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) + { + reason = "non-connected next-hop;"; + goto filtered; + } + + /* Next hop must not be 0.0.0.0 nor Class E address. Next hop + must not be my own address. */ + if (bgp_nexthop_self (afi, &new_attr) + || new_attr.nexthop.s_addr == 0 + || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000) + { + reason = "martian next-hop;"; + goto filtered; + } + } + + attr_new = bgp_attr_intern (&new_attr); + + /* If the update is implicit withdraw. */ + if (ri) + { + ri->uptime = time (NULL); + + /* Same attribute comes in. */ + if (attrhash_cmp (ri->attr, attr_new)) + { + UNSET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + + if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) + && peer_sort (peer) == BGP_PEER_EBGP + && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) + { + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_INFO, "%s rcvd %s/%d", + peer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + + peer->pcount[afi][safi]++; + ret = bgp_damp_update (ri, rn, afi, safi); + if (ret != BGP_DAMP_SUPPRESSED) + { + bgp_aggregate_increment (bgp, p, ri, afi, safi); + bgp_process (bgp, rn, afi, safi); + } + } + else + { + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_INFO, + "%s rcvd %s/%d...duplicate ignored", + peer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + + /* graceful restart STALE flag unset. */ + if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) + { + UNSET_FLAG (ri->flags, BGP_INFO_STALE); + peer->pcount[afi][safi]++; + } + } + + bgp_unlock_node (rn); + bgp_attr_unintern (attr_new); + return 0; + } + + /* Received Logging. */ + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_INFO, "%s rcvd %s/%d", + peer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + + /* graceful restart STALE flag unset. */ + if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) + { + UNSET_FLAG (ri->flags, BGP_INFO_STALE); + peer->pcount[afi][safi]++; + } + + /* The attribute is changed. */ + SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + + /* Update bgp route dampening information. */ + if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) + && peer_sort (peer) == BGP_PEER_EBGP) + { + /* This is implicit withdraw so we should update dampening + information. */ + if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) + bgp_damp_withdraw (ri, rn, afi, safi, 1); + else + peer->pcount[afi][safi]++; + } + + bgp_aggregate_decrement (bgp, p, ri, afi, safi); + + /* Update to new attribute. */ + bgp_attr_unintern (ri->attr); + ri->attr = attr_new; + + /* Update MPLS tag. */ + if (safi == SAFI_MPLS_VPN) + memcpy (ri->tag, tag, 3); + + /* Update bgp route dampening information. */ + if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) + && peer_sort (peer) == BGP_PEER_EBGP) + { + /* Now we do normal update dampening. */ + ret = bgp_damp_update (ri, rn, afi, safi); + if (ret == BGP_DAMP_SUPPRESSED) + { + bgp_unlock_node (rn); + return 0; + } + } + + /* Nexthop reachability check. */ + if ((afi == AFI_IP || afi == AFI_IP6) + && safi == SAFI_UNICAST + && (peer_sort (peer) == BGP_PEER_IBGP + || (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1) + || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) + { + if (bgp_nexthop_lookup (afi, peer, ri, NULL, NULL)) + SET_FLAG (ri->flags, BGP_INFO_VALID); + else + UNSET_FLAG (ri->flags, BGP_INFO_VALID); + } + else + SET_FLAG (ri->flags, BGP_INFO_VALID); + + /* Process change. */ + bgp_aggregate_increment (bgp, p, ri, afi, safi); + + bgp_process (bgp, rn, afi, safi); + bgp_unlock_node (rn); + return 0; + } + + /* Received Logging. */ + if (BGP_DEBUG (update, UPDATE_IN)) + { + zlog (peer->log, LOG_INFO, "%s rcvd %s/%d", + peer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + } + + /* Increment prefix counter */ + peer->pcount[afi][safi]++; + + /* Make new BGP info. */ + new = bgp_info_new (); + new->type = type; + new->sub_type = sub_type; + new->peer = peer; + new->attr = attr_new; + new->uptime = time (NULL); + + /* Update MPLS tag. */ + if (safi == SAFI_MPLS_VPN) + memcpy (new->tag, tag, 3); + + /* Nexthop reachability check. */ + if ((afi == AFI_IP || afi == AFI_IP6) + && safi == SAFI_UNICAST + && (peer_sort (peer) == BGP_PEER_IBGP + || (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1) + || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) + { + if (bgp_nexthop_lookup (afi, peer, new, NULL, NULL)) + SET_FLAG (new->flags, BGP_INFO_VALID); + else + UNSET_FLAG (new->flags, BGP_INFO_VALID); + } + else + SET_FLAG (new->flags, BGP_INFO_VALID); + + /* Aggregate address increment. */ + bgp_aggregate_increment (bgp, p, new, afi, safi); + + /* Register new BGP information. */ + bgp_info_add (rn, new); + + /* If maximum prefix count is configured and current prefix + count exeed it. */ + if (bgp_maximum_prefix_overflow (peer, afi, safi, 0)) + return -1; + + /* Process change. */ + bgp_process (bgp, rn, afi, safi); + + return 0; + + /* This BGP update is filtered. Log the reason then update BGP + entry. */ + filtered: + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_INFO, + "%s rcvd UPDATE about %s/%d -- DENIED due to: %s", + peer->host, + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen, reason); + + if (ri) + bgp_rib_withdraw (rn, ri, peer, afi, safi, 1); + + bgp_unlock_node (rn); + + return 0; +} + +int +bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr, + int afi, int safi, int type, int sub_type, struct prefix_rd *prd, + u_char *tag) +{ + struct bgp *bgp; + char buf[SU_ADDRSTRLEN]; + struct bgp_node *rn; + struct bgp_info *ri; + + bgp = peer->bgp; + + /* Logging. */ + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_INFO, "%s rcvd UPDATE about %s/%d -- withdrawn", + peer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + + /* Lookup node. */ + rn = bgp_afi_node_get (bgp, afi, safi, p, prd); + + /* If peer is soft reconfiguration enabled. Record input packet for + further calculation. */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) + && peer != bgp->peer_self) + bgp_adj_in_unset (rn, peer); + + /* Lookup withdrawn route. */ + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) + break; + + /* Withdraw specified route from routing table. */ + if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) + bgp_rib_withdraw (rn, ri, peer, afi, safi, 0); + else if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_INFO, + "%s Can't find the route %s/%d", peer->host, + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + + /* Unlock bgp_node_get() lock. */ + bgp_unlock_node (rn); + + return 0; +} + +void +bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) +{ + struct bgp *bgp; + struct attr attr; + struct aspath *aspath; + struct prefix p; + struct bgp_info binfo; + struct peer *from; + int ret = RMAP_DENYMATCH; + + bgp = peer->bgp; + from = bgp->peer_self; + + bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); + aspath = attr.aspath; + attr.local_pref = bgp->default_local_pref; + memcpy (&attr.nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN); + + if (afi == AFI_IP) + str2prefix ("0.0.0.0/0", &p); +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + { + str2prefix ("::/0", &p); + + /* IPv6 global nexthop must be included. */ + memcpy (&attr.mp_nexthop_global, &peer->nexthop.v6_global, + IPV6_MAX_BYTELEN); + attr.mp_nexthop_len = 16; + + /* If the peer is on shared nextwork and we have link-local + nexthop set it. */ + if (peer->shared_network + && !IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local)) + { + memcpy (&attr.mp_nexthop_local, &peer->nexthop.v6_local, + IPV6_MAX_BYTELEN); + attr.mp_nexthop_len = 32; + } + } +#endif /* HAVE_IPV6 */ + else + return; + + if (peer->default_rmap[afi][safi].name) + { + binfo.peer = bgp->peer_self; + binfo.attr = &attr; + + ret = route_map_apply (peer->default_rmap[afi][safi].map, &p, + RMAP_BGP, &binfo); + + if (ret == RMAP_DENYMATCH) + { + bgp_attr_flush (&attr); + withdraw = 1; + } + } + + if (withdraw) + { + if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) + bgp_default_withdraw_send (peer, afi, safi); + UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE); + } + else + { + SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE); + bgp_default_update_send (peer, &attr, afi, safi, from); + } + + aspath_unintern (aspath); +} + +static void +bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, + struct bgp_table *table) +{ + struct bgp_node *rn; + struct bgp_info *ri; + struct attr attr; + + if (! table) + table = peer->bgp->rib[afi][safi]; + + if (safi != SAFI_MPLS_VPN + && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) + bgp_default_originate (peer, afi, safi, 0); + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next(rn)) + for (ri = rn->info; ri; ri = ri->next) + if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->peer != peer) + { + if (bgp_announce_check (ri, peer, &rn->p, &attr, afi, safi)) + bgp_adj_out_set (rn, peer, &rn->p, &attr, afi, safi, ri); + else + bgp_adj_out_unset (rn, peer, &rn->p, afi, safi); + } +} + +void +bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp_node *rn; + struct bgp_table *table; + + if (peer->status != Established) + return; + + if (! peer->afc_nego[afi][safi]) + return; + + /* First update is deferred until ORF or ROUTE-REFRESH is received */ + if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) + return; + + if (safi != SAFI_MPLS_VPN) + bgp_announce_table (peer, afi, safi, NULL); + else + for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; + rn = bgp_route_next(rn)) + if ((table = (rn->info)) != NULL) + bgp_announce_table (peer, afi, safi, table); + + if (! peer->t_routeadv[afi][safi]) + bgp_routeadv_timer (peer, afi, safi); +} + +void +bgp_announce_route_all (struct peer *peer) +{ + afi_t afi; + safi_t safi; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + bgp_announce_route (peer, afi, safi); +} + +static void +bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi, + struct bgp_table *table) +{ + int ret; + struct bgp_node *rn; + struct bgp_adj_in *ain; + + if (! table) + table = peer->bgp->rib[afi][safi]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + for (ain = rn->adj_in; ain; ain = ain->next) + { + if (ain->peer == peer) + { + ret = bgp_update (peer, &rn->p, ain->attr, afi, safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, + NULL, NULL, 1); + if (ret < 0) + { + bgp_unlock_node (rn); + return; + } + continue; + } + } +} + +void +bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp_node *rn; + struct bgp_table *table; + + if (peer->status != Established) + return; + + if (safi != SAFI_MPLS_VPN) + bgp_soft_reconfig_table (peer, afi, safi, NULL); + else + for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; + rn = bgp_route_next (rn)) + if ((table = rn->info) != NULL) + bgp_soft_reconfig_table (peer, afi, safi, table); +} + +static void +bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, + struct bgp_table *table) +{ + struct bgp_node *rn; + struct bgp_adj_in *ain; + struct bgp_adj_out *aout; + struct bgp_info *ri; + + if (! table) + table = peer->bgp->rib[afi][safi]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + { + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == peer) + { + /* graceful restart STALE flag set. */ + if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT) + && peer->nsf[afi][safi] + && ! CHECK_FLAG (ri->flags, BGP_INFO_STALE) + && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY) + && ! CHECK_FLAG (ri->flags, BGP_INFO_DAMPED)) + { + SET_FLAG (ri->flags, BGP_INFO_STALE); + peer->pcount[afi][safi]--; + } + else + bgp_rib_remove (rn, ri, peer, afi, safi); + break; + } + for (ain = rn->adj_in; ain; ain = ain->next) + if (ain->peer == peer) + { + bgp_adj_in_remove (rn, ain); + bgp_unlock_node (rn); + break; + } + for (aout = rn->adj_out; aout; aout = aout->next) + if (aout->peer == peer) + { + bgp_adj_out_remove (rn, aout, peer, afi, safi); + bgp_unlock_node (rn); + break; + } + } +} + +void +bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp_node *rn; + struct bgp_table *table; + + if (safi != SAFI_MPLS_VPN) + bgp_clear_route_table (peer, afi, safi, NULL); + else + for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; + rn = bgp_route_next (rn)) + if ((table = rn->info) != NULL) + bgp_clear_route_table (peer, afi, safi, table); +} + +void +bgp_clear_route_all (struct peer *peer) +{ + afi_t afi; + safi_t safi; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + bgp_clear_route (peer, afi, safi); +} + +void +bgp_clear_adj_in (struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_adj_in *ain; + + table = peer->bgp->rib[afi][safi]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + for (ain = rn->adj_in; ain ; ain = ain->next) + if (ain->peer == peer) + { + bgp_adj_in_remove (rn, ain); + bgp_unlock_node (rn); + break; + } +} + +void +bgp_clear_stale_route (struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp_node *rn; + struct bgp_info *ri; + struct bgp_table *table; + + table = peer->bgp->rib[afi][safi]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + { + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == peer) + { + if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) + bgp_rib_remove (rn, ri, peer, afi, safi); + break; + } + } +} + +/* Delete all kernel routes. */ +void +bgp_terminate () +{ + struct bgp *bgp; + struct listnode *nn; + struct bgp_node *rn; + struct bgp_table *table; + struct bgp_info *ri; + + LIST_LOOP (bm->bgp, bgp, nn) + { + table = bgp->rib[AFI_IP][SAFI_UNICAST]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + for (ri = rn->info; ri; ri = ri->next) + if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_NORMAL) + bgp_zebra_withdraw (&rn->p, ri); + + table = bgp->rib[AFI_IP6][SAFI_UNICAST]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + for (ri = rn->info; ri; ri = ri->next) + if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_NORMAL) + bgp_zebra_withdraw (&rn->p, ri); + } +} + +void +bgp_reset () +{ + vty_reset (); + bgp_zclient_reset (); + access_list_reset (); + prefix_list_reset (); +} + +/* Parse NLRI stream. Withdraw NLRI is recognized by NULL attr + value. */ +int +bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) +{ + u_char *pnt; + u_char *lim; + struct prefix p; + int psize; + int ret; + + /* Check peer status. */ + if (peer->status != Established) + return 0; + + pnt = packet->nlri; + lim = pnt + packet->length; + + for (; pnt < lim; pnt += psize) + { + /* Clear prefix structure. */ + memset (&p, 0, sizeof (struct prefix)); + + /* Fetch prefix length. */ + p.prefixlen = *pnt++; + p.family = afi2family (packet->afi); + + /* Already checked in nlri_sanity_check(). We do double check + here. */ + if ((packet->afi == AFI_IP && p.prefixlen > 32) + || (packet->afi == AFI_IP6 && p.prefixlen > 128)) + return -1; + + /* Packet size overflow check. */ + psize = PSIZE (p.prefixlen); + + /* When packet overflow occur return immediately. */ + if (pnt + psize > lim) + return -1; + + /* Fetch prefix from NLRI packet. */ + memcpy (&p.u.prefix, pnt, psize); + + /* Check address. */ + if (packet->afi == AFI_IP && packet->safi == SAFI_UNICAST) + { + if (IN_CLASSD (ntohl (p.u.prefix4.s_addr))) + { + zlog (peer->log, LOG_ERR, + "IPv4 unicast NLRI is multicast address %s", + inet_ntoa (p.u.prefix4)); + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); + return -1; + } + } + +#ifdef HAVE_IPV6 + /* Check address. */ + if (packet->afi == AFI_IP6 && packet->safi == SAFI_UNICAST) + { + if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) + { + char buf[BUFSIZ]; + + zlog (peer->log, LOG_WARNING, + "IPv6 link-local NLRI received %s ignore this NLRI", + inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ)); + + continue; + } + } +#endif /* HAVE_IPV6 */ + + /* Normal process. */ + if (attr) + ret = bgp_update (peer, &p, attr, packet->afi, packet->safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0); + else + ret = bgp_withdraw (peer, &p, attr, packet->afi, packet->safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL); + + /* Address family configuration mismatch or maximum-prefix count + overflow. */ + if (ret < 0) + return -1; + } + + /* Packet length consistency check. */ + if (pnt != lim) + return -1; + + return 0; +} + +/* NLRI encode syntax check routine. */ +int +bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt, + bgp_size_t length) +{ + u_char *end; + u_char prefixlen; + int psize; + + end = pnt + length; + + /* RFC1771 6.3 The NLRI field in the UPDATE message is checked for + syntactic validity. If the field is syntactically incorrect, + then the Error Subcode is set to Invalid Network Field. */ + + while (pnt < end) + { + prefixlen = *pnt++; + + /* Prefix length check. */ + if ((afi == AFI_IP && prefixlen > 32) + || (afi == AFI_IP6 && prefixlen > 128)) + { + plog_err (peer->log, + "%s [Error] Update packet error (wrong prefix length %d)", + peer->host, prefixlen); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); + return -1; + } + + /* Packet size overflow check. */ + psize = PSIZE (prefixlen); + + if (pnt + psize > end) + { + plog_err (peer->log, + "%s [Error] Update packet error" + " (prefix data overflow prefix size is %d)", + peer->host, psize); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); + return -1; + } + + pnt += psize; + } + + /* Packet length consistency check. */ + if (pnt != end) + { + plog_err (peer->log, + "%s [Error] Update packet error" + " (prefix length mismatch with total length)", + peer->host); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); + return -1; + } + return 0; +} + +struct bgp_static * +bgp_static_new () +{ + struct bgp_static *new; + new = XMALLOC (MTYPE_BGP_STATIC, sizeof (struct bgp_static)); + memset (new, 0, sizeof (struct bgp_static)); + return new; +} + +void +bgp_static_free (struct bgp_static *bgp_static) +{ + if (bgp_static->rmap.name) + free (bgp_static->rmap.name); + XFREE (MTYPE_BGP_STATIC, bgp_static); +} + +void +bgp_static_update (struct bgp *bgp, struct prefix *p, + struct bgp_static *bgp_static, afi_t afi, safi_t safi) +{ + struct bgp_node *rn; + struct bgp_info *ri; + struct bgp_info *new; + struct bgp_info info; + struct attr attr; + struct attr attr_tmp; + struct attr *attr_new; + int ret; + + rn = bgp_afi_node_get (bgp, afi, safi, p, NULL); + + bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); + if (bgp_static) + { + attr.nexthop = bgp_static->igpnexthop; + attr.med = bgp_static->igpmetric; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + } + + /* Apply route-map. */ + if (bgp_static->rmap.name) + { + attr_tmp = attr; + info.peer = bgp->peer_self; + info.attr = &attr_tmp; + + ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); + + if (ret == RMAP_DENYMATCH) + { + /* Free uninterned attribute. */ + bgp_attr_flush (&attr_tmp); + + /* Unintern original. */ + aspath_unintern (attr.aspath); + bgp_static_withdraw (bgp, p, afi, safi); + return; + } + attr_new = bgp_attr_intern (&attr_tmp); + } + else + attr_new = bgp_attr_intern (&attr); + + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_STATIC) + break; + + if (ri) + { + if (attrhash_cmp (ri->attr, attr_new)) + { + bgp_unlock_node (rn); + bgp_attr_unintern (attr_new); + aspath_unintern (attr.aspath); + return; + } + else + { + /* The attribute is changed. */ + SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + + /* Rewrite BGP route information. */ + bgp_aggregate_decrement (bgp, p, ri, afi, safi); + bgp_attr_unintern (ri->attr); + ri->attr = attr_new; + ri->uptime = time (NULL); + + /* Process change. */ + bgp_aggregate_increment (bgp, p, ri, afi, safi); + bgp_process (bgp, rn, afi, safi); + bgp_unlock_node (rn); + aspath_unintern (attr.aspath); + return; + } + } + + /* Make new BGP info. */ + new = bgp_info_new (); + new->type = ZEBRA_ROUTE_BGP; + new->sub_type = BGP_ROUTE_STATIC; + new->peer = bgp->peer_self; + SET_FLAG (new->flags, BGP_INFO_VALID); + new->attr = attr_new; + new->uptime = time (NULL); + + /* Aggregate address increment. */ + bgp_aggregate_increment (bgp, p, new, afi, safi); + + /* Register new BGP information. */ + bgp_info_add (rn, new); + + /* Process change. */ + bgp_process (bgp, rn, afi, safi); + + /* Unintern original. */ + aspath_unintern (attr.aspath); +} + +void +bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi, + u_char safi, struct prefix_rd *prd, u_char *tag) +{ + struct bgp_node *rn; + struct bgp_info *new; + + rn = bgp_afi_node_get (bgp, afi, safi, p, prd); + + /* Make new BGP info. */ + new = bgp_info_new (); + new->type = ZEBRA_ROUTE_BGP; + new->sub_type = BGP_ROUTE_STATIC; + new->peer = bgp->peer_self; + new->attr = bgp_attr_default_intern (BGP_ORIGIN_IGP); + SET_FLAG (new->flags, BGP_INFO_VALID); + new->uptime = time (NULL); + memcpy (new->tag, tag, 3); + + /* Aggregate address increment. */ + bgp_aggregate_increment (bgp, p, (struct bgp_info *) new, afi, safi); + + /* Register new BGP information. */ + bgp_info_add (rn, (struct bgp_info *) new); + + /* Process change. */ + bgp_process (bgp, rn, afi, safi); +} + +void +bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi, + safi_t safi) +{ + struct bgp_node *rn; + struct bgp_info *ri; + + rn = bgp_afi_node_get (bgp, afi, safi, p, NULL); + + /* Check selected route and self inserted route. */ + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_STATIC) + break; + + /* Withdraw static BGP route from routing table. */ + if (ri) + { + bgp_aggregate_decrement (bgp, p, ri, afi, safi); + UNSET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_process (bgp, rn, afi, safi); + bgp_info_delete (rn, ri); + bgp_info_free (ri); + bgp_unlock_node (rn); + } + + /* Unlock bgp_node_lookup. */ + bgp_unlock_node (rn); +} + +void +bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi, + u_char safi, struct prefix_rd *prd, u_char *tag) +{ + struct bgp_node *rn; + struct bgp_info *ri; + + rn = bgp_afi_node_get (bgp, afi, safi, p, prd); + + /* Check selected route and self inserted route. */ + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_STATIC) + break; + + /* Withdraw static BGP route from routing table. */ + if (ri) + { + bgp_aggregate_decrement (bgp, p, ri, afi, safi); + UNSET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_process (bgp, rn, afi, safi); + bgp_info_delete (rn, ri); + bgp_info_free (ri); + bgp_unlock_node (rn); + } + + /* Unlock bgp_node_lookup. */ + bgp_unlock_node (rn); +} + +/* Configure static BGP network. When user don't run zebra, static + route should be installed as valid. */ +int +bgp_static_set (struct vty *vty, struct bgp *bgp, char *ip_str, u_int16_t afi, + u_char safi, char *rmap, int backdoor) +{ + int ret; + struct prefix p; + struct bgp_static *bgp_static; + struct bgp_node *rn; + int need_update = 0; + + /* Convert IP prefix string to struct prefix. */ + ret = str2prefix (ip_str, &p); + if (! ret) + { + vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } +#ifdef HAVE_IPV6 + if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) + { + vty_out (vty, "%% Malformed prefix (link-local address)%s", + VTY_NEWLINE); + return CMD_WARNING; + } +#endif /* HAVE_IPV6 */ + + apply_mask (&p); + + /* Set BGP static route configuration. */ + rn = bgp_node_get (bgp->route[afi][safi], &p); + + if (rn->info) + { + /* Configuration change. */ + bgp_static = rn->info; + + /* Check previous routes are installed into BGP. */ + if (! bgp_static->backdoor && bgp_static->valid) + need_update = 1; + + bgp_static->backdoor = backdoor; + if (rmap) + { + if (bgp_static->rmap.name) + free (bgp_static->rmap.name); + bgp_static->rmap.name = strdup (rmap); + bgp_static->rmap.map = route_map_lookup_by_name (rmap); + } + else + { + if (bgp_static->rmap.name) + free (bgp_static->rmap.name); + bgp_static->rmap.name = NULL; + bgp_static->rmap.map = NULL; + bgp_static->valid = 0; + } + bgp_unlock_node (rn); + } + else + { + /* New configuration. */ + bgp_static = bgp_static_new (); + bgp_static->backdoor = backdoor; + bgp_static->valid = 0; + bgp_static->igpmetric = 0; + bgp_static->igpnexthop.s_addr = 0; + if (rmap) + { + if (bgp_static->rmap.name) + free (bgp_static->rmap.name); + bgp_static->rmap.name = strdup (rmap); + bgp_static->rmap.map = route_map_lookup_by_name (rmap); + } + rn->info = bgp_static; + } + + /* If BGP scan is not enabled, we should install this route here. */ + if (! bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) + { + bgp_static->valid = 1; + + if (need_update) + bgp_static_withdraw (bgp, &p, afi, safi); + + if (! bgp_static->backdoor) + bgp_static_update (bgp, &p, bgp_static, afi, safi); + } + + return CMD_SUCCESS; +} + +/* Configure static BGP network. */ +int +bgp_static_unset (struct vty *vty, struct bgp *bgp, char *ip_str, + u_int16_t afi, u_char safi) +{ + int ret; + struct prefix p; + struct bgp_static *bgp_static; + struct bgp_node *rn; + + /* Convert IP prefix string to struct prefix. */ + ret = str2prefix (ip_str, &p); + if (! ret) + { + vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } +#ifdef HAVE_IPV6 + if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) + { + vty_out (vty, "%% Malformed prefix (link-local address)%s", + VTY_NEWLINE); + return CMD_WARNING; + } +#endif /* HAVE_IPV6 */ + + apply_mask (&p); + + rn = bgp_node_lookup (bgp->route[afi][safi], &p); + if (! rn) + { + vty_out (vty, "%% Can't find specified static route configuration.%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_static = rn->info; + + /* Update BGP RIB. */ + if (! bgp_static->backdoor) + bgp_static_withdraw (bgp, &p, afi, safi); + + /* Clear configuration. */ + bgp_static_free (bgp_static); + rn->info = NULL; + bgp_unlock_node (rn); + bgp_unlock_node (rn); + + return CMD_SUCCESS; +} + +/* Called from bgp_delete(). Delete all static routes from the BGP + instance. */ +void +bgp_static_delete (struct bgp *bgp) +{ + afi_t afi; + safi_t safi; + struct bgp_node *rn; + struct bgp_node *rm; + struct bgp_table *table; + struct bgp_static *bgp_static; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) + if (rn->info != NULL) + { + if (safi == SAFI_MPLS_VPN) + { + table = rn->info; + + for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) + { + bgp_static = rn->info; + bgp_static_withdraw_vpnv4 (bgp, &rm->p, + AFI_IP, SAFI_MPLS_VPN, + (struct prefix_rd *)&rn->p, + bgp_static->tag); + bgp_static_free (bgp_static); + rn->info = NULL; + bgp_unlock_node (rn); + } + } + else + { + bgp_static = rn->info; + bgp_static_withdraw (bgp, &rn->p, afi, safi); + bgp_static_free (bgp_static); + rn->info = NULL; + bgp_unlock_node (rn); + } + } +} + +int +bgp_static_set_vpnv4 (struct vty *vty, char *ip_str, char *rd_str, + char *tag_str) +{ + int ret; + struct prefix p; + struct prefix_rd prd; + struct bgp *bgp; + struct bgp_node *prn; + struct bgp_node *rn; + struct bgp_table *table; + struct bgp_static *bgp_static; + u_char tag[3]; + + bgp = vty->index; + + ret = str2prefix (ip_str, &p); + if (! ret) + { + vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask (&p); + + ret = str2prefix_rd (rd_str, &prd); + if (! ret) + { + vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2tag (tag_str, tag); + if (! ret) + { + vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE); + return CMD_WARNING; + } + + prn = bgp_node_get (bgp->route[AFI_IP][SAFI_MPLS_VPN], + (struct prefix *)&prd); + if (prn->info == NULL) + prn->info = bgp_table_init (); + else + bgp_unlock_node (prn); + table = prn->info; + + rn = bgp_node_get (table, &p); + + if (rn->info) + { + vty_out (vty, "%% Same network configuration exists%s", VTY_NEWLINE); + bgp_unlock_node (rn); + } + else + { + /* New configuration. */ + bgp_static = bgp_static_new (); + bgp_static->valid = 1; + memcpy (bgp_static->tag, tag, 3); + rn->info = bgp_static; + + bgp_static_update_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag); + } + + return CMD_SUCCESS; +} + +/* Configure static BGP network. */ +int +bgp_static_unset_vpnv4 (struct vty *vty, char *ip_str, char *rd_str, + char *tag_str) +{ + int ret; + struct bgp *bgp; + struct prefix p; + struct prefix_rd prd; + struct bgp_node *prn; + struct bgp_node *rn; + struct bgp_table *table; + struct bgp_static *bgp_static; + u_char tag[3]; + + bgp = vty->index; + + /* Convert IP prefix string to struct prefix. */ + ret = str2prefix (ip_str, &p); + if (! ret) + { + vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask (&p); + + ret = str2prefix_rd (rd_str, &prd); + if (! ret) + { + vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2tag (tag_str, tag); + if (! ret) + { + vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE); + return CMD_WARNING; + } + + prn = bgp_node_get (bgp->route[AFI_IP][SAFI_MPLS_VPN], + (struct prefix *)&prd); + if (prn->info == NULL) + prn->info = bgp_table_init (); + else + bgp_unlock_node (prn); + table = prn->info; + + rn = bgp_node_lookup (table, &p); + + if (rn) + { + bgp_static_withdraw_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag); + + bgp_static = rn->info; + bgp_static_free (bgp_static); + rn->info = NULL; + bgp_unlock_node (rn); + bgp_unlock_node (rn); + } + else + vty_out (vty, "%% Can't find the route%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN (bgp_network, + bgp_network_cmd, + "network A.B.C.D/M", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_static_set (vty, vty->index, argv[0], + AFI_IP, bgp_node_safi (vty), NULL, 0); +} + +DEFUN (bgp_network_route_map, + bgp_network_route_map_cmd, + "network A.B.C.D/M route-map WORD", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") +{ + return bgp_static_set (vty, vty->index, argv[0], + AFI_IP, bgp_node_safi (vty), argv[1], 0); +} + +DEFUN (bgp_network_backdoor, + bgp_network_backdoor_cmd, + "network A.B.C.D/M backdoor", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify a BGP backdoor route\n") +{ + return bgp_static_set (vty, vty->index, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (bgp_network_mask, + bgp_network_mask_cmd, + "network A.B.C.D mask A.B.C.D", + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_set (vty, vty->index, prefix_str, + AFI_IP, bgp_node_safi (vty), NULL, 0); +} + +DEFUN (bgp_network_mask_route_map, + bgp_network_mask_route_map_cmd, + "network A.B.C.D mask A.B.C.D route-map WORD", + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_set (vty, vty->index, prefix_str, + AFI_IP, bgp_node_safi (vty), argv[2], 0); +} + +DEFUN (bgp_network_mask_backdoor, + bgp_network_mask_backdoor_cmd, + "network A.B.C.D mask A.B.C.D backdoor", + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Specify a BGP backdoor route\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (bgp_network_mask_natural, + bgp_network_mask_natural_cmd, + "network A.B.C.D", + "Specify a network to announce via BGP\n" + "Network number\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_set (vty, vty->index, prefix_str, + AFI_IP, bgp_node_safi (vty), NULL, 0); +} + +DEFUN (bgp_network_mask_natural_route_map, + bgp_network_mask_natural_route_map_cmd, + "network A.B.C.D route-map WORD", + "Specify a network to announce via BGP\n" + "Network number\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_set (vty, vty->index, prefix_str, + AFI_IP, bgp_node_safi (vty), argv[1], 0); +} + +DEFUN (bgp_network_mask_natural_backdoor, + bgp_network_mask_natural_backdoor_cmd, + "network A.B.C.D backdoor", + "Specify a network to announce via BGP\n" + "Network number\n" + "Specify a BGP backdoor route\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (no_bgp_network, + no_bgp_network_cmd, + "no network A.B.C.D/M", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_static_unset (vty, vty->index, argv[0], AFI_IP, + bgp_node_safi (vty)); +} + +ALIAS (no_bgp_network, + no_bgp_network_route_map_cmd, + "no network A.B.C.D/M route-map WORD", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Route-map to modify the attributes\n" + "Name of the route map\n"); + +ALIAS (no_bgp_network, + no_bgp_network_backdoor_cmd, + "no network A.B.C.D/M backdoor", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify a BGP backdoor route\n"); + +DEFUN (no_bgp_network_mask, + no_bgp_network_mask_cmd, + "no network A.B.C.D mask A.B.C.D", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP, + bgp_node_safi (vty)); +} + +ALIAS (no_bgp_network_mask, + no_bgp_network_mask_route_map_cmd, + "no network A.B.C.D mask A.B.C.D route-map WORD", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Route-map to modify the attributes\n" + "Name of the route map\n"); + +ALIAS (no_bgp_network_mask, + no_bgp_network_mask_backdoor_cmd, + "no network A.B.C.D mask A.B.C.D backdoor", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Specify a BGP backdoor route\n"); + +DEFUN (no_bgp_network_mask_natural, + no_bgp_network_mask_natural_cmd, + "no network A.B.C.D", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP, + bgp_node_safi (vty)); +} + +ALIAS (no_bgp_network_mask_natural, + no_bgp_network_mask_natural_route_map_cmd, + "no network A.B.C.D route-map WORD", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "Route-map to modify the attributes\n" + "Name of the route map\n"); + +ALIAS (no_bgp_network_mask_natural, + no_bgp_network_mask_natural_backdoor_cmd, + "no network A.B.C.D backdoor", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "Specify a BGP backdoor route\n"); + +#ifdef HAVE_IPV6 +DEFUN (ipv6_bgp_network, + ipv6_bgp_network_cmd, + "network X:X::X:X/M", + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n") +{ + return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +DEFUN (ipv6_bgp_network_route_map, + ipv6_bgp_network_route_map_cmd, + "network X:X::X:X/M route-map WORD", + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") +{ + return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, + bgp_node_safi (vty), argv[1], 0); +} + +DEFUN (no_ipv6_bgp_network, + no_ipv6_bgp_network_cmd, + "no network X:X::X:X/M", + NO_STR + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n") +{ + return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST); +} + +ALIAS (no_ipv6_bgp_network, + no_ipv6_bgp_network_route_map_cmd, + "no network X:X::X:X/M route-map WORD", + NO_STR + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n" + "Route-map to modify the attributes\n" + "Name of the route map\n"); + +ALIAS (ipv6_bgp_network, + old_ipv6_bgp_network_cmd, + "ipv6 bgp network X:X::X:X/M", + IPV6_STR + BGP_STR + "Specify a network to announce via BGP\n" + "IPv6 prefix /, e.g., 3ffe::/16\n"); + +ALIAS (no_ipv6_bgp_network, + old_no_ipv6_bgp_network_cmd, + "no ipv6 bgp network X:X::X:X/M", + NO_STR + IPV6_STR + BGP_STR + "Specify a network to announce via BGP\n" + "IPv6 prefix /, e.g., 3ffe::/16\n"); +#endif /* HAVE_IPV6 */ + +/* Aggreagete address: + + advertise-map Set condition to advertise attribute + as-set Generate AS set path information + attribute-map Set attributes of aggregate + route-map Set parameters of aggregate + summary-only Filter more specific routes from updates + suppress-map Conditionally filter more specific routes from updates + + */ +struct bgp_aggregate +{ + /* Summary-only flag. */ + u_char summary_only; + + /* AS set generation. */ + u_char as_set; + + /* Route-map for aggregated route. */ + struct route_map *map; + + /* Suppress-count. */ + unsigned long count; + + /* SAFI configuration. */ + safi_t safi; +}; + +struct bgp_aggregate * +bgp_aggregate_new () +{ + struct bgp_aggregate *new; + new = XMALLOC (MTYPE_BGP_AGGREGATE, sizeof (struct bgp_aggregate)); + memset (new, 0, sizeof (struct bgp_aggregate)); + return new; +} + +void +bgp_aggregate_free (struct bgp_aggregate *aggregate) +{ + XFREE (MTYPE_BGP_AGGREGATE, aggregate); +} + +void +bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, + afi_t afi, safi_t safi, struct bgp_info *del, + struct bgp_aggregate *aggregate) +{ + struct bgp_table *table; + struct bgp_node *top; + struct bgp_node *rn; + u_char origin; + struct aspath *aspath = NULL; + struct aspath *asmerge = NULL; + struct community *community = NULL; + struct community *commerge = NULL; + struct in_addr nexthop; + u_int32_t med = 0; + struct bgp_info *ri; + struct bgp_info *new; + int first = 1; + unsigned long match = 0; + + /* Record adding route's nexthop and med. */ + if (rinew) + { + nexthop = rinew->attr->nexthop; + med = rinew->attr->med; + } + + /* ORIGIN attribute: If at least one route among routes that are + aggregated has ORIGIN with the value INCOMPLETE, then the + aggregated route must have the ORIGIN attribute with the value + INCOMPLETE. Otherwise, if at least one route among routes that + are aggregated has ORIGIN with the value EGP, then the aggregated + route must have the origin attribute with the value EGP. In all + other case the value of the ORIGIN attribute of the aggregated + route is INTERNAL. */ + origin = BGP_ORIGIN_IGP; + + table = bgp->rib[afi][safi]; + + top = bgp_node_get (table, p); + for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top)) + if (rn->p.prefixlen > p->prefixlen) + { + match = 0; + + for (ri = rn->info; ri; ri = ri->next) + { + if (BGP_INFO_HOLDDOWN (ri)) + continue; + + if (del && ri == del) + continue; + + if (! rinew && first) + { + nexthop = ri->attr->nexthop; + med = ri->attr->med; + first = 0; + } + +#ifdef AGGREGATE_NEXTHOP_CHECK + if (! IPV4_ADDR_SAME (&ri->attr->nexthop, &nexthop) + || ri->attr->med != med) + { + if (aspath) + aspath_free (aspath); + if (community) + community_free (community); + bgp_unlock_node (rn); + bgp_unlock_node (top); + return; + } +#endif /* AGGREGATE_NEXTHOP_CHECK */ + + if (ri->sub_type != BGP_ROUTE_AGGREGATE) + { + if (aggregate->summary_only) + { + ri->suppress++; + SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + match++; + } + + aggregate->count++; + + if (aggregate->as_set) + { + if (origin < ri->attr->origin) + origin = ri->attr->origin; + + if (aspath) + { + asmerge = aspath_aggregate (aspath, ri->attr->aspath); + aspath_free (aspath); + aspath = asmerge; + } + else + aspath = aspath_dup (ri->attr->aspath); + + if (ri->attr->community) + { + if (community) + { + commerge = community_merge (community, + ri->attr->community); + community = community_uniq_sort (commerge); + community_free (commerge); + } + else + community = community_dup (ri->attr->community); + } + } + } + } + if (match) + bgp_process (bgp, rn, afi, safi); + } + bgp_unlock_node (top); + + if (rinew) + { + aggregate->count++; + + if (aggregate->summary_only) + rinew->suppress++; + + if (aggregate->as_set) + { + if (origin < rinew->attr->origin) + origin = rinew->attr->origin; + + if (aspath) + { + asmerge = aspath_aggregate (aspath, rinew->attr->aspath); + aspath_free (aspath); + aspath = asmerge; + } + else + aspath = aspath_dup (rinew->attr->aspath); + + if (rinew->attr->community) + { + if (community) + { + commerge = community_merge (community, + rinew->attr->community); + community = community_uniq_sort (commerge); + community_free (commerge); + } + else + community = community_dup (rinew->attr->community); + } + } + } + + if (aggregate->count > 0) + { + rn = bgp_node_get (table, p); + new = bgp_info_new (); + new->type = ZEBRA_ROUTE_BGP; + new->sub_type = BGP_ROUTE_AGGREGATE; + new->peer = bgp->peer_self; + SET_FLAG (new->flags, BGP_INFO_VALID); + new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set); + new->uptime = time (NULL); + + bgp_info_add (rn, new); + bgp_process (bgp, rn, afi, safi); + } + else + { + if (aspath) + aspath_free (aspath); + if (community) + community_free (community); + } +} + +void bgp_aggregate_delete (struct bgp *, struct prefix *, afi_t, safi_t, + struct bgp_aggregate *); + +void +bgp_aggregate_increment (struct bgp *bgp, struct prefix *p, + struct bgp_info *ri, afi_t afi, safi_t safi) +{ + struct bgp_node *child; + struct bgp_node *rn; + struct bgp_aggregate *aggregate; + + /* MPLS-VPN aggregation is not yet supported. */ + if (safi == SAFI_MPLS_VPN) + return; + + if (p->prefixlen == 0) + return; + + if (BGP_INFO_HOLDDOWN (ri)) + return; + + child = bgp_node_get (bgp->aggregate[afi][safi], p); + + /* Aggregate address configuration check. */ + for (rn = child; rn; rn = rn->parent) + if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen) + { + bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate); + bgp_aggregate_route (bgp, &rn->p, ri, afi, safi, NULL, aggregate); + } + bgp_unlock_node (child); +} + +void +bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p, + struct bgp_info *del, afi_t afi, safi_t safi) +{ + struct bgp_node *child; + struct bgp_node *rn; + struct bgp_aggregate *aggregate; + + /* MPLS-VPN aggregation is not yet supported. */ + if (safi == SAFI_MPLS_VPN) + return; + + if (p->prefixlen == 0) + return; + + child = bgp_node_get (bgp->aggregate[afi][safi], p); + + /* Aggregate address configuration check. */ + for (rn = child; rn; rn = rn->parent) + if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen) + { + bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate); + bgp_aggregate_route (bgp, &rn->p, NULL, afi, safi, del, aggregate); + } + bgp_unlock_node (child); +} + +void +bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, + struct bgp_aggregate *aggregate) +{ + struct bgp_table *table; + struct bgp_node *top; + struct bgp_node *rn; + struct bgp_info *new; + struct bgp_info *ri; + unsigned long match; + u_char origin = BGP_ORIGIN_IGP; + struct aspath *aspath = NULL; + struct aspath *asmerge = NULL; + struct community *community = NULL; + struct community *commerge = NULL; + + table = bgp->rib[afi][safi]; + + /* Sanity check. */ + if (afi == AFI_IP && p->prefixlen == IPV4_MAX_BITLEN) + return; + if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN) + return; + + /* If routes exists below this node, generate aggregate routes. */ + top = bgp_node_get (table, p); + for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top)) + if (rn->p.prefixlen > p->prefixlen) + { + match = 0; + + for (ri = rn->info; ri; ri = ri->next) + { + if (BGP_INFO_HOLDDOWN (ri)) + continue; + + if (ri->sub_type != BGP_ROUTE_AGGREGATE) + { + /* summary-only aggregate route suppress aggregated + route announcement. */ + if (aggregate->summary_only) + { + ri->suppress++; + SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + match++; + } + /* as-set aggregate route generate origin, as path, + community aggregation. */ + if (aggregate->as_set) + { + if (origin < ri->attr->origin) + origin = ri->attr->origin; + + if (aspath) + { + asmerge = aspath_aggregate (aspath, ri->attr->aspath); + aspath_free (aspath); + aspath = asmerge; + } + else + aspath = aspath_dup (ri->attr->aspath); + + if (ri->attr->community) + { + if (community) + { + commerge = community_merge (community, + ri->attr->community); + community = community_uniq_sort (commerge); + community_free (commerge); + } + else + community = community_dup (ri->attr->community); + } + } + aggregate->count++; + } + } + + /* If this node is suppressed, process the change. */ + if (match) + bgp_process (bgp, rn, afi, safi); + } + bgp_unlock_node (top); + + /* Add aggregate route to BGP table. */ + if (aggregate->count) + { + rn = bgp_node_get (table, p); + + new = bgp_info_new (); + new->type = ZEBRA_ROUTE_BGP; + new->sub_type = BGP_ROUTE_AGGREGATE; + new->peer = bgp->peer_self; + SET_FLAG (new->flags, BGP_INFO_VALID); + new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set); + new->uptime = time (NULL); + + bgp_info_add (rn, new); + + /* Process change. */ + bgp_process (bgp, rn, afi, safi); + } +} + +void +bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi, + safi_t safi, struct bgp_aggregate *aggregate) +{ + struct bgp_table *table; + struct bgp_node *top; + struct bgp_node *rn; + struct bgp_info *ri; + unsigned long match; + + table = bgp->rib[afi][safi]; + + if (afi == AFI_IP && p->prefixlen == IPV4_MAX_BITLEN) + return; + if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN) + return; + + /* If routes exists below this node, generate aggregate routes. */ + top = bgp_node_get (table, p); + for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top)) + if (rn->p.prefixlen > p->prefixlen) + { + match = 0; + + for (ri = rn->info; ri; ri = ri->next) + { + if (BGP_INFO_HOLDDOWN (ri)) + continue; + + if (ri->sub_type != BGP_ROUTE_AGGREGATE) + { + if (aggregate->summary_only) + { + ri->suppress--; + + if (ri->suppress == 0) + { + SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + match++; + } + } + aggregate->count--; + } + } + + /* If this node is suppressed, process the change. */ + if (match) + bgp_process (bgp, rn, afi, safi); + } + bgp_unlock_node (top); + + /* Delete aggregate route from BGP table. */ + rn = bgp_node_get (table, p); + + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_AGGREGATE) + break; + + /* Withdraw static BGP route from routing table. */ + if (ri) + { + UNSET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_process (bgp, rn, afi, safi); + bgp_info_delete (rn, ri); + bgp_info_free (ri); + bgp_unlock_node (rn); + } + + /* Unlock bgp_node_lookup. */ + bgp_unlock_node (rn); +} + +/* Aggregate route attribute. */ +#define AGGREGATE_SUMMARY_ONLY 1 +#define AGGREGATE_AS_SET 1 + +int +bgp_aggregate_set (struct vty *vty, char *prefix_str, afi_t afi, safi_t safi, + u_char summary_only, u_char as_set) +{ + int ret; + struct prefix p; + struct bgp_node *rn; + struct bgp *bgp; + struct bgp_aggregate *aggregate; + + /* Convert string to prefix structure. */ + ret = str2prefix (prefix_str, &p); + if (!ret) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask (&p); + + /* Get BGP structure. */ + bgp = vty->index; + + /* Old configuration check. */ + rn = bgp_node_get (bgp->aggregate[afi][safi], &p); + + if (rn->info) + { + vty_out (vty, "There is already same aggregate network.%s", VTY_NEWLINE); + bgp_unlock_node (rn); + return CMD_WARNING; + } + + /* Make aggregate address structure. */ + aggregate = bgp_aggregate_new (); + aggregate->summary_only = summary_only; + aggregate->as_set = as_set; + aggregate->safi = safi; + rn->info = aggregate; + + /* Aggregate address insert into BGP routing table. */ + if (safi & SAFI_UNICAST) + bgp_aggregate_add (bgp, &p, afi, SAFI_UNICAST, aggregate); + if (safi & SAFI_MULTICAST) + bgp_aggregate_add (bgp, &p, afi, SAFI_MULTICAST, aggregate); + + return CMD_SUCCESS; +} + +int +bgp_aggregate_unset (struct vty *vty, char *prefix_str, afi_t afi, safi_t safi) +{ + int ret; + struct prefix p; + struct bgp_node *rn; + struct bgp *bgp; + struct bgp_aggregate *aggregate; + + /* Convert string to prefix structure. */ + ret = str2prefix (prefix_str, &p); + if (!ret) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask (&p); + + /* Get BGP structure. */ + bgp = vty->index; + + /* Old configuration check. */ + rn = bgp_node_lookup (bgp->aggregate[afi][safi], &p); + if (! rn) + { + vty_out (vty, "%% There is no aggregate-address configuration.%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + aggregate = rn->info; + if (aggregate->safi & SAFI_UNICAST) + bgp_aggregate_delete (bgp, &p, afi, SAFI_UNICAST, aggregate); + if (aggregate->safi & SAFI_MULTICAST) + bgp_aggregate_delete (bgp, &p, afi, SAFI_MULTICAST, aggregate); + + /* Unlock aggregate address configuration. */ + rn->info = NULL; + bgp_aggregate_free (aggregate); + bgp_unlock_node (rn); + bgp_unlock_node (rn); + + return CMD_SUCCESS; +} + +DEFUN (aggregate_address, + aggregate_address_cmd, + "aggregate-address A.B.C.D/M", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n") +{ + return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), 0, 0); +} + +DEFUN (aggregate_address_mask, + aggregate_address_mask_cmd, + "aggregate-address A.B.C.D A.B.C.D", + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty), + 0, 0); +} + +DEFUN (aggregate_address_summary_only, + aggregate_address_summary_only_cmd, + "aggregate-address A.B.C.D/M summary-only", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n") +{ + return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), + AGGREGATE_SUMMARY_ONLY, 0); +} + +DEFUN (aggregate_address_mask_summary_only, + aggregate_address_mask_summary_only_cmd, + "aggregate-address A.B.C.D A.B.C.D summary-only", + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Filter more specific routes from updates\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty), + AGGREGATE_SUMMARY_ONLY, 0); +} + +DEFUN (aggregate_address_as_set, + aggregate_address_as_set_cmd, + "aggregate-address A.B.C.D/M as-set", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Generate AS set path information\n") +{ + return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), + 0, AGGREGATE_AS_SET); +} + +DEFUN (aggregate_address_mask_as_set, + aggregate_address_mask_as_set_cmd, + "aggregate-address A.B.C.D A.B.C.D as-set", + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Generate AS set path information\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty), + 0, AGGREGATE_AS_SET); +} + + +DEFUN (aggregate_address_as_set_summary, + aggregate_address_as_set_summary_cmd, + "aggregate-address A.B.C.D/M as-set summary-only", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Generate AS set path information\n" + "Filter more specific routes from updates\n") +{ + return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), + AGGREGATE_SUMMARY_ONLY, AGGREGATE_AS_SET); +} + +ALIAS (aggregate_address_as_set_summary, + aggregate_address_summary_as_set_cmd, + "aggregate-address A.B.C.D/M summary-only as-set", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n" + "Generate AS set path information\n"); + +DEFUN (aggregate_address_mask_as_set_summary, + aggregate_address_mask_as_set_summary_cmd, + "aggregate-address A.B.C.D A.B.C.D as-set summary-only", + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Generate AS set path information\n" + "Filter more specific routes from updates\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty), + AGGREGATE_SUMMARY_ONLY, AGGREGATE_AS_SET); +} + +ALIAS (aggregate_address_mask_as_set_summary, + aggregate_address_mask_summary_as_set_cmd, + "aggregate-address A.B.C.D A.B.C.D summary-only as-set", + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Filter more specific routes from updates\n" + "Generate AS set path information\n"); + +DEFUN (no_aggregate_address, + no_aggregate_address_cmd, + "no aggregate-address A.B.C.D/M", + NO_STR + "Configure BGP aggregate entries\n" + "Aggregate prefix\n") +{ + return bgp_aggregate_unset (vty, argv[0], AFI_IP, bgp_node_safi (vty)); +} + +ALIAS (no_aggregate_address, + no_aggregate_address_summary_only_cmd, + "no aggregate-address A.B.C.D/M summary-only", + NO_STR + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n"); + +ALIAS (no_aggregate_address, + no_aggregate_address_as_set_cmd, + "no aggregate-address A.B.C.D/M as-set", + NO_STR + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Generate AS set path information\n"); + +ALIAS (no_aggregate_address, + no_aggregate_address_as_set_summary_cmd, + "no aggregate-address A.B.C.D/M as-set summary-only", + NO_STR + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Generate AS set path information\n" + "Filter more specific routes from updates\n"); + +ALIAS (no_aggregate_address, + no_aggregate_address_summary_as_set_cmd, + "no aggregate-address A.B.C.D/M summary-only as-set", + NO_STR + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n" + "Generate AS set path information\n"); + +DEFUN (no_aggregate_address_mask, + no_aggregate_address_mask_cmd, + "no aggregate-address A.B.C.D A.B.C.D", + NO_STR + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_aggregate_unset (vty, prefix_str, AFI_IP, bgp_node_safi (vty)); +} + +ALIAS (no_aggregate_address_mask, + no_aggregate_address_mask_summary_only_cmd, + "no aggregate-address A.B.C.D A.B.C.D summary-only", + NO_STR + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Filter more specific routes from updates\n"); + +ALIAS (no_aggregate_address_mask, + no_aggregate_address_mask_as_set_cmd, + "no aggregate-address A.B.C.D A.B.C.D as-set", + NO_STR + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Generate AS set path information\n"); + +ALIAS (no_aggregate_address_mask, + no_aggregate_address_mask_as_set_summary_cmd, + "no aggregate-address A.B.C.D A.B.C.D as-set summary-only", + NO_STR + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Generate AS set path information\n" + "Filter more specific routes from updates\n"); + +ALIAS (no_aggregate_address_mask, + no_aggregate_address_mask_summary_as_set_cmd, + "no aggregate-address A.B.C.D A.B.C.D summary-only as-set", + NO_STR + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Filter more specific routes from updates\n" + "Generate AS set path information\n"); + +#ifdef HAVE_IPV6 +DEFUN (ipv6_aggregate_address, + ipv6_aggregate_address_cmd, + "aggregate-address X:X::X:X/M", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n") +{ + return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST, 0, 0); +} + +DEFUN (ipv6_aggregate_address_summary_only, + ipv6_aggregate_address_summary_only_cmd, + "aggregate-address X:X::X:X/M summary-only", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n") +{ + return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST, + AGGREGATE_SUMMARY_ONLY, 0); +} + +DEFUN (no_ipv6_aggregate_address, + no_ipv6_aggregate_address_cmd, + "no aggregate-address X:X::X:X/M", + NO_STR + "Configure BGP aggregate entries\n" + "Aggregate prefix\n") +{ + return bgp_aggregate_unset (vty, argv[0], AFI_IP6, SAFI_UNICAST); +} + +DEFUN (no_ipv6_aggregate_address_summary_only, + no_ipv6_aggregate_address_summary_only_cmd, + "no aggregate-address X:X::X:X/M summary-only", + NO_STR + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n") +{ + return bgp_aggregate_unset (vty, argv[0], AFI_IP6, SAFI_UNICAST); +} + +ALIAS (ipv6_aggregate_address, + old_ipv6_aggregate_address_cmd, + "ipv6 bgp aggregate-address X:X::X:X/M", + IPV6_STR + BGP_STR + "Configure BGP aggregate entries\n" + "Aggregate prefix\n"); + +ALIAS (ipv6_aggregate_address_summary_only, + old_ipv6_aggregate_address_summary_only_cmd, + "ipv6 bgp aggregate-address X:X::X:X/M summary-only", + IPV6_STR + BGP_STR + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n"); + +ALIAS (no_ipv6_aggregate_address, + old_no_ipv6_aggregate_address_cmd, + "no ipv6 bgp aggregate-address X:X::X:X/M", + NO_STR + IPV6_STR + BGP_STR + "Configure BGP aggregate entries\n" + "Aggregate prefix\n"); + +ALIAS (no_ipv6_aggregate_address_summary_only, + old_no_ipv6_aggregate_address_summary_only_cmd, + "no ipv6 bgp aggregate-address X:X::X:X/M summary-only", + NO_STR + IPV6_STR + BGP_STR + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n"); +#endif /* HAVE_IPV6 */ + +/* Redistribute route treatment. */ +void +bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, + u_int32_t metric, u_char type) +{ + struct bgp *bgp; + struct listnode *nn; + struct bgp_info *new; + struct bgp_info *bi; + struct bgp_info info; + struct bgp_node *bn; + struct attr attr; + struct attr attr_new; + struct attr *new_attr; + afi_t afi; + int ret; + + /* Make default attribute. */ + bgp_attr_default_set (&attr, BGP_ORIGIN_INCOMPLETE); + if (nexthop) + attr.nexthop = *nexthop; + + attr.med = metric; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + + LIST_LOOP (bm->bgp, bgp, nn) + { + afi = family2afi (p->family); + + if (bgp->redist[afi][type]) + { + /* Copy attribute for modification. */ + attr_new = attr; + + if (bgp->redist_metric_flag[afi][type]) + attr_new.med = bgp->redist_metric[afi][type]; + + /* Apply route-map. */ + if (bgp->rmap[afi][type].map) + { + info.peer = bgp->peer_self; + info.attr = &attr_new; + + ret = route_map_apply (bgp->rmap[afi][type].map, p, RMAP_BGP, + &info); + if (ret == RMAP_DENYMATCH) + { + /* Free uninterned attribute. */ + bgp_attr_flush (&attr_new); + + /* Unintern original. */ + aspath_unintern (attr.aspath); + bgp_redistribute_delete (p, type); + return; + } + } + + bn = bgp_afi_node_get (bgp, afi, SAFI_UNICAST, p, NULL); + new_attr = bgp_attr_intern (&attr_new); + + for (bi = bn->info; bi; bi = bi->next) + if (bi->peer == bgp->peer_self + && bi->sub_type == BGP_ROUTE_REDISTRIBUTE) + break; + + if (bi) + { + if (attrhash_cmp (bi->attr, new_attr)) + { + bgp_attr_unintern (new_attr); + aspath_unintern (attr.aspath); + bgp_unlock_node (bn); + return; + } + else + { + /* The attribute is changed. */ + SET_FLAG (bi->flags, BGP_INFO_ATTR_CHANGED); + + /* Rewrite BGP route information. */ + bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST); + bgp_attr_unintern (bi->attr); + bi->attr = new_attr; + bi->uptime = time (NULL); + + /* Process change. */ + bgp_aggregate_increment (bgp, p, bi, afi, SAFI_UNICAST); + bgp_process (bgp, bn, afi, SAFI_UNICAST); + bgp_unlock_node (bn); + aspath_unintern (attr.aspath); + return; + } + } + + new = bgp_info_new (); + new->type = type; + new->sub_type = BGP_ROUTE_REDISTRIBUTE; + new->peer = bgp->peer_self; + SET_FLAG (new->flags, BGP_INFO_VALID); + new->attr = new_attr; + new->uptime = time (NULL); + + bgp_aggregate_increment (bgp, p, new, afi, SAFI_UNICAST); + bgp_info_add (bn, new); + bgp_process (bgp, bn, afi, SAFI_UNICAST); + } + } + + /* Unintern original. */ + aspath_unintern (attr.aspath); +} + +void +bgp_redistribute_delete (struct prefix *p, u_char type) +{ + struct bgp *bgp; + struct listnode *nn; + afi_t afi; + struct bgp_node *rn; + struct bgp_info *ri; + + LIST_LOOP (bm->bgp, bgp, nn) + { + afi = family2afi (p->family); + + if (bgp->redist[afi][type]) + { + rn = bgp_afi_node_get (bgp, afi, SAFI_UNICAST, p, NULL); + + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self + && ri->type == type) + break; + + if (ri) + { + bgp_aggregate_decrement (bgp, p, ri, afi, SAFI_UNICAST); + UNSET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_process (bgp, rn, afi, SAFI_UNICAST); + bgp_info_delete (rn, ri); + bgp_info_free (ri); + bgp_unlock_node (rn); + } + bgp_unlock_node (rn); + } + } +} + +/* Withdraw specified route type's route. */ +void +bgp_redistribute_withdraw (struct bgp *bgp, afi_t afi, int type) +{ + struct bgp_node *rn; + struct bgp_info *ri; + struct bgp_table *table; + + table = bgp->rib[afi][SAFI_UNICAST]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + { + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self + && ri->type == type) + break; + + if (ri) + { + bgp_aggregate_decrement (bgp, &rn->p, ri, afi, SAFI_UNICAST); + UNSET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_process (bgp, rn, afi, SAFI_UNICAST); + bgp_info_delete (rn, ri); + bgp_info_free (ri); + bgp_unlock_node (rn); + } + } +} + +/* Static function to display route. */ +static int +route_vty_out_route (struct prefix *p, struct vty *vty) +{ + int len; + u_int32_t destination; + char buf[BUFSIZ]; + + if (p->family == AF_INET) + { + len = vty_out (vty, "%s", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ)); + destination = ntohl (p->u.prefix4.s_addr); + + if ((IN_CLASSC (destination) && p->prefixlen == 24) + || (IN_CLASSB (destination) && p->prefixlen == 16) + || (IN_CLASSA (destination) && p->prefixlen == 8) + || p->u.prefix4.s_addr == 0) + { + /* When mask is natural, mask is not displayed. */ + } + else + len += vty_out (vty, "/%d", p->prefixlen); + } + else + len = vty_out (vty, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + len = 17 - len; + if (len < 1) + vty_out (vty, "%s%*s", VTY_NEWLINE, 20, " "); + else + vty_out (vty, "%*s", len, " "); + + /* return 1 if it added extra newline */ + if (len < 1) + return 1; + else + return 0; +} + +/* Calculate line number of output data. */ +int +vty_calc_line (struct vty *vty, unsigned long length) +{ + return vty->width ? (((vty->obuf->length - length) / vty->width) + 1) : 1; +} + +enum bgp_display_type +{ + normal_list, +}; + +/* called from terminal list command */ +int +route_vty_out (struct vty *vty, struct prefix *p, + struct bgp_info *binfo, int display, safi_t safi) +{ + struct attr *attr; + unsigned long length = 0; + int extra_line = 0; + + length = vty->obuf->length; + + /* Route status display. */ + if (CHECK_FLAG (binfo->flags, BGP_INFO_STALE)) + vty_out (vty, "S"); + else if (binfo->suppress) + vty_out (vty, "s"); + else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + vty_out (vty, "*"); + else + vty_out (vty, " "); + + /* Selected */ + if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + vty_out (vty, "h"); + else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) + vty_out (vty, "d"); + else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) + vty_out (vty, ">"); + else + vty_out (vty, " "); + + /* Internal route. */ + if ((binfo->peer->as) && (binfo->peer->as == binfo->peer->local_as)) + vty_out (vty, "i"); + else + vty_out (vty, " "); + + /* print prefix and mask */ + if (! display) + extra_line += route_vty_out_route (p, vty); + else + vty_out (vty, "%*s", 17, " "); + + /* Print attribute */ + attr = binfo->attr; + if (attr) + { + if (p->family == AF_INET) + { + if (safi == SAFI_MPLS_VPN) + vty_out (vty, "%-16s", inet_ntoa (attr->mp_nexthop_global_in)); + else + vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); + } +#ifdef HAVE_IPV6 + else if (p->family == AF_INET6) + { + int len; + char buf[BUFSIZ]; + + len = vty_out (vty, "%s", + inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ)); + len = 16 - len; + if (len < 1) + { + vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " "); + extra_line++; /* Adjust More mode for newline above */ + } + else + vty_out (vty, "%*s", len, " "); + } +#endif /* HAVE_IPV6 */ + + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) + vty_out (vty, "%10u", attr->med); + else + vty_out (vty, " "); + + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) + vty_out (vty, "%7u", attr->local_pref); + else + vty_out (vty, " "); + + vty_out (vty, "%7d ",attr->weight); + + /* Print aspath */ + if (attr->aspath) + aspath_print_vty (vty, attr->aspath); + + /* Print origin */ + if (strlen (attr->aspath->str) == 0) + vty_out (vty, "%s", bgp_origin_str[attr->origin]); + else + vty_out (vty, " %s", bgp_origin_str[attr->origin]); + } + vty_out (vty, "%s", VTY_NEWLINE); + + return vty_calc_line (vty, length) + extra_line; +} + +/* called from terminal list command */ +void +route_vty_out_tmp (struct vty *vty, struct prefix *p, + struct attr *attr, safi_t safi) +{ + /* Route status display. */ + vty_out (vty, "*"); + vty_out (vty, ">"); + vty_out (vty, " "); + + /* print prefix and mask */ + route_vty_out_route (p, vty); + + /* Print attribute */ + if (attr) + { + if (p->family == AF_INET) + { + if (safi == SAFI_MPLS_VPN) + vty_out (vty, "%-16s", inet_ntoa (attr->mp_nexthop_global_in)); + else + vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); + } +#ifdef HAVE_IPV6 + else if (p->family == AF_INET6) + { + int len; + char buf[BUFSIZ]; + + len = vty_out (vty, "%s", + inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ)); + len = 16 - len; + if (len < 1) + vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " "); + else + vty_out (vty, "%*s", len, " "); + } +#endif /* HAVE_IPV6 */ + + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) + vty_out (vty, "%10u", attr->med); + else + vty_out (vty, " "); + + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) + vty_out (vty, "%7u", attr->local_pref); + else + vty_out (vty, " "); + + vty_out (vty, "%7d ",attr->weight); + + /* Print aspath */ + if (attr->aspath) + aspath_print_vty (vty, attr->aspath); + + /* Print origin */ + if (strlen (attr->aspath->str) == 0) + vty_out (vty, "%s", bgp_origin_str[attr->origin]); + else + vty_out (vty, " %s", bgp_origin_str[attr->origin]); + } + + vty_out (vty, "%s", VTY_NEWLINE); +} + +int +route_vty_out_tag (struct vty *vty, struct prefix *p, + struct bgp_info *binfo, int display, safi_t safi) +{ + struct attr *attr; + unsigned long length = 0; + u_int32_t label = 0; + int extra_line = 0; + + length = vty->obuf->length; + + /* Route status display. */ + if (binfo->suppress) + vty_out (vty, "s"); + else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + vty_out (vty, "*"); + else + vty_out (vty, " "); + + /* Selected */ + if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + vty_out (vty, "h"); + else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) + vty_out (vty, "d"); + else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) + vty_out (vty, ">"); + else + vty_out (vty, " "); + + /* Internal route. */ + if ((binfo->peer->as) && (binfo->peer->as == binfo->peer->local_as)) + vty_out (vty, "i"); + else + vty_out (vty, " "); + + /* print prefix and mask */ + if (! display) + extra_line += route_vty_out_route (p, vty); + else + vty_out (vty, "%*s", 17, " "); + + /* Print attribute */ + attr = binfo->attr; + if (attr) + { + if (p->family == AF_INET) + { + if (safi == SAFI_MPLS_VPN) + vty_out (vty, "%-16s", inet_ntoa (attr->mp_nexthop_global_in)); + else + vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); + } +#ifdef HAVE_IPV6 + else if (p->family == AF_INET6) + { + char buf[BUFSIZ]; + char buf1[BUFSIZ]; + if (attr->mp_nexthop_len == 16) + vty_out (vty, "%s", + inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ)); + else if (attr->mp_nexthop_len == 32) + vty_out (vty, "%s(%s)", + inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ), + inet_ntop (AF_INET6, &attr->mp_nexthop_local, buf1, BUFSIZ)); + + } +#endif /* HAVE_IPV6 */ + } + + label = decode_label (binfo->tag); + + vty_out (vty, "notag/%d", label); + + vty_out (vty, "%s", VTY_NEWLINE); + + return vty_calc_line (vty, length) + extra_line; +} + +/* dampening route */ +int +damp_route_vty_out (struct vty *vty, struct prefix *p, + struct bgp_info *binfo, int display, safi_t safi) +{ + struct attr *attr; + unsigned long length = 0; + int len; + int extra_line = 0; + + length = vty->obuf->length; + + /* Route status display. */ + if (binfo->suppress) + vty_out (vty, "s"); + else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + vty_out (vty, "*"); + else + vty_out (vty, " "); + + /* Selected */ + if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + vty_out (vty, "h"); + else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) + vty_out (vty, "d"); + else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) + vty_out (vty, ">"); + else + vty_out (vty, " "); + + vty_out (vty, " "); + + /* print prefix and mask */ + if (! display) + extra_line += route_vty_out_route (p, vty); + else + vty_out (vty, "%*s", 17, " "); + + len = vty_out (vty, "%s", binfo->peer->host); + len = 17 - len; + if (len < 1) + { + vty_out (vty, "%s%*s", VTY_NEWLINE, 34, " "); + extra_line++; + } + else + vty_out (vty, "%*s", len, " "); + + vty_out (vty, "%s ", bgp_damp_reuse_time_vty (vty, binfo)); + + /* Print attribute */ + attr = binfo->attr; + if (attr) + { + /* Print aspath */ + if (attr->aspath) + aspath_print_vty (vty, attr->aspath); + + /* Print origin */ + if (strlen (attr->aspath->str) == 0) + vty_out (vty, "%s", bgp_origin_str[attr->origin]); + else + vty_out (vty, " %s", bgp_origin_str[attr->origin]); + } + vty_out (vty, "%s", VTY_NEWLINE); + + return vty_calc_line (vty, length) + extra_line; +} + +#define BGP_UPTIME_LEN 25 + +/* flap route */ +int +flap_route_vty_out (struct vty *vty, struct prefix *p, + struct bgp_info *binfo, int display, safi_t safi) +{ + struct attr *attr; + struct bgp_damp_info *bdi; + unsigned long length = 0; + char timebuf[BGP_UPTIME_LEN]; + int len; + int extra_line = 0; + + length = vty->obuf->length; + bdi = binfo->damp_info; + + /* Route status display. */ + if (binfo->suppress) + vty_out (vty, "s"); + else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + vty_out (vty, "*"); + else + vty_out (vty, " "); + + /* Selected */ + if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + vty_out (vty, "h"); + else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) + vty_out (vty, "d"); + else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) + vty_out (vty, ">"); + else + vty_out (vty, " "); + + vty_out (vty, " "); + + /* print prefix and mask */ + if (! display) + extra_line += route_vty_out_route (p, vty); + else + vty_out (vty, "%*s", 17, " "); + + len = vty_out (vty, "%s", binfo->peer->host); + len = 16 - len; + if (len < 1) + { + vty_out (vty, "%s%*s", VTY_NEWLINE, 33, " "); + extra_line++; + } + else + vty_out (vty, "%*s", len, " "); + + len = vty_out (vty, "%d", bdi->flap); + len = 5 - len; + if (len < 1) + vty_out (vty, " "); + else + vty_out (vty, "%*s ", len, " "); + + vty_out (vty, "%s ", peer_uptime (bdi->start_time, + timebuf, BGP_UPTIME_LEN)); + + if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED) + && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + vty_out (vty, "%s ", bgp_damp_reuse_time_vty (vty, binfo)); + else + vty_out (vty, "%*s ", 8, " "); + + /* Print attribute */ + attr = binfo->attr; + if (attr) + { + /* Print aspath */ + if (attr->aspath) + aspath_print_vty (vty, attr->aspath); + + /* Print origin */ + if (strlen (attr->aspath->str) == 0) + vty_out (vty, "%s", bgp_origin_str[attr->origin]); + else + vty_out (vty, " %s", bgp_origin_str[attr->origin]); + } + vty_out (vty, "%s", VTY_NEWLINE); + + return vty_calc_line (vty, length) + extra_line; +} + +void +route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, + struct bgp_info *binfo, afi_t afi, safi_t safi) +{ + char buf[INET6_ADDRSTRLEN]; + char buf1[BUFSIZ]; + struct attr *attr; + int sockunion_vty_out (struct vty *, union sockunion *); + + attr = binfo->attr; + + if (attr) + { + /* Line1 display AS-path, Aggregator */ + if (attr->aspath) + { + vty_out (vty, " "); + if (attr->aspath->length == 0) + vty_out (vty, "Local"); + else + aspath_print_vty (vty, attr->aspath); + } + + if (CHECK_FLAG (binfo->flags, BGP_INFO_STALE)) + vty_out (vty, ", (stale)"); + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))) + vty_out (vty, ", (aggregated by %d %s)", attr->aggregator_as, + inet_ntoa (attr->aggregator_addr)); + if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) + vty_out (vty, ", (Received from a RR-client)"); + if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + vty_out (vty, ", (Received from a RS-client)"); + if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + vty_out (vty, ", (history entry)"); + else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) + vty_out (vty, ", (suppressed due to dampening)"); + vty_out (vty, "%s", VTY_NEWLINE); + + /* Line2 display Next-hop, Neighbor, Router-id */ + if (p->family == AF_INET) + { + vty_out (vty, " %s", safi == SAFI_MPLS_VPN ? + inet_ntoa (attr->mp_nexthop_global_in) : + inet_ntoa (attr->nexthop)); + } +#ifdef HAVE_IPV6 + else + { + vty_out (vty, " %s", + inet_ntop (AF_INET6, &attr->mp_nexthop_global, + buf, INET6_ADDRSTRLEN)); + } +#endif /* HAVE_IPV6 */ + + if (binfo->peer == bgp->peer_self) + { + vty_out (vty, " from %s ", + p->family == AF_INET ? "0.0.0.0" : "::"); + vty_out (vty, "(%s)", inet_ntoa(bgp->router_id)); + } + else + { + if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID)) + vty_out (vty, " (inaccessible)"); + else if (binfo->igpmetric) + vty_out (vty, " (metric %d)", binfo->igpmetric); + vty_out (vty, " from %s", sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN)); + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) + vty_out (vty, " (%s)", inet_ntoa (attr->originator_id)); + else + vty_out (vty, " (%s)", inet_ntop (AF_INET, &binfo->peer->remote_id, buf1, BUFSIZ)); + } + vty_out (vty, "%s", VTY_NEWLINE); + +#ifdef HAVE_IPV6 + /* display nexthop local */ + if (attr->mp_nexthop_len == 32) + { + vty_out (vty, " (%s)%s", + inet_ntop (AF_INET6, &attr->mp_nexthop_local, + buf, INET6_ADDRSTRLEN), + VTY_NEWLINE); + } +#endif /* HAVE_IPV6 */ + + /* Line 3 display Origin, Med, Locpref, Weight, valid, Int/Ext/Local, Atomic, best */ + vty_out (vty, " Origin %s", bgp_origin_long_str[attr->origin]); + + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) + vty_out (vty, ", metric %u", attr->med); + + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) + vty_out (vty, ", localpref %u", attr->local_pref); + else + vty_out (vty, ", localpref %u", bgp->default_local_pref); + + if (attr->weight != 0) + vty_out (vty, ", weight %d", attr->weight); + + if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) + vty_out (vty, ", valid"); + + if (binfo->peer != bgp->peer_self) + { + if (binfo->peer->as == binfo->peer->local_as) + vty_out (vty, ", internal"); + else + vty_out (vty, ", %s", + (bgp_confederation_peers_check(bgp, binfo->peer->as) ? "confed-external" : "external")); + } + else if (binfo->sub_type == BGP_ROUTE_AGGREGATE) + vty_out (vty, ", aggregated, local"); + else if (binfo->type != ZEBRA_ROUTE_BGP) + vty_out (vty, ", sourced"); + else + vty_out (vty, ", sourced, local"); + + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) + vty_out (vty, ", atomic-aggregate"); + + if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) + vty_out (vty, ", best"); + + vty_out (vty, "%s", VTY_NEWLINE); + + /* Line 4 display Community */ + if (attr->community) + vty_out (vty, " Community: %s%s", attr->community->str, + VTY_NEWLINE); + + /* Line 5 display Extended-community */ + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) + vty_out (vty, " Extended Community: %s%s", attr->ecommunity->str, + VTY_NEWLINE); + + /* Line 6 display Originator, Cluster-id */ + if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) || + (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) + { + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) + vty_out (vty, " Originator: %s", inet_ntoa (attr->originator_id)); + + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) + { + int i; + vty_out (vty, ", Cluster list: "); + for (i = 0; i < attr->cluster->length / 4; i++) + vty_out (vty, "%s ", inet_ntoa (attr->cluster->list[i])); + } + vty_out (vty, "%s", VTY_NEWLINE); + } + + if (binfo->damp_info) + bgp_damp_info_vty (vty, binfo); + + /* Line 7 display Uptime */ + vty_out (vty, " Last update: %s", ctime (&binfo->uptime)); + } + vty_out (vty, "%s", VTY_NEWLINE); +} + +#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,%s r RIB-failure, S Stale%s" +#define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s" +#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s" +#define BGP_SHOW_DAMP_HEADER " Network From Reuse Path%s" +#define BGP_SHOW_FLAP_HEADER " Network From Flaps Duration Reuse Path%s" + +enum bgp_show_type +{ + bgp_show_type_normal, + bgp_show_type_regexp, + bgp_show_type_prefix_list, + bgp_show_type_filter_list, + bgp_show_type_route_map, + bgp_show_type_neighbor, + bgp_show_type_cidr_only, + bgp_show_type_prefix_longer, + bgp_show_type_community_all, + bgp_show_type_community, + bgp_show_type_community_exact, + bgp_show_type_community_list, + bgp_show_type_community_list_exact, + bgp_show_type_flap_statistics, + bgp_show_type_flap_address, + bgp_show_type_flap_prefix, + bgp_show_type_flap_cidr_only, + bgp_show_type_flap_regexp, + bgp_show_type_flap_filter_list, + bgp_show_type_flap_prefix_list, + bgp_show_type_flap_prefix_longer, + bgp_show_type_flap_route_map, + bgp_show_type_flap_neighbor, + bgp_show_type_dampend_paths, + bgp_show_type_damp_neighbor +}; + +int +bgp_show_callback (struct vty *vty, int unlock) +{ + struct bgp_node *rn; + struct bgp_info *ri; + int count; + int limit; + int display; + + rn = vty->output_rn; + count = 0; + limit = ((vty->lines == 0) ? 10 : + (vty->lines > 0 ? vty->lines : vty->height - 2)); + if (vty->status == VTY_MORELINE) + limit = 1; + else + limit = limit > 0 ? limit : 2; + + /* Quit of display. */ + if (unlock && rn) + { + bgp_unlock_node (rn); + if (vty->output_clean) + (*vty->output_clean) (vty); + vty->output_rn = NULL; + vty->output_func = NULL; + vty->output_clean = NULL; + vty->output_arg = NULL; + return 0; + } + + for (; rn; rn = bgp_route_next (rn)) + if (rn->info != NULL) + { + display = 0; + + for (ri = rn->info; ri; ri = ri->next) + { + if (vty->output_type == bgp_show_type_flap_statistics + || vty->output_type == bgp_show_type_flap_address + || vty->output_type == bgp_show_type_flap_prefix + || vty->output_type == bgp_show_type_flap_cidr_only + || vty->output_type == bgp_show_type_flap_regexp + || vty->output_type == bgp_show_type_flap_filter_list + || vty->output_type == bgp_show_type_flap_prefix_list + || vty->output_type == bgp_show_type_flap_prefix_longer + || vty->output_type == bgp_show_type_flap_route_map + || vty->output_type == bgp_show_type_flap_neighbor + || vty->output_type == bgp_show_type_dampend_paths + || vty->output_type == bgp_show_type_damp_neighbor) + { + if (! ri->damp_info) + continue; + } + if (vty->output_type == bgp_show_type_regexp + || vty->output_type == bgp_show_type_flap_regexp) + { + regex_t *regex = vty->output_arg; + + if (bgp_regexec (regex, ri->attr->aspath) == REG_NOMATCH) + continue; + } + if (vty->output_type == bgp_show_type_prefix_list + || vty->output_type == bgp_show_type_flap_prefix_list) + { + struct prefix_list *plist = vty->output_arg; + + if (prefix_list_apply (plist, &rn->p) != PREFIX_PERMIT) + continue; + } + if (vty->output_type == bgp_show_type_filter_list + || vty->output_type == bgp_show_type_flap_filter_list) + { + struct as_list *as_list = vty->output_arg; + + if (as_list_apply (as_list, ri->attr->aspath) != AS_FILTER_PERMIT) + continue; + } + if (vty->output_type == bgp_show_type_route_map + || vty->output_type == bgp_show_type_flap_route_map) + { + struct route_map *rmap = vty->output_arg; + struct bgp_info binfo; + struct attr dummy_attr; + int ret; + + dummy_attr = *ri->attr; + binfo.peer = ri->peer; + binfo.attr = &dummy_attr; + + ret = route_map_apply (rmap, &rn->p, RMAP_BGP, &binfo); + + if (ret == RMAP_DENYMATCH) + continue; + } + if (vty->output_type == bgp_show_type_neighbor + || vty->output_type == bgp_show_type_flap_neighbor + || vty->output_type == bgp_show_type_damp_neighbor) + { + union sockunion *su = vty->output_arg; + + if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) + continue; + } + if (vty->output_type == bgp_show_type_cidr_only + || vty->output_type == bgp_show_type_flap_cidr_only) + { + u_int32_t destination; + + destination = ntohl (rn->p.u.prefix4.s_addr); + if (IN_CLASSC (destination) && rn->p.prefixlen == 24) + continue; + if (IN_CLASSB (destination) && rn->p.prefixlen == 16) + continue; + if (IN_CLASSA (destination) && rn->p.prefixlen == 8) + continue; + } + if (vty->output_type == bgp_show_type_prefix_longer + || vty->output_type == bgp_show_type_flap_prefix_longer) + { + struct prefix *p = vty->output_arg; + + if (! prefix_match (p, &rn->p)) + continue; + } + if (vty->output_type == bgp_show_type_community_all) + { + if (! ri->attr->community) + continue; + } + if (vty->output_type == bgp_show_type_community) + { + struct community *com = vty->output_arg; + + if (! ri->attr->community || + ! community_match (ri->attr->community, com)) + continue; + } + if (vty->output_type == bgp_show_type_community_exact) + { + struct community *com = vty->output_arg; + + if (! ri->attr->community || + ! community_cmp (ri->attr->community, com)) + continue; + } + if (vty->output_type == bgp_show_type_community_list) + { + struct community_list *list = vty->output_arg; + + if (! community_list_match (ri->attr->community, list)) + continue; + } + if (vty->output_type == bgp_show_type_community_list_exact) + { + struct community_list *list = vty->output_arg; + + if (! community_list_exact_match (ri->attr->community, list)) + continue; + } + if (vty->output_type == bgp_show_type_flap_address + || vty->output_type == bgp_show_type_flap_prefix) + { + struct prefix *p = vty->output_arg; + + if (! prefix_match (&rn->p, p)) + continue; + + if (vty->output_type == bgp_show_type_flap_prefix) + if (p->prefixlen != rn->p.prefixlen) + continue; + } + if (vty->output_type == bgp_show_type_dampend_paths + || vty->output_type == bgp_show_type_damp_neighbor) + { + if (! CHECK_FLAG (ri->flags, BGP_INFO_DAMPED) + || CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) + continue; + } + + if (vty->output_type == bgp_show_type_dampend_paths + || vty->output_type == bgp_show_type_damp_neighbor) + count += damp_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); + else if (vty->output_type == bgp_show_type_flap_statistics + || vty->output_type == bgp_show_type_flap_address + || vty->output_type == bgp_show_type_flap_prefix + || vty->output_type == bgp_show_type_flap_cidr_only + || vty->output_type == bgp_show_type_flap_regexp + || vty->output_type == bgp_show_type_flap_filter_list + || vty->output_type == bgp_show_type_flap_prefix_list + || vty->output_type == bgp_show_type_flap_prefix_longer + || vty->output_type == bgp_show_type_flap_route_map + || vty->output_type == bgp_show_type_flap_neighbor) + count += flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); + else + count += route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); + display++; + } + + if (display) + vty->output_count++; + + /* Remember current pointer then suspend output. */ + if (count >= limit) + { + vty->status = VTY_CONTINUE; + vty->output_rn = bgp_route_next (rn);; + vty->output_func = bgp_show_callback; + return 0; + } + } + + /* Total line display. */ + if (vty->output_count) + vty_out (vty, "%sTotal number of prefixes %ld%s", + VTY_NEWLINE, vty->output_count, VTY_NEWLINE); + + if (vty->output_clean) + (*vty->output_clean) (vty); + + vty->status = VTY_CONTINUE; + vty->output_rn = NULL; + vty->output_func = NULL; + vty->output_clean = NULL; + vty->output_arg = NULL; + + return 0; +} + +int +bgp_show (struct vty *vty, char *view_name, afi_t afi, safi_t safi, + enum bgp_show_type type) +{ + struct bgp *bgp; + struct bgp_info *ri; + struct bgp_node *rn; + struct bgp_table *table; + int header = 1; + int count; + int limit; + int display; + + limit = ((vty->lines == 0) + ? 10 : (vty->lines > 0 + ? vty->lines : vty->height - 2)); + limit = limit > 0 ? limit : 2; + + /* BGP structure lookup. */ + if (view_name) + { + bgp = bgp_lookup_by_name (view_name); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + count = 0; + + /* This is first entry point, so reset total line. */ + vty->output_count = 0; + vty->output_type = type; + + table = bgp->rib[afi][safi]; + + /* Start processing of routes. */ + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + if (rn->info != NULL) + { + display = 0; + + for (ri = rn->info; ri; ri = ri->next) + { + if (vty->output_type == bgp_show_type_flap_statistics + || type == bgp_show_type_flap_address + || type == bgp_show_type_flap_prefix + || type == bgp_show_type_flap_cidr_only + || type == bgp_show_type_flap_regexp + || type == bgp_show_type_flap_filter_list + || type == bgp_show_type_flap_prefix_list + || type == bgp_show_type_flap_prefix_longer + || type == bgp_show_type_flap_route_map + || type == bgp_show_type_flap_neighbor + || type == bgp_show_type_dampend_paths + || type == bgp_show_type_damp_neighbor) + { + if (! ri->damp_info) + continue; + } + if (type == bgp_show_type_regexp + || type == bgp_show_type_flap_regexp) + { + regex_t *regex = vty->output_arg; + + if (bgp_regexec (regex, ri->attr->aspath) == REG_NOMATCH) + continue; + } + if (type == bgp_show_type_prefix_list + || type == bgp_show_type_flap_prefix_list) + { + struct prefix_list *plist = vty->output_arg; + + if (prefix_list_apply (plist, &rn->p) != PREFIX_PERMIT) + continue; + } + if (type == bgp_show_type_filter_list + || type == bgp_show_type_flap_filter_list) + { + struct as_list *as_list = vty->output_arg; + + if (as_list_apply (as_list, ri->attr->aspath) != AS_FILTER_PERMIT) + continue; + } + if (type == bgp_show_type_route_map + || type == bgp_show_type_flap_route_map) + { + struct route_map *rmap = vty->output_arg; + struct bgp_info binfo; + struct attr dummy_attr; + int ret; + + dummy_attr = *ri->attr; + binfo.peer = ri->peer; + binfo.attr = &dummy_attr; + + ret = route_map_apply (rmap, &rn->p, RMAP_BGP, &binfo); + + if (ret == RMAP_DENYMATCH) + continue; + } + if (type == bgp_show_type_neighbor + || type == bgp_show_type_flap_neighbor + || type == bgp_show_type_damp_neighbor) + { + union sockunion *su = vty->output_arg; + + if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) + continue; + } + if (type == bgp_show_type_cidr_only + || type == bgp_show_type_flap_cidr_only) + { + u_int32_t destination; + + destination = ntohl (rn->p.u.prefix4.s_addr); + if (IN_CLASSC (destination) && rn->p.prefixlen == 24) + continue; + if (IN_CLASSB (destination) && rn->p.prefixlen == 16) + continue; + if (IN_CLASSA (destination) && rn->p.prefixlen == 8) + continue; + } + if (type == bgp_show_type_prefix_longer + || type == bgp_show_type_flap_prefix_longer) + { + struct prefix *p = vty->output_arg; + + if (! prefix_match (p, &rn->p)) + continue; + } + if (type == bgp_show_type_community_all) + { + if (! ri->attr->community) + continue; + } + if (type == bgp_show_type_community) + { + struct community *com = vty->output_arg; + + if (! ri->attr->community || + ! community_match (ri->attr->community, com)) + continue; + } + if (type == bgp_show_type_community_exact) + { + struct community *com = vty->output_arg; + + if (! ri->attr->community || + ! community_cmp (ri->attr->community, com)) + continue; + } + if (type == bgp_show_type_community_list) + { + struct community_list *list = vty->output_arg; + + if (! community_list_match (ri->attr->community, list)) + continue; + } + if (type == bgp_show_type_community_list_exact) + { + struct community_list *list = vty->output_arg; + + if (! community_list_exact_match (ri->attr->community, list)) + continue; + } + if (type == bgp_show_type_flap_address + || type == bgp_show_type_flap_prefix) + { + struct prefix *p = vty->output_arg; + + if (! prefix_match (&rn->p, p)) + continue; + + if (type == bgp_show_type_flap_prefix) + if (p->prefixlen != rn->p.prefixlen) + continue; + } + if (type == bgp_show_type_dampend_paths + || type == bgp_show_type_damp_neighbor) + { + if (! CHECK_FLAG (ri->flags, BGP_INFO_DAMPED) + || CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) + continue; + } + + if (header) + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + if (type == bgp_show_type_dampend_paths + || type == bgp_show_type_damp_neighbor) + vty_out (vty, BGP_SHOW_DAMP_HEADER, VTY_NEWLINE); + else if (type == bgp_show_type_flap_statistics + || type == bgp_show_type_flap_address + || type == bgp_show_type_flap_prefix + || type == bgp_show_type_flap_cidr_only + || type == bgp_show_type_flap_regexp + || type == bgp_show_type_flap_filter_list + || type == bgp_show_type_flap_prefix_list + || type == bgp_show_type_flap_prefix_longer + || type == bgp_show_type_flap_route_map + || type == bgp_show_type_flap_neighbor) + vty_out (vty, BGP_SHOW_FLAP_HEADER, VTY_NEWLINE); + else + vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); + count += 5; + header = 0; + } + + if (type == bgp_show_type_dampend_paths + || type == bgp_show_type_damp_neighbor) + count += damp_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); + else if (type == bgp_show_type_flap_statistics + || type == bgp_show_type_flap_address + || type == bgp_show_type_flap_prefix + || type == bgp_show_type_flap_cidr_only + || type == bgp_show_type_flap_regexp + || type == bgp_show_type_flap_filter_list + || type == bgp_show_type_flap_prefix_list + || type == bgp_show_type_flap_prefix_longer + || type == bgp_show_type_flap_route_map + || type == bgp_show_type_flap_neighbor) + count += flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); + else + count += route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); + display++; + } + if (display) + vty->output_count++; + + /* Remember current pointer then suspend output. */ + if (count >= limit && vty->type != VTY_SHELL_SERV) + { + vty->status = VTY_START; + vty->output_rn = bgp_route_next (rn); + vty->output_func = bgp_show_callback; + vty->output_type = type; + + return CMD_SUCCESS; + } + } + + /* No route is displayed */ + if (vty->output_count == 0) + { + if (type == bgp_show_type_normal) + vty_out (vty, "No BGP network exists%s", VTY_NEWLINE); + } + else + vty_out (vty, "%sTotal number of prefixes %ld%s", + VTY_NEWLINE, vty->output_count, VTY_NEWLINE); + + /* Clean up allocated resources. */ + if (vty->output_clean) + (*vty->output_clean) (vty); + + vty->status = VTY_START; + vty->output_rn = NULL; + vty->output_func = NULL; + vty->output_clean = NULL; + vty->output_arg = NULL; + + return CMD_SUCCESS; +} + +/* Header of detailed BGP route information */ +void +route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, + struct bgp_node *rn, + struct prefix_rd *prd, afi_t afi, safi_t safi) +{ + struct bgp_info *ri; + struct prefix *p; + struct peer *peer; + struct listnode *nn; + char buf1[INET6_ADDRSTRLEN]; + char buf2[INET6_ADDRSTRLEN]; + int count = 0; + int best = 0; + int suppress = 0; + int no_export = 0; + int no_advertise = 0; + int local_as = 0; + int first = 0; + + p = &rn->p; + vty_out (vty, "BGP routing table entry for %s%s%s/%d%s", + (safi == SAFI_MPLS_VPN ? + prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""), + safi == SAFI_MPLS_VPN ? ":" : "", + inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN), + p->prefixlen, VTY_NEWLINE); + + for (ri = rn->info; ri; ri = ri->next) + { + count++; + if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) + { + best = count; + if (ri->suppress) + suppress = 1; + if (ri->attr->community != NULL) + { + if (community_include (ri->attr->community, COMMUNITY_NO_ADVERTISE)) + no_advertise = 1; + if (community_include (ri->attr->community, COMMUNITY_NO_EXPORT)) + no_export = 1; + if (community_include (ri->attr->community, COMMUNITY_LOCAL_AS)) + local_as = 1; + } + } + } + + vty_out (vty, "Paths: (%d available", count); + if (best) + { + vty_out (vty, ", best #%d", best); + if (safi == SAFI_UNICAST) + vty_out (vty, ", table Default-IP-Routing-Table"); + } + else + vty_out (vty, ", no best path"); + if (no_advertise) + vty_out (vty, ", not advertised to any peer"); + else if (no_export) + vty_out (vty, ", not advertised to EBGP peer"); + else if (local_as) + vty_out (vty, ", not advertised outside local AS"); + if (suppress) + vty_out (vty, ", Advertisements suppressed by an aggregate."); + vty_out (vty, ")%s", VTY_NEWLINE); + + /* advertised peer */ + LIST_LOOP (bgp->peer, peer, nn) + { + if (bgp_adj_out_lookup (peer, p, afi, safi, rn)) + { + if (! first) + vty_out (vty, " Advertised to non peer-group peers:%s ", VTY_NEWLINE); + vty_out (vty, " %s", sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN)); + first = 1; + } + } + if (! first) + vty_out (vty, " Not advertised to any peer"); + vty_out (vty, "%s", VTY_NEWLINE); +} + +/* Display specified route of BGP table. */ +int +bgp_show_route (struct vty *vty, char *view_name, char *ip_str, + afi_t afi, safi_t safi, struct prefix_rd *prd, + int prefix_check) +{ + int ret; + int header; + int display = 0; + struct prefix match; + struct bgp_node *rn; + struct bgp_node *rm; + struct bgp_info *ri; + struct bgp *bgp; + struct bgp_table *table; + + /* BGP structure lookup. */ + if (view_name) + { + bgp = bgp_lookup_by_name (view_name); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + /* Check IP address argument. */ + ret = str2prefix (ip_str, &match); + if (! ret) + { + vty_out (vty, "address is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + + match.family = afi2family (afi); + + if (safi == SAFI_MPLS_VPN) + { + for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) + { + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + { + header = 1; + + if ((rm = bgp_node_match (table, &match)) != NULL) + { + if (prefix_check && rm->p.prefixlen != match.prefixlen) + continue; + + for (ri = rm->info; ri; ri = ri->next) + { + if (header) + { + route_vty_out_detail_header (vty, bgp, rm, (struct prefix_rd *)&rn->p, + AFI_IP, SAFI_MPLS_VPN); + + header = 0; + } + display++; + route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, SAFI_MPLS_VPN); + } + } + } + } + } + else + { + header = 1; + + if ((rn = bgp_node_match (bgp->rib[afi][safi], &match)) != NULL) + { + if (! prefix_check || rn->p.prefixlen == match.prefixlen) + { + for (ri = rn->info; ri; ri = ri->next) + { + if (header) + { + route_vty_out_detail_header (vty, bgp, rn, NULL, afi, safi); + header = 0; + } + display++; + route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi); + } + } + } + } + + if (! display) + { + vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* BGP route print out function. */ +DEFUN (show_ip_bgp, + show_ip_bgp_cmd, + "show ip bgp", + SHOW_STR + IP_STR + BGP_STR) +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal); +} + +DEFUN (show_ip_bgp_ipv4, + show_ip_bgp_ipv4_cmd, + "show ip bgp ipv4 (unicast|multicast)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, bgp_show_type_normal); + + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal); +} + +DEFUN (show_ip_bgp_route, + show_ip_bgp_route_cmd, + "show ip bgp A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_ip_bgp_ipv4_route, + show_ip_bgp_ipv4_route_cmd, + "show ip bgp ipv4 (unicast|multicast) A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Network in the BGP routing table to display\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0); + + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_ip_bgp_vpnv4_all_route, + show_ip_bgp_vpnv4_all_route_cmd, + "show ip bgp vpnv4 all A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0); +} + +DEFUN (show_ip_bgp_vpnv4_rd_route, + show_ip_bgp_vpnv4_rd_route_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Network in the BGP routing table to display\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0); +} + +DEFUN (show_ip_bgp_prefix, + show_ip_bgp_prefix_cmd, + "show ip bgp A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (show_ip_bgp_ipv4_prefix, + show_ip_bgp_ipv4_prefix_cmd, + "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1); + + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (show_ip_bgp_vpnv4_all_prefix, + show_ip_bgp_vpnv4_all_prefix_cmd, + "show ip bgp vpnv4 all A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1); +} + +DEFUN (show_ip_bgp_vpnv4_rd_prefix, + show_ip_bgp_vpnv4_rd_prefix_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 1); +} + +DEFUN (show_ip_bgp_view, + show_ip_bgp_view_cmd, + "show ip bgp view WORD", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "BGP view name\n") +{ + return bgp_show (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_normal); +} + +DEFUN (show_ip_bgp_view_route, + show_ip_bgp_view_route_cmd, + "show ip bgp view WORD A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_ip_bgp_view_prefix, + show_ip_bgp_view_prefix_cmd, + "show ip bgp view WORD A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp, + show_bgp_cmd, + "show bgp", + SHOW_STR + BGP_STR) +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal); +} + +ALIAS (show_bgp, + show_bgp_ipv6_cmd, + "show bgp ipv6", + SHOW_STR + BGP_STR + "Address family\n"); + +/* old command */ +DEFUN (show_ipv6_bgp, + show_ipv6_bgp_cmd, + "show ipv6 bgp", + SHOW_STR + IP_STR + BGP_STR) +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal); +} + +DEFUN (show_bgp_route, + show_bgp_route_cmd, + "show bgp X:X::X:X", + SHOW_STR + BGP_STR + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +ALIAS (show_bgp_route, + show_bgp_ipv6_route_cmd, + "show bgp ipv6 X:X::X:X", + SHOW_STR + BGP_STR + "Address family\n" + "Network in the BGP routing table to display\n"); + +/* old command */ +DEFUN (show_ipv6_bgp_route, + show_ipv6_bgp_route_cmd, + "show ipv6 bgp X:X::X:X", + SHOW_STR + IP_STR + BGP_STR + "Network in the BGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_bgp_prefix, + show_bgp_prefix_cmd, + "show bgp X:X::X:X/M", + SHOW_STR + BGP_STR + "IPv6 prefix /\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); +} + +ALIAS (show_bgp_prefix, + show_bgp_ipv6_prefix_cmd, + "show bgp ipv6 X:X::X:X/M", + SHOW_STR + BGP_STR + "Address family\n" + "IPv6 prefix /\n"); + +/* old command */ +DEFUN (show_ipv6_bgp_prefix, + show_ipv6_bgp_prefix_cmd, + "show ipv6 bgp X:X::X:X/M", + SHOW_STR + IP_STR + BGP_STR + "IPv6 prefix /, e.g., 3ffe::/16\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); +} + +/* old command */ +DEFUN (show_ipv6_mbgp, + show_ipv6_mbgp_cmd, + "show ipv6 mbgp", + SHOW_STR + IP_STR + MBGP_STR) +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_normal); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_route, + show_ipv6_mbgp_route_cmd, + "show ipv6 mbgp X:X::X:X", + SHOW_STR + IP_STR + MBGP_STR + "Network in the MBGP routing table to display\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 0); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_prefix, + show_ipv6_mbgp_prefix_cmd, + "show ipv6 mbgp X:X::X:X/M", + SHOW_STR + IP_STR + MBGP_STR + "IPv6 prefix /, e.g., 3ffe::/16\n") +{ + return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1); +} +#endif + +void +bgp_show_regexp_clean (struct vty *vty) +{ + bgp_regex_free (vty->output_arg); +} + +int +bgp_show_regexp (struct vty *vty, int argc, char **argv, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + int i; + struct buffer *b; + char *regstr; + int first; + regex_t *regex; + + first = 0; + b = buffer_new (1024); + for (i = 0; i < argc; i++) + { + if (first) + buffer_putc (b, ' '); + else + { + if ((strcmp (argv[i], "unicast") == 0) || (strcmp (argv[i], "multicast") == 0)) + continue; + first = 1; + } + + buffer_putstr (b, argv[i]); + } + buffer_putc (b, '\0'); + + regstr = buffer_getstr (b); + buffer_free (b); + + regex = bgp_regcomp (regstr); + if (! regex) + { + vty_out (vty, "Can't compile regexp %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + vty->output_arg = regex; + vty->output_clean = bgp_show_regexp_clean; + + return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_regexp, + show_ip_bgp_regexp_cmd, + "show ip bgp regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, + bgp_show_type_regexp); +} + +DEFUN (show_ip_bgp_flap_regexp, + show_ip_bgp_flap_regexp_cmd, + "show ip bgp flap-statistics regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_regexp); +} + +DEFUN (show_ip_bgp_ipv4_regexp, + show_ip_bgp_ipv4_regexp_cmd, + "show ip bgp ipv4 (unicast|multicast) regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_MULTICAST, + bgp_show_type_regexp); + + return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, + bgp_show_type_regexp); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_regexp, + show_bgp_regexp_cmd, + "show bgp regexp .LINE", + SHOW_STR + BGP_STR + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, + bgp_show_type_regexp); +} + +ALIAS (show_bgp_regexp, + show_bgp_ipv6_regexp_cmd, + "show bgp ipv6 regexp .LINE", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n"); + +/* old command */ +DEFUN (show_ipv6_bgp_regexp, + show_ipv6_bgp_regexp_cmd, + "show ipv6 bgp regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, + bgp_show_type_regexp); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_regexp, + show_ipv6_mbgp_regexp_cmd, + "show ipv6 mbgp regexp .LINE", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the MBGP AS paths\n") +{ + return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_MULTICAST, + bgp_show_type_regexp); +} +#endif /* HAVE_IPV6 */ + +int +bgp_show_prefix_list (struct vty *vty, char *prefix_list_str, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + struct prefix_list *plist; + + plist = prefix_list_lookup (afi, prefix_list_str); + if (plist == NULL) + { + vty_out (vty, "%% %s is not a valid prefix-list name%s", + prefix_list_str, VTY_NEWLINE); + return CMD_WARNING; + } + + vty->output_arg = plist; + + return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_prefix_list, + show_ip_bgp_prefix_list_cmd, + "show ip bgp prefix-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_prefix_list); +} + +DEFUN (show_ip_bgp_flap_prefix_list, + show_ip_bgp_flap_prefix_list_cmd, + "show ip bgp flap-statistics prefix-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_prefix_list); +} + +DEFUN (show_ip_bgp_ipv4_prefix_list, + show_ip_bgp_ipv4_prefix_list_cmd, + "show ip bgp ipv4 (unicast|multicast) prefix-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_prefix_list); + + return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_prefix_list); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_prefix_list, + show_bgp_prefix_list_cmd, + "show bgp prefix-list WORD", + SHOW_STR + BGP_STR + "Display routes conforming to the prefix-list\n" + "IPv6 prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_prefix_list); +} + +ALIAS (show_bgp_prefix_list, + show_bgp_ipv6_prefix_list_cmd, + "show bgp ipv6 prefix-list WORD", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes conforming to the prefix-list\n" + "IPv6 prefix-list name\n"); + +/* old command */ +DEFUN (show_ipv6_bgp_prefix_list, + show_ipv6_bgp_prefix_list_cmd, + "show ipv6 bgp prefix-list WORD", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the prefix-list\n" + "IPv6 prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_prefix_list); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_prefix_list, + show_ipv6_mbgp_prefix_list_cmd, + "show ipv6 mbgp prefix-list WORD", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the prefix-list\n" + "IPv6 prefix-list name\n") +{ + return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, + bgp_show_type_prefix_list); +} +#endif /* HAVE_IPV6 */ + +int +bgp_show_filter_list (struct vty *vty, char *filter, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + struct as_list *as_list; + + as_list = as_list_lookup (filter); + if (as_list == NULL) + { + vty_out (vty, "%% %s is not a valid AS-path access-list name%s", filter, VTY_NEWLINE); + return CMD_WARNING; + } + + vty->output_arg = as_list; + + return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_filter_list, + show_ip_bgp_filter_list_cmd, + "show ip bgp filter-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_filter_list); +} + +DEFUN (show_ip_bgp_flap_filter_list, + show_ip_bgp_flap_filter_list_cmd, + "show ip bgp flap-statistics filter-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_filter_list); +} + +DEFUN (show_ip_bgp_ipv4_filter_list, + show_ip_bgp_ipv4_filter_list_cmd, + "show ip bgp ipv4 (unicast|multicast) filter-list WORD", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_filter_list); + + return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_filter_list); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_filter_list, + show_bgp_filter_list_cmd, + "show bgp filter-list WORD", + SHOW_STR + BGP_STR + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_filter_list); +} + +ALIAS (show_bgp_filter_list, + show_bgp_ipv6_filter_list_cmd, + "show bgp ipv6 filter-list WORD", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n"); + +/* old command */ +DEFUN (show_ipv6_bgp_filter_list, + show_ipv6_bgp_filter_list_cmd, + "show ipv6 bgp filter-list WORD", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_filter_list); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_filter_list, + show_ipv6_mbgp_filter_list_cmd, + "show ipv6 mbgp filter-list WORD", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") +{ + return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, + bgp_show_type_filter_list); +} +#endif /* HAVE_IPV6 */ + +int +bgp_show_route_map (struct vty *vty, char *rmap_str, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + struct route_map *rmap; + + rmap = route_map_lookup_by_name (rmap_str); + if (! rmap) + { + vty_out (vty, "%% %s is not a valid route-map name%s", + rmap_str, VTY_NEWLINE); + return CMD_WARNING; + } + + vty->output_arg = rmap; + + return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_route_map, + show_ip_bgp_route_map_cmd, + "show ip bgp route-map WORD", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the route-map\n" + "A route-map to match on\n") +{ + return bgp_show_route_map (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_route_map); +} + +DEFUN (show_ip_bgp_flap_route_map, + show_ip_bgp_flap_route_map_cmd, + "show ip bgp flap-statistics route-map WORD", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") +{ + return bgp_show_route_map (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_route_map); +} + +DEFUN (show_ip_bgp_ipv4_route_map, + show_ip_bgp_ipv4_route_map_cmd, + "show ip bgp ipv4 (unicast|multicast) route-map WORD", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_route_map); + + return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_route_map); +} + +DEFUN (show_bgp_route_map, + show_bgp_route_map_cmd, + "show bgp route-map WORD", + SHOW_STR + BGP_STR + "Display routes matching the route-map\n" + "A route-map to match on\n") +{ + return bgp_show_route_map (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_route_map); +} + +ALIAS (show_bgp_route_map, + show_bgp_ipv6_route_map_cmd, + "show bgp ipv6 route-map WORD", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the route-map\n" + "A route-map to match on\n"); + +DEFUN (show_ip_bgp_cidr_only, + show_ip_bgp_cidr_only_cmd, + "show ip bgp cidr-only", + SHOW_STR + IP_STR + BGP_STR + "Display only routes with non-natural netmasks\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_cidr_only); +} + +DEFUN (show_ip_bgp_flap_cidr_only, + show_ip_bgp_flap_cidr_only_cmd, + "show ip bgp flap-statistics cidr-only", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Display only routes with non-natural netmasks\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_cidr_only); +} + +DEFUN (show_ip_bgp_ipv4_cidr_only, + show_ip_bgp_ipv4_cidr_only_cmd, + "show ip bgp ipv4 (unicast|multicast) cidr-only", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display only routes with non-natural netmasks\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_cidr_only); + + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_cidr_only); +} + +DEFUN (show_ip_bgp_community_all, + show_ip_bgp_community_all_cmd, + "show ip bgp community", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_community_all); +} + +DEFUN (show_ip_bgp_ipv4_community_all, + show_ip_bgp_ipv4_community_all_cmd, + "show ip bgp ipv4 (unicast|multicast) community", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, + bgp_show_type_community_all); + + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, + bgp_show_type_community_all); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_community_all, + show_bgp_community_all_cmd, + "show bgp community", + SHOW_STR + BGP_STR + "Display routes matching the communities\n") +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, + bgp_show_type_community_all); +} + +ALIAS (show_bgp_community_all, + show_bgp_ipv6_community_all_cmd, + "show bgp ipv6 community", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n"); + +/* old command */ +DEFUN (show_ipv6_bgp_community_all, + show_ipv6_bgp_community_all_cmd, + "show ipv6 bgp community", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n") +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, + bgp_show_type_community_all); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_community_all, + show_ipv6_mbgp_community_all_cmd, + "show ipv6 mbgp community", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n") +{ + return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, + bgp_show_type_community_all); +} +#endif /* HAVE_IPV6 */ + +int +bgp_show_community (struct vty *vty, int argc, char **argv, int exact, + u_int16_t afi, u_char safi) +{ + struct community *com; + struct buffer *b; + int i; + char *str; + int first = 0; + + b = buffer_new (1024); + for (i = 0; i < argc; i++) + { + if (first) + buffer_putc (b, ' '); + else + { + if ((strcmp (argv[i], "unicast") == 0) || (strcmp (argv[i], "multicast") == 0)) + continue; + first = 1; + } + + buffer_putstr (b, argv[i]); + } + buffer_putc (b, '\0'); + + str = buffer_getstr (b); + buffer_free (b); + + com = community_str2com (str); + free (str); + if (! com) + { + vty_out (vty, "%% Community malformed: %s", VTY_NEWLINE); + return CMD_WARNING; + } + + vty->output_arg = com; + + if (exact) + return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_exact); + + return bgp_show (vty, NULL, afi, safi, bgp_show_type_community); +} + +DEFUN (show_ip_bgp_community, + show_ip_bgp_community_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") +{ + return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_community, + show_ip_bgp_community2_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +ALIAS (show_ip_bgp_community, + show_ip_bgp_community3_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +ALIAS (show_ip_bgp_community, + show_ip_bgp_community4_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +DEFUN (show_ip_bgp_ipv4_community, + show_ip_bgp_ipv4_community_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_MULTICAST); + + return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_ipv4_community, + show_ip_bgp_ipv4_community2_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +ALIAS (show_ip_bgp_ipv4_community, + show_ip_bgp_ipv4_community3_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +ALIAS (show_ip_bgp_ipv4_community, + show_ip_bgp_ipv4_community4_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +DEFUN (show_ip_bgp_community_exact, + show_ip_bgp_community_exact_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_community_exact, + show_ip_bgp_community2_exact_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +ALIAS (show_ip_bgp_community_exact, + show_ip_bgp_community3_exact_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +ALIAS (show_ip_bgp_community_exact, + show_ip_bgp_community4_exact_cmd, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +DEFUN (show_ip_bgp_ipv4_community_exact, + show_ip_bgp_ipv4_community_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_MULTICAST); + + return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_ipv4_community_exact, + show_ip_bgp_ipv4_community2_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +ALIAS (show_ip_bgp_ipv4_community_exact, + show_ip_bgp_ipv4_community3_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +ALIAS (show_ip_bgp_ipv4_community_exact, + show_ip_bgp_ipv4_community4_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_community, + show_bgp_community_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") +{ + return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_community, + show_bgp_ipv6_community_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +ALIAS (show_bgp_community, + show_bgp_community2_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +ALIAS (show_bgp_community, + show_bgp_ipv6_community2_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +ALIAS (show_bgp_community, + show_bgp_community3_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +ALIAS (show_bgp_community, + show_bgp_ipv6_community3_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +ALIAS (show_bgp_community, + show_bgp_community4_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +ALIAS (show_bgp_community, + show_bgp_ipv6_community4_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +/* old command */ +DEFUN (show_ipv6_bgp_community, + show_ipv6_bgp_community_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") +{ + return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +ALIAS (show_ipv6_bgp_community, + show_ipv6_bgp_community2_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +/* old command */ +ALIAS (show_ipv6_bgp_community, + show_ipv6_bgp_community3_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +/* old command */ +ALIAS (show_ipv6_bgp_community, + show_ipv6_bgp_community4_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +DEFUN (show_bgp_community_exact, + show_bgp_community_exact_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_community_exact_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +ALIAS (show_bgp_community_exact, + show_bgp_community2_exact_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_community2_exact_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +ALIAS (show_bgp_community_exact, + show_bgp_community3_exact_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_community3_exact_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +ALIAS (show_bgp_community_exact, + show_bgp_community4_exact_cmd, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +ALIAS (show_bgp_community_exact, + show_bgp_ipv6_community4_exact_cmd, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +/* old command */ +DEFUN (show_ipv6_bgp_community_exact, + show_ipv6_bgp_community_exact_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +ALIAS (show_ipv6_bgp_community_exact, + show_ipv6_bgp_community2_exact_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +/* old command */ +ALIAS (show_ipv6_bgp_community_exact, + show_ipv6_bgp_community3_exact_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +/* old command */ +ALIAS (show_ipv6_bgp_community_exact, + show_ipv6_bgp_community4_exact_cmd, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +/* old command */ +DEFUN (show_ipv6_mbgp_community, + show_ipv6_mbgp_community_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") +{ + return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_MULTICAST); +} + +/* old command */ +ALIAS (show_ipv6_mbgp_community, + show_ipv6_mbgp_community2_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +/* old command */ +ALIAS (show_ipv6_mbgp_community, + show_ipv6_mbgp_community3_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +/* old command */ +ALIAS (show_ipv6_mbgp_community, + show_ipv6_mbgp_community4_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n"); + +/* old command */ +DEFUN (show_ipv6_mbgp_community_exact, + show_ipv6_mbgp_community_exact_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") +{ + return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_MULTICAST); +} + +/* old command */ +ALIAS (show_ipv6_mbgp_community_exact, + show_ipv6_mbgp_community2_exact_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +/* old command */ +ALIAS (show_ipv6_mbgp_community_exact, + show_ipv6_mbgp_community3_exact_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); + +/* old command */ +ALIAS (show_ipv6_mbgp_community_exact, + show_ipv6_mbgp_community4_exact_cmd, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities"); +#endif /* HAVE_IPV6 */ + +int +bgp_show_community_list (struct vty *vty, char *com, int exact, + u_int16_t afi, u_char safi) +{ + struct community_list *list; + + list = community_list_lookup (bgp_clist, com, COMMUNITY_LIST_MASTER); + if (list == NULL) + { + vty_out (vty, "%% %s is not a valid community-list name%s", com, + VTY_NEWLINE); + return CMD_WARNING; + } + + vty->output_arg = list; + + if (exact) + return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_list_exact); + + return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_list); +} + +DEFUN (show_ip_bgp_community_list, + show_ip_bgp_community_list_cmd, + "show ip bgp community-list (<1-500>|WORD)", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") +{ + return bgp_show_community_list (vty, argv[0], 0, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_community_list, + show_ip_bgp_ipv4_community_list_cmd, + "show ip bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_MULTICAST); + + return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_community_list_exact, + show_ip_bgp_community_list_exact_cmd, + "show ip bgp community-list (<1-500>|WORD) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") +{ + return bgp_show_community_list (vty, argv[0], 1, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_community_list_exact, + show_ip_bgp_ipv4_community_list_exact_cmd, + "show ip bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD) exact-match", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_MULTICAST); + + return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_UNICAST); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_community_list, + show_bgp_community_list_cmd, + "show bgp community-list (<1-500>|WORD)", + SHOW_STR + BGP_STR + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") +{ + return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_community_list, + show_bgp_ipv6_community_list_cmd, + "show bgp ipv6 community-list (<1-500>|WORD)", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n"); + +/* old command */ +DEFUN (show_ipv6_bgp_community_list, + show_ipv6_bgp_community_list_cmd, + "show ipv6 bgp community-list WORD", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the community-list\n" + "community-list name\n") +{ + return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_community_list, + show_ipv6_mbgp_community_list_cmd, + "show ipv6 mbgp community-list WORD", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the community-list\n" + "community-list name\n") +{ + return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_MULTICAST); +} + +DEFUN (show_bgp_community_list_exact, + show_bgp_community_list_exact_cmd, + "show bgp community-list (<1-500>|WORD) exact-match", + SHOW_STR + BGP_STR + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") +{ + return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_community_list_exact, + show_bgp_ipv6_community_list_exact_cmd, + "show bgp ipv6 community-list (<1-500>|WORD) exact-match", + SHOW_STR + BGP_STR + "Address family\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n"); + +/* old command */ +DEFUN (show_ipv6_bgp_community_list_exact, + show_ipv6_bgp_community_list_exact_cmd, + "show ipv6 bgp community-list WORD exact-match", + SHOW_STR + IPV6_STR + BGP_STR + "Display routes matching the community-list\n" + "community-list name\n" + "Exact match of the communities\n") +{ + return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_community_list_exact, + show_ipv6_mbgp_community_list_exact_cmd, + "show ipv6 mbgp community-list WORD exact-match", + SHOW_STR + IPV6_STR + MBGP_STR + "Display routes matching the community-list\n" + "community-list name\n" + "Exact match of the communities\n") +{ + return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_MULTICAST); +} +#endif /* HAVE_IPV6 */ + +void +bgp_show_prefix_longer_clean (struct vty *vty) +{ + struct prefix *p; + + p = vty->output_arg; + prefix_free (p); +} + +int +bgp_show_prefix_longer (struct vty *vty, char *prefix, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + int ret; + struct prefix *p; + + p = prefix_new(); + + ret = str2prefix (prefix, p); + if (! ret) + { + vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + vty->output_arg = p; + vty->output_clean = bgp_show_prefix_longer_clean; + + return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_prefix_longer, + show_ip_bgp_prefix_longer_cmd, + "show ip bgp A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + BGP_STR + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_prefix_longer); +} + +DEFUN (show_ip_bgp_flap_prefix_longer, + show_ip_bgp_flap_prefix_longer_cmd, + "show ip bgp flap-statistics A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_prefix_longer); +} + +DEFUN (show_ip_bgp_ipv4_prefix_longer, + show_ip_bgp_ipv4_prefix_longer_cmd, + "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_prefix_longer); + + return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_prefix_longer); +} + +DEFUN (show_ip_bgp_flap_address, + show_ip_bgp_flap_address_cmd, + "show ip bgp flap-statistics A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "Network in the BGP routing table to display\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_address); +} + +DEFUN (show_ip_bgp_flap_prefix, + show_ip_bgp_flap_prefix_cmd, + "show ip bgp flap-statistics A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_prefix); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_prefix_longer, + show_bgp_prefix_longer_cmd, + "show bgp X:X::X:X/M longer-prefixes", + SHOW_STR + BGP_STR + "IPv6 prefix /\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_prefix_longer); +} + +ALIAS (show_bgp_prefix_longer, + show_bgp_ipv6_prefix_longer_cmd, + "show bgp ipv6 X:X::X:X/M longer-prefixes", + SHOW_STR + BGP_STR + "Address family\n" + "IPv6 prefix /\n" + "Display route and more specific routes\n"); + +/* old command */ +DEFUN (show_ipv6_bgp_prefix_longer, + show_ipv6_bgp_prefix_longer_cmd, + "show ipv6 bgp X:X::X:X/M longer-prefixes", + SHOW_STR + IPV6_STR + BGP_STR + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_prefix_longer); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_prefix_longer, + show_ipv6_mbgp_prefix_longer_cmd, + "show ipv6 mbgp X:X::X:X/M longer-prefixes", + SHOW_STR + IPV6_STR + MBGP_STR + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Display route and more specific routes\n") +{ + return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_MULTICAST, + bgp_show_type_prefix_longer); +} +#endif /* HAVE_IPV6 */ + +void +show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, + int in) +{ + struct bgp_table *table; + struct bgp_adj_in *ain; + struct bgp_adj_out *adj; + unsigned long output_count; + struct bgp_node *rn; + int header1 = 1; + struct bgp *bgp; + int header2 = 1; + + bgp = bgp_get_default (); + + if (! bgp) + return; + + table = bgp->rib[afi][safi]; + + output_count = 0; + + if (! in && CHECK_FLAG (peer->af_sflags[afi][safi], + PEER_STATUS_DEFAULT_ORIGINATE)) + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + + vty_out (vty, "Originating default network 0.0.0.0%s%s", + VTY_NEWLINE, VTY_NEWLINE); + header1 = 0; + } + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + if (in) + { + for (ain = rn->adj_in; ain; ain = ain->next) + if (ain->peer == peer) + { + if (header1) + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + header1 = 0; + } + if (header2) + { + vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); + header2 = 0; + } + if (ain->attr) + { + route_vty_out_tmp (vty, &rn->p, ain->attr, safi); + output_count++; + } + } + } + else + { + for (adj = rn->adj_out; adj; adj = adj->next) + if (adj->peer == peer) + { + if (header1) + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + header1 = 0; + } + if (header2) + { + vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); + header2 = 0; + } + if (adj->attr) + { + route_vty_out_tmp (vty, &rn->p, adj->attr, safi); + output_count++; + } + } + } + + if (output_count != 0) + vty_out (vty, "%sTotal number of prefixes %ld%s", + VTY_NEWLINE, output_count, VTY_NEWLINE); +} + +int +peer_adj_routes (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, int in) +{ + int ret; + struct peer *peer; + union sockunion su; + + ret = str2sockunion (ip_str, &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", ip_str, VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[afi][safi]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (in && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) + { + vty_out (vty, "%% Inbound soft reconfiguration not enabled%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + show_adj_route (vty, peer, afi, safi, in); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_neighbor_advertised_route, + show_ip_bgp_neighbor_advertised_route_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + return peer_adj_routes (vty, argv[0], AFI_IP, SAFI_UNICAST, 0); +} + +DEFUN (show_ip_bgp_ipv4_neighbor_advertised_route, + show_ip_bgp_ipv4_neighbor_advertised_route_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_MULTICAST, 0); + + return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_UNICAST, 0); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_neighbor_advertised_route, + show_bgp_neighbor_advertised_route_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 0); +} + +ALIAS (show_bgp_neighbor_advertised_route, + show_bgp_ipv6_neighbor_advertised_route_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n"); + +/* old command */ +DEFUN (ipv6_bgp_neighbor_advertised_route, + ipv6_bgp_neighbor_advertised_route_cmd, + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + IPV6_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 0); +} + +/* old command */ +DEFUN (ipv6_mbgp_neighbor_advertised_route, + ipv6_mbgp_neighbor_advertised_route_cmd, + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", + SHOW_STR + IPV6_STR + MBGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") +{ + return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_MULTICAST, 0); +} +#endif /* HAVE_IPV6 */ + +DEFUN (show_ip_bgp_neighbor_received_routes, + show_ip_bgp_neighbor_received_routes_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") +{ + return peer_adj_routes (vty, argv[0], AFI_IP, SAFI_UNICAST, 1); +} + +DEFUN (show_ip_bgp_ipv4_neighbor_received_routes, + show_ip_bgp_ipv4_neighbor_received_routes_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_MULTICAST, 1); + + return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_UNICAST, 1); +} + +DEFUN (show_ip_bgp_neighbor_received_prefix_filter, + show_ip_bgp_neighbor_received_prefix_filter_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") +{ + char name[BUFSIZ]; + union sockunion *su; + struct peer *peer; + int count; + + su = sockunion_str2su (argv[0]); + if (su == NULL) + return CMD_WARNING; + + peer = peer_lookup (NULL, su); + if (! peer) + return CMD_WARNING; + + sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); + if (count) + { + vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP, name); + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter, + show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") +{ + char name[BUFSIZ]; + union sockunion *su; + struct peer *peer; + int count; + + su = sockunion_str2su (argv[1]); + if (su == NULL) + return CMD_WARNING; + + peer = peer_lookup (NULL, su); + if (! peer) + return CMD_WARNING; + + if (strncmp (argv[0], "m", 1) == 0) + { + sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_MULTICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); + if (count) + { + vty_out (vty, "Address family: IPv4 Multicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP, name); + } + } + else + { + sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); + if (count) + { + vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP, name); + } + } + + return CMD_SUCCESS; +} + + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_neighbor_received_routes, + show_bgp_neighbor_received_routes_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") +{ + return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 1); +} + +ALIAS (show_bgp_neighbor_received_routes, + show_bgp_ipv6_neighbor_received_routes_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n"); + +DEFUN (show_bgp_neighbor_received_prefix_filter, + show_bgp_neighbor_received_prefix_filter_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") +{ + char name[BUFSIZ]; + union sockunion *su; + struct peer *peer; + int count; + + su = sockunion_str2su (argv[0]); + if (su == NULL) + return CMD_WARNING; + + peer = peer_lookup (NULL, su); + if (! peer) + return CMD_WARNING; + + sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST); + count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); + if (count) + { + vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE); + prefix_bgp_show_prefix_list (vty, AFI_IP6, name); + } + + return CMD_SUCCESS; +} + +ALIAS (show_bgp_neighbor_received_prefix_filter, + show_bgp_ipv6_neighbor_received_prefix_filter_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n"); + +/* old command */ +DEFUN (ipv6_bgp_neighbor_received_routes, + ipv6_bgp_neighbor_received_routes_cmd, + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + IPV6_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") +{ + return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 1); +} + +/* old command */ +DEFUN (ipv6_mbgp_neighbor_received_routes, + ipv6_mbgp_neighbor_received_routes_cmd, + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) received-routes", + SHOW_STR + IPV6_STR + MBGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") +{ + return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_MULTICAST, 1); +} +#endif /* HAVE_IPV6 */ + +void +bgp_show_neighbor_route_clean (struct vty *vty) +{ + union sockunion *su; + + su = vty->output_arg; + XFREE (MTYPE_SOCKUNION, su); +} + +int +bgp_show_neighbor_route (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, enum bgp_show_type type) +{ + union sockunion *su; + struct peer *peer; + + su = sockunion_str2su (ip_str); + if (su == NULL) + { + vty_out (vty, "Malformed address: %s%s", ip_str, VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, su); + if (! peer || ! peer->afc[afi][safi]) + { + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + XFREE (MTYPE_SOCKUNION, su); + return CMD_WARNING; + } + + vty->output_arg = su; + vty->output_clean = bgp_show_neighbor_route_clean; + + return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_neighbor_routes, + show_ip_bgp_neighbor_routes_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + return bgp_show_neighbor_route (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_neighbor); +} + +DEFUN (show_ip_bgp_neighbor_flap, + show_ip_bgp_neighbor_flap_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display flap statistics of the routes learned from neighbor\n") +{ + return bgp_show_neighbor_route (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_flap_neighbor); +} + +DEFUN (show_ip_bgp_neighbor_damp, + show_ip_bgp_neighbor_damp_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the dampened routes received from neighbor\n") +{ + return bgp_show_neighbor_route (vty, argv[0], AFI_IP, SAFI_UNICAST, + bgp_show_type_damp_neighbor); +} + +DEFUN (show_ip_bgp_ipv4_neighbor_routes, + show_ip_bgp_ipv4_neighbor_routes_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_neighbor_route (vty, argv[1], AFI_IP, SAFI_MULTICAST, + bgp_show_type_neighbor); + + return bgp_show_neighbor_route (vty, argv[1], AFI_IP, SAFI_UNICAST, + bgp_show_type_neighbor); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_neighbor_routes, + show_bgp_neighbor_routes_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + return bgp_show_neighbor_route (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_neighbor); +} + +ALIAS (show_bgp_neighbor_routes, + show_bgp_ipv6_neighbor_routes_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n"); + +/* old command */ +DEFUN (ipv6_bgp_neighbor_routes, + ipv6_bgp_neighbor_routes_cmd, + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + IPV6_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + return bgp_show_neighbor_route (vty, argv[0], AFI_IP6, SAFI_UNICAST, + bgp_show_type_neighbor); +} + +/* old command */ +DEFUN (ipv6_mbgp_neighbor_routes, + ipv6_mbgp_neighbor_routes_cmd, + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes", + SHOW_STR + IPV6_STR + MBGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") +{ + return bgp_show_neighbor_route (vty, argv[0], AFI_IP6, SAFI_MULTICAST, + bgp_show_type_neighbor); +} +#endif /* HAVE_IPV6 */ + +struct bgp_table *bgp_distance_table; + +struct bgp_distance +{ + /* Distance value for the IP source prefix. */ + u_char distance; + + /* Name of the access-list to be matched. */ + char *access_list; +}; + +struct bgp_distance * +bgp_distance_new () +{ + struct bgp_distance *new; + new = XMALLOC (MTYPE_BGP_DISTANCE, sizeof (struct bgp_distance)); + memset (new, 0, sizeof (struct bgp_distance)); + return new; +} + +void +bgp_distance_free (struct bgp_distance *bdistance) +{ + XFREE (MTYPE_BGP_DISTANCE, bdistance); +} + +int +bgp_distance_set (struct vty *vty, char *distance_str, char *ip_str, + char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct bgp_node *rn; + struct bgp_distance *bdistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + /* Get BGP distance node. */ + rn = bgp_node_get (bgp_distance_table, (struct prefix *) &p); + if (rn->info) + { + bdistance = rn->info; + bgp_unlock_node (rn); + } + else + { + bdistance = bgp_distance_new (); + rn->info = bdistance; + } + + /* Set distance value. */ + bdistance->distance = distance; + + /* Reset access-list configuration. */ + if (bdistance->access_list) + { + free (bdistance->access_list); + bdistance->access_list = NULL; + } + if (access_list_str) + bdistance->access_list = strdup (access_list_str); + + return CMD_SUCCESS; +} + +int +bgp_distance_unset (struct vty *vty, char *distance_str, char *ip_str, + char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct bgp_node *rn; + struct bgp_distance *bdistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + rn = bgp_node_lookup (bgp_distance_table, (struct prefix *)&p); + if (! rn) + { + vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bdistance = rn->info; + + if (bdistance->access_list) + free (bdistance->access_list); + bgp_distance_free (bdistance); + + rn->info = NULL; + bgp_unlock_node (rn); + bgp_unlock_node (rn); + + return CMD_SUCCESS; +} + +void +bgp_distance_reset () +{ + struct bgp_node *rn; + struct bgp_distance *bdistance; + + for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn)) + if ((bdistance = rn->info) != NULL) + { + if (bdistance->access_list) + free (bdistance->access_list); + bgp_distance_free (bdistance); + rn->info = NULL; + bgp_unlock_node (rn); + } +} + +/* Apply BGP information to distance method. */ +u_char +bgp_distance_apply (struct prefix *p, struct bgp_info *rinfo, struct bgp *bgp) +{ + struct bgp_node *rn; + struct prefix_ipv4 q; + struct peer *peer; + struct bgp_distance *bdistance; + struct access_list *alist; + struct bgp_static *bgp_static; + + if (! bgp) + return 0; + + if (p->family != AF_INET) + return 0; + + peer = rinfo->peer; + + if (peer->su.sa.sa_family != AF_INET) + return 0; + + memset (&q, 0, sizeof (struct prefix_ipv4)); + q.family = AF_INET; + q.prefix = peer->su.sin.sin_addr; + q.prefixlen = IPV4_MAX_BITLEN; + + /* Check source address. */ + rn = bgp_node_match (bgp_distance_table, (struct prefix *) &q); + if (rn) + { + bdistance = rn->info; + bgp_unlock_node (rn); + + if (bdistance->access_list) + { + alist = access_list_lookup (AFI_IP, bdistance->access_list); + if (alist && access_list_apply (alist, p) == FILTER_PERMIT) + return bdistance->distance; + } + else + return bdistance->distance; + } + + /* Backdoor check. */ + rn = bgp_node_lookup (bgp->route[AFI_IP][SAFI_UNICAST], p); + if (rn) + { + bgp_static = rn->info; + bgp_unlock_node (rn); + + if (bgp_static->backdoor) + { + if (bgp->distance_local) + return bgp->distance_local; + else + return ZEBRA_IBGP_DISTANCE_DEFAULT; + } + } + + if (peer_sort (peer) == BGP_PEER_EBGP) + { + if (bgp->distance_ebgp) + return bgp->distance_ebgp; + return ZEBRA_EBGP_DISTANCE_DEFAULT; + } + else + { + if (bgp->distance_ibgp) + return bgp->distance_ibgp; + return ZEBRA_IBGP_DISTANCE_DEFAULT; + } +} + +DEFUN (bgp_distance, + bgp_distance_cmd, + "distance bgp <1-255> <1-255> <1-255>", + "Define an administrative distance\n" + "BGP distance\n" + "Distance for routes external to the AS\n" + "Distance for routes internal to the AS\n" + "Distance for local routes\n") +{ + struct bgp *bgp; + + bgp = vty->index; + + bgp->distance_ebgp = atoi (argv[0]); + bgp->distance_ibgp = atoi (argv[1]); + bgp->distance_local = atoi (argv[2]); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_distance, + no_bgp_distance_cmd, + "no distance bgp <1-255> <1-255> <1-255>", + NO_STR + "Define an administrative distance\n" + "BGP distance\n" + "Distance for routes external to the AS\n" + "Distance for routes internal to the AS\n" + "Distance for local routes\n") +{ + struct bgp *bgp; + + bgp = vty->index; + + bgp->distance_ebgp= 0; + bgp->distance_ibgp = 0; + bgp->distance_local = 0; + return CMD_SUCCESS; +} + +ALIAS (no_bgp_distance, + no_bgp_distance2_cmd, + "no distance bgp", + NO_STR + "Define an administrative distance\n" + "BGP distance\n"); + +DEFUN (bgp_distance_source, + bgp_distance_source_cmd, + "distance <1-255> A.B.C.D/M", + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n") +{ + bgp_distance_set (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_distance_source, + no_bgp_distance_source_cmd, + "no distance <1-255> A.B.C.D/M", + NO_STR + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n") +{ + bgp_distance_unset (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (bgp_distance_source_access_list, + bgp_distance_source_access_list_cmd, + "distance <1-255> A.B.C.D/M WORD", + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n" + "Access list name\n") +{ + bgp_distance_set (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_distance_source_access_list, + no_bgp_distance_source_access_list_cmd, + "no distance <1-255> A.B.C.D/M WORD", + NO_STR + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n" + "Access list name\n") +{ + bgp_distance_unset (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} + +DEFUN (bgp_damp_set, + bgp_damp_set_cmd, + "bgp dampening <1-45> <1-20000> <1-20000> <1-255>", + "BGP Specific commands\n" + "Enable route-flap dampening\n" + "Half-life time for the penalty\n" + "Value to start reusing a route\n" + "Value to start suppressing a route\n" + "Maximum duration to suppress a stable route\n") +{ + struct bgp *bgp; + int half = DEFAULT_HALF_LIFE * 60; + int reuse = DEFAULT_REUSE; + int suppress = DEFAULT_SUPPRESS; + int max = 4 * half; + + if (argc == 4) + { + half = atoi (argv[0]) * 60; + reuse = atoi (argv[1]); + suppress = atoi (argv[2]); + max = atoi (argv[3]) * 60; + } + else if (argc == 1) + { + half = atoi (argv[0]) * 60; + max = 4 * half; + } + + bgp = vty->index; + return bgp_damp_enable (bgp, bgp_node_afi (vty), bgp_node_safi (vty), + half, reuse, suppress, max); +} + +ALIAS (bgp_damp_set, + bgp_damp_set2_cmd, + "bgp dampening <1-45>", + "BGP Specific commands\n" + "Enable route-flap dampening\n" + "Half-life time for the penalty\n"); + +ALIAS (bgp_damp_set, + bgp_damp_set3_cmd, + "bgp dampening", + "BGP Specific commands\n" + "Enable route-flap dampening\n"); + +DEFUN (bgp_damp_unset, + bgp_damp_unset_cmd, + "no bgp dampening", + NO_STR + "BGP Specific commands\n" + "Enable route-flap dampening\n") +{ + struct bgp *bgp; + + bgp = vty->index; + return bgp_damp_disable (bgp, bgp_node_afi (vty), bgp_node_safi (vty)); +} + +ALIAS (bgp_damp_unset, + bgp_damp_unset2_cmd, + "no bgp dampening <1-45> <1-20000> <1-20000> <1-255>", + NO_STR + "BGP Specific commands\n" + "Enable route-flap dampening\n" + "Half-life time for the penalty\n" + "Value to start reusing a route\n" + "Value to start suppressing a route\n" + "Maximum duration to suppress a stable route\n"); + +DEFUN (show_ip_bgp_dampened_paths, + show_ip_bgp_dampened_paths_cmd, + "show ip bgp dampened-paths", + SHOW_STR + IP_STR + BGP_STR + "Display paths suppressed due to dampening\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_dampend_paths); +} + +DEFUN (show_ip_bgp_flap_statistics, + show_ip_bgp_flap_statistics_cmd, + "show ip bgp flap-statistics", + SHOW_STR + IP_STR + BGP_STR + "Display flap statistics of routes\n") +{ + return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_flap_statistics); +} + +/* Display specified route of BGP table. */ +int +bgp_clear_damp_route (struct vty *vty, char *view_name, char *ip_str, + afi_t afi, safi_t safi, struct prefix_rd *prd, + int prefix_check) +{ + int ret; + struct prefix match; + struct bgp_node *rn; + struct bgp_node *rm; + struct bgp_info *ri; + struct bgp_info *ri_temp; + struct bgp *bgp; + struct bgp_table *table; + + /* BGP structure lookup. */ + if (view_name) + { + bgp = bgp_lookup_by_name (view_name); + if (bgp == NULL) + { + vty_out (vty, "%% Can't find BGP view %s%s", view_name, VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "%% No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + /* Check IP address argument. */ + ret = str2prefix (ip_str, &match); + if (! ret) + { + vty_out (vty, "%% address is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + + match.family = afi2family (afi); + + if (safi == SAFI_MPLS_VPN) + { + for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) + { + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + if ((rm = bgp_node_match (table, &match)) != NULL) + if (! prefix_check || rm->p.prefixlen == match.prefixlen) + { + ri = rm->info; + while (ri) + { + if (ri->damp_info) + { + ri_temp = ri->next; + bgp_damp_info_free (ri->damp_info, 1); + ri = ri_temp; + } + else + ri = ri->next; + } + } + } + } + else + { + if ((rn = bgp_node_match (bgp->rib[afi][safi], &match)) != NULL) + if (! prefix_check || rn->p.prefixlen == match.prefixlen) + { + ri = rn->info; + while (ri) + { + if (ri->damp_info) + { + ri_temp = ri->next; + bgp_damp_info_free (ri->damp_info, 1); + ri = ri_temp; + } + else + ri = ri->next; + } + } + } + + return CMD_SUCCESS; +} + +DEFUN (clear_ip_bgp_dampening, + clear_ip_bgp_dampening_cmd, + "clear ip bgp dampening", + CLEAR_STR + IP_STR + BGP_STR + "Clear route flap dampening information\n") +{ + bgp_damp_info_clean (); + return CMD_SUCCESS; +} + +DEFUN (clear_ip_bgp_dampening_prefix, + clear_ip_bgp_dampening_prefix_cmd, + "clear ip bgp dampening A.B.C.D/M", + CLEAR_STR + IP_STR + BGP_STR + "Clear route flap dampening information\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return bgp_clear_damp_route (vty, NULL, argv[0], AFI_IP, + SAFI_UNICAST, NULL, 1); +} + +DEFUN (clear_ip_bgp_dampening_address, + clear_ip_bgp_dampening_address_cmd, + "clear ip bgp dampening A.B.C.D", + CLEAR_STR + IP_STR + BGP_STR + "Clear route flap dampening information\n" + "Network to clear damping information\n") +{ + return bgp_clear_damp_route (vty, NULL, argv[0], AFI_IP, + SAFI_UNICAST, NULL, 0); +} + +DEFUN (clear_ip_bgp_dampening_address_mask, + clear_ip_bgp_dampening_address_mask_cmd, + "clear ip bgp dampening A.B.C.D A.B.C.D", + CLEAR_STR + IP_STR + BGP_STR + "Clear route flap dampening information\n" + "Network to clear damping information\n" + "Network mask\n") +{ + int ret; + char prefix_str[BUFSIZ]; + + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + if (! ret) + { + vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_clear_damp_route (vty, NULL, prefix_str, AFI_IP, + SAFI_UNICAST, NULL, 0); +} + +int +bgp_config_write_network_vpnv4 (struct vty *vty, struct bgp *bgp, + afi_t afi, safi_t safi, int *write) +{ + struct bgp_node *prn; + struct bgp_node *rn; + struct bgp_table *table; + struct prefix *p; + struct prefix_rd *prd; + struct bgp_static *bgp_static; + u_int32_t label; + char buf[SU_ADDRSTRLEN]; + char rdbuf[RD_ADDRSTRLEN]; + + /* Network configuration. */ + for (prn = bgp_table_top (bgp->route[afi][safi]); prn; prn = bgp_route_next (prn)) + if ((table = prn->info) != NULL) + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + if ((bgp_static = rn->info) != NULL) + { + p = &rn->p; + prd = (struct prefix_rd *) &prn->p; + + /* "address-family" display. */ + bgp_config_write_family_header (vty, afi, safi, write); + + /* "network" configuration display. */ + prefix_rd2str (prd, rdbuf, RD_ADDRSTRLEN); + label = decode_label (bgp_static->tag); + + vty_out (vty, " network %s/%d rd %s tag %d", + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen, + rdbuf, label); + vty_out (vty, "%s", VTY_NEWLINE); + } + return 0; +} + +/* Configuration of static route announcement and aggregate + information. */ +int +bgp_config_write_network (struct vty *vty, struct bgp *bgp, + afi_t afi, safi_t safi, int *write) +{ + struct bgp_node *rn; + struct prefix *p; + struct bgp_static *bgp_static; + struct bgp_aggregate *bgp_aggregate; + char buf[SU_ADDRSTRLEN]; + + if (afi == AFI_IP && safi == SAFI_MPLS_VPN) + return bgp_config_write_network_vpnv4 (vty, bgp, afi, safi, write); + + /* Network configuration. */ + for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) + if ((bgp_static = rn->info) != NULL) + { + p = &rn->p; + + /* "address-family" display. */ + bgp_config_write_family_header (vty, afi, safi, write); + + /* "network" configuration display. */ + if (bgp_option_check (BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) + { + u_int32_t destination; + struct in_addr netmask; + + destination = ntohl (p->u.prefix4.s_addr); + masklen2ip (p->prefixlen, &netmask); + vty_out (vty, " network %s", + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN)); + + if ((IN_CLASSC (destination) && p->prefixlen == 24) + || (IN_CLASSB (destination) && p->prefixlen == 16) + || (IN_CLASSA (destination) && p->prefixlen == 8) + || p->u.prefix4.s_addr == 0) + { + /* Natural mask is not display. */ + } + else + vty_out (vty, " mask %s", inet_ntoa (netmask)); + } + else + { + vty_out (vty, " network %s/%d", + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + } + + if (bgp_static->rmap.name) + vty_out (vty, " route-map %s", bgp_static->rmap.name); + else if (bgp_static->backdoor) + vty_out (vty, " backdoor"); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Aggregate-address configuration. */ + for (rn = bgp_table_top (bgp->aggregate[afi][safi]); rn; rn = bgp_route_next (rn)) + if ((bgp_aggregate = rn->info) != NULL) + { + p = &rn->p; + + /* "address-family" display. */ + bgp_config_write_family_header (vty, afi, safi, write); + + if (bgp_option_check (BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) + { + struct in_addr netmask; + + masklen2ip (p->prefixlen, &netmask); + vty_out (vty, " aggregate-address %s %s", + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + inet_ntoa (netmask)); + } + else + { + vty_out (vty, " aggregate-address %s/%d", + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + } + + if (bgp_aggregate->as_set) + vty_out (vty, " as-set"); + + if (bgp_aggregate->summary_only) + vty_out (vty, " summary-only"); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + return 0; +} + +int +bgp_config_write_distance (struct vty *vty, struct bgp *bgp) +{ + struct bgp_node *rn; + struct bgp_distance *bdistance; + + /* Distance configuration. */ + if (bgp->distance_ebgp + && bgp->distance_ibgp + && bgp->distance_local + && (bgp->distance_ebgp != ZEBRA_EBGP_DISTANCE_DEFAULT + || bgp->distance_ibgp != ZEBRA_IBGP_DISTANCE_DEFAULT + || bgp->distance_local != ZEBRA_IBGP_DISTANCE_DEFAULT)) + vty_out (vty, " distance bgp %d %d %d%s", + bgp->distance_ebgp, bgp->distance_ibgp, bgp->distance_local, + VTY_NEWLINE); + + for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn)) + if ((bdistance = rn->info) != NULL) + { + vty_out (vty, " distance %d %s/%d %s%s", bdistance->distance, + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + bdistance->access_list ? bdistance->access_list : "", + VTY_NEWLINE); + } + + return 0; +} + +/* Allocate routing table structure and install commands. */ +void +bgp_route_init () +{ + /* Init BGP distance table. */ + bgp_distance_table = bgp_table_init (); + + /* IPv4 BGP commands. */ + install_element (BGP_NODE, &bgp_network_cmd); + install_element (BGP_NODE, &bgp_network_mask_cmd); + install_element (BGP_NODE, &bgp_network_mask_natural_cmd); + install_element (BGP_NODE, &bgp_network_route_map_cmd); + install_element (BGP_NODE, &bgp_network_mask_route_map_cmd); + install_element (BGP_NODE, &bgp_network_mask_natural_route_map_cmd); + install_element (BGP_NODE, &bgp_network_backdoor_cmd); + install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd); + install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd); + install_element (BGP_NODE, &no_bgp_network_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd); + install_element (BGP_NODE, &no_bgp_network_route_map_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_route_map_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_natural_route_map_cmd); + install_element (BGP_NODE, &no_bgp_network_backdoor_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_backdoor_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_cmd); + + install_element (BGP_NODE, &aggregate_address_cmd); + install_element (BGP_NODE, &aggregate_address_mask_cmd); + install_element (BGP_NODE, &aggregate_address_summary_only_cmd); + install_element (BGP_NODE, &aggregate_address_mask_summary_only_cmd); + install_element (BGP_NODE, &aggregate_address_as_set_cmd); + install_element (BGP_NODE, &aggregate_address_mask_as_set_cmd); + install_element (BGP_NODE, &aggregate_address_as_set_summary_cmd); + install_element (BGP_NODE, &aggregate_address_mask_as_set_summary_cmd); + install_element (BGP_NODE, &aggregate_address_summary_as_set_cmd); + install_element (BGP_NODE, &aggregate_address_mask_summary_as_set_cmd); + install_element (BGP_NODE, &no_aggregate_address_cmd); + install_element (BGP_NODE, &no_aggregate_address_summary_only_cmd); + install_element (BGP_NODE, &no_aggregate_address_as_set_cmd); + install_element (BGP_NODE, &no_aggregate_address_as_set_summary_cmd); + install_element (BGP_NODE, &no_aggregate_address_summary_as_set_cmd); + install_element (BGP_NODE, &no_aggregate_address_mask_cmd); + install_element (BGP_NODE, &no_aggregate_address_mask_summary_only_cmd); + install_element (BGP_NODE, &no_aggregate_address_mask_as_set_cmd); + install_element (BGP_NODE, &no_aggregate_address_mask_as_set_summary_cmd); + install_element (BGP_NODE, &no_aggregate_address_mask_summary_as_set_cmd); + + /* IPv4 unicast configuration. */ + install_element (BGP_IPV4_NODE, &bgp_network_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_mask_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_route_map_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_route_map_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_summary_only_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_only_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_as_set_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_as_set_summary_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_summary_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_summary_as_set_cmd); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_as_set_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_only_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_summary_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_as_set_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_only_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_summary_cmd); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_as_set_cmd); + + /* IPv4 multicast configuration. */ + install_element (BGP_IPV4M_NODE, &bgp_network_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_route_map_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_route_map_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_summary_only_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_only_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_summary_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_summary_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_summary_as_set_cmd); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_as_set_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_only_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_summary_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_as_set_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_only_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_summary_cmd); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_as_set_cmd); + + install_element (VIEW_NODE, &show_ip_bgp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd); + install_element (VIEW_NODE, &show_ip_bgp_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_regexp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_prefix_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_filter_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_filter_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_route_map_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_map_cmd); + install_element (VIEW_NODE, &show_ip_bgp_cidr_only_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_all_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_all_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community2_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community3_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community4_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community4_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); + install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd); + + install_element (ENABLE_NODE, &show_ip_bgp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_regexp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_regexp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_filter_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_filter_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_route_map_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_map_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_cidr_only_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_all_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_all_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community2_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community3_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community4_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community4_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd); + + /* BGP dampening clear commands */ + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd); + +#ifdef HAVE_IPV6 + /* New config IPv6 BGP commands. */ + install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd); + install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd); + + install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd); + install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_summary_only_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd); + + /* Old config IPv6 BGP commands. */ + install_element (BGP_NODE, &old_ipv6_bgp_network_cmd); + install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd); + + install_element (BGP_NODE, &old_ipv6_aggregate_address_cmd); + install_element (BGP_NODE, &old_ipv6_aggregate_address_summary_only_cmd); + install_element (BGP_NODE, &old_no_ipv6_aggregate_address_cmd); + install_element (BGP_NODE, &old_no_ipv6_aggregate_address_summary_only_cmd); + + install_element (VIEW_NODE, &show_bgp_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_cmd); + install_element (VIEW_NODE, &show_bgp_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd); + install_element (VIEW_NODE, &show_bgp_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_regexp_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd); + install_element (VIEW_NODE, &show_bgp_prefix_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd); + install_element (VIEW_NODE, &show_bgp_filter_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd); + install_element (VIEW_NODE, &show_bgp_route_map_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd); + install_element (VIEW_NODE, &show_bgp_community_all_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_all_cmd); + install_element (VIEW_NODE, &show_bgp_community_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd); + install_element (VIEW_NODE, &show_bgp_community2_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd); + install_element (VIEW_NODE, &show_bgp_community3_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd); + install_element (VIEW_NODE, &show_bgp_community4_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd); + install_element (VIEW_NODE, &show_bgp_community_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd); + install_element (VIEW_NODE, &show_bgp_community2_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd); + install_element (VIEW_NODE, &show_bgp_community3_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd); + install_element (VIEW_NODE, &show_bgp_community4_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd); + install_element (VIEW_NODE, &show_bgp_community_list_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd); + install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd); + install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); + + install_element (ENABLE_NODE, &show_bgp_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_cmd); + install_element (ENABLE_NODE, &show_bgp_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd); + install_element (ENABLE_NODE, &show_bgp_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_regexp_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd); + install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_list_cmd); + install_element (ENABLE_NODE, &show_bgp_filter_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_filter_list_cmd); + install_element (ENABLE_NODE, &show_bgp_route_map_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_route_map_cmd); + install_element (ENABLE_NODE, &show_bgp_community_all_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_all_cmd); + install_element (ENABLE_NODE, &show_bgp_community_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd); + install_element (ENABLE_NODE, &show_bgp_community2_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd); + install_element (ENABLE_NODE, &show_bgp_community3_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd); + install_element (ENABLE_NODE, &show_bgp_community4_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd); + install_element (ENABLE_NODE, &show_bgp_community_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_community2_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_community3_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_community4_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_community_list_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_cmd); + install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); + + /* old command */ + install_element (VIEW_NODE, &show_ipv6_bgp_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_regexp_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_prefix_list_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_filter_list_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_all_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community2_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community3_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community4_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community2_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community3_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_regexp_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_list_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_filter_list_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_all_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community2_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community3_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community4_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community2_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community3_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd); + install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd); + + /* old command */ + install_element (ENABLE_NODE, &show_ipv6_bgp_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_regexp_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_filter_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community2_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community3_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community4_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community2_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community3_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community4_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_route_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_regexp_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_filter_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_all_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd); + install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd); + + /* old command */ + install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); + install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); + install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); + + /* old command */ + install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); + + /* old command */ + install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd); + install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd); + install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd); + install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_routes_cmd); +#endif /* HAVE_IPV6 */ + + install_element (BGP_NODE, &bgp_distance_cmd); + install_element (BGP_NODE, &no_bgp_distance_cmd); + install_element (BGP_NODE, &no_bgp_distance2_cmd); + install_element (BGP_NODE, &bgp_distance_source_cmd); + install_element (BGP_NODE, &no_bgp_distance_source_cmd); + install_element (BGP_NODE, &bgp_distance_source_access_list_cmd); + install_element (BGP_NODE, &no_bgp_distance_source_access_list_cmd); + + install_element (BGP_NODE, &bgp_damp_set_cmd); + install_element (BGP_NODE, &bgp_damp_set2_cmd); + install_element (BGP_NODE, &bgp_damp_set3_cmd); + install_element (BGP_NODE, &bgp_damp_unset_cmd); + install_element (BGP_NODE, &bgp_damp_unset2_cmd); + install_element (BGP_IPV4_NODE, &bgp_damp_set_cmd); + install_element (BGP_IPV4_NODE, &bgp_damp_set2_cmd); + install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd); + install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd); + install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd); +} diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h new file mode 100644 index 0000000..0e75df3 --- /dev/null +++ b/bgpd/bgp_route.h @@ -0,0 +1,161 @@ +/* BGP routing information base + Copyright (C) 1996, 97, 98, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +struct bgp_info +{ + /* For linked list. */ + struct bgp_info *next; + struct bgp_info *prev; + + /* BGP route type. This can be static, RIP, OSPF, BGP etc. */ + u_char type; + + /* When above type is BGP. This sub type specify BGP sub type + information. */ + u_char sub_type; +#define BGP_ROUTE_NORMAL 0 +#define BGP_ROUTE_STATIC 1 +#define BGP_ROUTE_AGGREGATE 2 +#define BGP_ROUTE_REDISTRIBUTE 3 + + /* BGP information status. */ + u_int16_t flags; +#define BGP_INFO_IGP_CHANGED (1 << 0) +#define BGP_INFO_DAMPED (1 << 1) +#define BGP_INFO_HISTORY (1 << 2) +#define BGP_INFO_SELECTED (1 << 3) +#define BGP_INFO_VALID (1 << 4) +#define BGP_INFO_ATTR_CHANGED (1 << 5) +#define BGP_INFO_DMED_CHECK (1 << 6) +#define BGP_INFO_DMED_SELECTED (1 << 7) +#define BGP_INFO_STALE (1 << 8) + + /* Peer structure. */ + struct peer *peer; + + /* Attribute structure. */ + struct attr *attr; + + /* This route is suppressed with aggregation. */ + int suppress; + + /* Nexthop reachability check. */ + u_int32_t igpmetric; + + /* Uptime. */ + time_t uptime; + + /* Pointer to dampening structure. */ + struct bgp_damp_info *damp_info; + + /* MPLS label. */ + u_char tag[3]; +}; + +/* BGP static route configuration. */ +struct bgp_static +{ + /* Backdoor configuration. */ + int backdoor; + + /* Import check status. */ + u_char valid; + + /* IGP metric. */ + u_int32_t igpmetric; + + /* IGP nexthop. */ + struct in_addr igpnexthop; + + /* BGP redistribute route-map. */ + struct + { + char *name; + struct route_map *map; + } rmap; + + /* MPLS label. */ + u_char tag[3]; +}; + +#define DISTRIBUTE_IN_NAME(F) ((F)->dlist[FILTER_IN].name) +#define DISTRIBUTE_IN(F) ((F)->dlist[FILTER_IN].alist) +#define DISTRIBUTE_OUT_NAME(F) ((F)->dlist[FILTER_OUT].name) +#define DISTRIBUTE_OUT(F) ((F)->dlist[FILTER_OUT].alist) + +#define PREFIX_LIST_IN_NAME(F) ((F)->plist[FILTER_IN].name) +#define PREFIX_LIST_IN(F) ((F)->plist[FILTER_IN].plist) +#define PREFIX_LIST_OUT_NAME(F) ((F)->plist[FILTER_OUT].name) +#define PREFIX_LIST_OUT(F) ((F)->plist[FILTER_OUT].plist) + +#define FILTER_LIST_IN_NAME(F) ((F)->aslist[FILTER_IN].name) +#define FILTER_LIST_IN(F) ((F)->aslist[FILTER_IN].aslist) +#define FILTER_LIST_OUT_NAME(F) ((F)->aslist[FILTER_OUT].name) +#define FILTER_LIST_OUT(F) ((F)->aslist[FILTER_OUT].aslist) + +#define ROUTE_MAP_IN_NAME(F) ((F)->map[FILTER_IN].name) +#define ROUTE_MAP_IN(F) ((F)->map[FILTER_IN].map) +#define ROUTE_MAP_OUT_NAME(F) ((F)->map[FILTER_OUT].name) +#define ROUTE_MAP_OUT(F) ((F)->map[FILTER_OUT].map) + +#define UNSUPPRESS_MAP_NAME(F) ((F)->usmap.name) +#define UNSUPPRESS_MAP(F) ((F)->usmap.map) + +/* Prototypes. */ +void bgp_route_init (); +void bgp_announce_route (struct peer *, afi_t, safi_t); +void bgp_announce_route_all (struct peer *); +void bgp_default_originate (struct peer *, afi_t, safi_t, int); +void bgp_soft_reconfig_in (struct peer *, afi_t, safi_t); +void bgp_clear_route (struct peer *, afi_t, safi_t); +void bgp_clear_route_all (struct peer *); +void bgp_clear_adj_in (struct peer *, afi_t, safi_t); +void bgp_clear_stale_route (struct peer *, afi_t, safi_t); + +int bgp_nlri_sanity_check (struct peer *, int, u_char *, bgp_size_t); +int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); + +int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int); + +void bgp_redistribute_add (struct prefix *, struct in_addr *, u_int32_t, u_char); +void bgp_redistribute_delete (struct prefix *, u_char); +void bgp_redistribute_withdraw (struct bgp *, afi_t, int); + +void bgp_static_delete (struct bgp *); +void bgp_static_update (struct bgp *, struct prefix *, struct bgp_static *, + afi_t, safi_t); +void bgp_static_withdraw (struct bgp *, struct prefix *, afi_t, safi_t); + +int bgp_static_set_vpnv4 (struct vty *vty, char *, char *, char *); + +int bgp_static_unset_vpnv4 (struct vty *, char *, char *, char *); + +int bgp_config_write_network (struct vty *, struct bgp *, afi_t, safi_t, int *); +int bgp_config_write_distance (struct vty *, struct bgp *); + +void bgp_aggregate_increment (struct bgp *, struct prefix *, struct bgp_info *, + afi_t, safi_t); +void bgp_aggregate_decrement (struct bgp *, struct prefix *, struct bgp_info *, + afi_t, safi_t); + +u_char bgp_distance_apply (struct prefix *, struct bgp_info *, struct bgp *); + +afi_t bgp_node_afi (struct vty *); +safi_t bgp_node_safi (struct vty *); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c new file mode 100644 index 0000000..5af2c24 --- /dev/null +++ b/bgpd/bgp_routemap.c @@ -0,0 +1,3706 @@ +/* Route map function of bgpd. + Copyright (C) 1998, 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "prefix.h" +#include "filter.h" +#include "routemap.h" +#include "command.h" +#include "linklist.h" +#include "plist.h" +#include "memory.h" +#include "log.h" +#ifdef HAVE_GNU_REGEX +#include +#else +#include "regex-gnu.h" +#endif /* HAVE_GNU_REGEX */ +#include "buffer.h" +#include "sockunion.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_clist.h" +#include "bgpd/bgp_filter.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_ecommunity.h" + +/* Memo of route-map commands. + +o Cisco route-map + + match as-path : Done + community : Done + interface : Not yet + ip address : Done + ip next-hop : Done + ip route-source : (This will not be implemented by bgpd) + ip prefix-list : Done + ipv6 address : Done + ipv6 next-hop : Done + ipv6 route-source: (This will not be implemented by bgpd) + ipv6 prefix-list : Done + length : (This will not be implemented by bgpd) + metric : Done + route-type : (This will not be implemented by bgpd) + tag : (This will not be implemented by bgpd) + + set as-path prepend : Done + as-path tag : Not yet + automatic-tag : (This will not be implemented by bgpd) + community : Done + comm-list : Not yet + dampning : Not yet + default : (This will not be implemented by bgpd) + interface : (This will not be implemented by bgpd) + ip default : (This will not be implemented by bgpd) + ip next-hop : Done + ip precedence : (This will not be implemented by bgpd) + ip tos : (This will not be implemented by bgpd) + level : (This will not be implemented by bgpd) + local-preference : Done + metric : Done + metric-type : Not yet + origin : Done + tag : (This will not be implemented by bgpd) + weight : Done + +o Local extention + + set ipv6 next-hop global: Done + set ipv6 next-hop local : Done + +*/ + +/* `match ip address IP_ACCESS_LIST' */ + +/* Match function should return 1 if match is success else return + zero. */ +route_map_result_t +route_match_ip_address (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + /* struct prefix_ipv4 match; */ + + if (type == RMAP_BGP) + { + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, prefix) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip address' match statement. `arg' should be + access-list name. */ +void * +route_match_ip_address_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_address_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_ip_address_cmd = +{ + "ip address", + route_match_ip_address, + route_match_ip_address_compile, + route_match_ip_address_free +}; + +/* `match ip next-hop IP_ADDRESS' */ + +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_ip_next_hop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + struct bgp_info *bgp_info; + struct prefix_ipv4 p; + + if (type == RMAP_BGP) + { + bgp_info = object; + p.family = AF_INET; + p.prefix = bgp_info->attr->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, &p) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip next-hop' match statement. `arg' is + access-list name. */ +void * +route_match_ip_next_hop_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_next_hop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip next-hop matching. */ +struct route_map_rule_cmd route_match_ip_next_hop_cmd = +{ + "ip next-hop", + route_match_ip_next_hop, + route_match_ip_next_hop_compile, + route_match_ip_next_hop_free +}; + +/* `match ip route-source ACCESS-LIST' */ + +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_ip_route_source (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + struct bgp_info *bgp_info; + struct peer *peer; + struct prefix_ipv4 p; + + if (type == RMAP_BGP) + { + bgp_info = object; + peer = bgp_info->peer; + + if (! peer || sockunion_family (&peer->su) != AF_INET) + return RMAP_NOMATCH; + + p.family = AF_INET; + p.prefix = peer->su.sin.sin_addr; + p.prefixlen = IPV4_MAX_BITLEN; + + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, &p) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip route-source' match statement. `arg' is + access-list name. */ +void * +route_match_ip_route_source_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_route_source_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip route-source matching. */ +struct route_map_rule_cmd route_match_ip_route_source_cmd = +{ + "ip route-source", + route_match_ip_route_source, + route_match_ip_route_source_compile, + route_match_ip_route_source_free +}; + +/* `match ip address prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + + if (type == RMAP_BGP) + { + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_address_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_address_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = +{ + "ip address prefix-list", + route_match_ip_address_prefix_list, + route_match_ip_address_prefix_list_compile, + route_match_ip_address_prefix_list_free +}; + +/* `match ip next-hop prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + struct bgp_info *bgp_info; + struct prefix_ipv4 p; + + if (type == RMAP_BGP) + { + bgp_info = object; + p.family = AF_INET; + p.prefix = bgp_info->attr->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, &p) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_next_hop_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_next_hop_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = +{ + "ip next-hop prefix-list", + route_match_ip_next_hop_prefix_list, + route_match_ip_next_hop_prefix_list_compile, + route_match_ip_next_hop_prefix_list_free +}; + +/* `match ip route-source prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_route_source_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + struct bgp_info *bgp_info; + struct peer *peer; + struct prefix_ipv4 p; + + if (type == RMAP_BGP) + { + bgp_info = object; + peer = bgp_info->peer; + + if (! peer || sockunion_family (&peer->su) != AF_INET) + return RMAP_NOMATCH; + + p.family = AF_INET; + p.prefix = peer->su.sin.sin_addr; + p.prefixlen = IPV4_MAX_BITLEN; + + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, &p) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_route_source_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_route_source_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = +{ + "ip route-source prefix-list", + route_match_ip_route_source_prefix_list, + route_match_ip_route_source_prefix_list_compile, + route_match_ip_route_source_prefix_list_free +}; + +/* `match metric METRIC' */ + +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *med; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + med = rule; + bgp_info = object; + + if (bgp_info->attr->med == *med) + return RMAP_MATCH; + else + return RMAP_NOMATCH; + } + return RMAP_NOMATCH; +} + +/* Route map `match metric' match statement. `arg' is MED value */ +void * +route_match_metric_compile (char *arg) +{ + u_int32_t *med; + char *endptr = NULL; + + med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + *med = strtoul (arg, &endptr, 10); + if (*endptr != '\0' || *med == ULONG_MAX) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, med); + return NULL; + } + return med; +} + +/* Free route map's compiled `match metric' value. */ +void +route_match_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for metric matching. */ +struct route_map_rule_cmd route_match_metric_cmd = +{ + "metric", + route_match_metric, + route_match_metric_compile, + route_match_metric_free +}; + +/* `match as-path ASPATH' */ + +/* Match function for as-path match. I assume given object is */ +route_map_result_t +route_match_aspath (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + + struct as_list *as_list; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + as_list = as_list_lookup ((char *) rule); + if (as_list == NULL) + return RMAP_NOMATCH; + + bgp_info = object; + + /* Perform match. */ + return ((as_list_apply (as_list, bgp_info->attr->aspath) == AS_FILTER_DENY) ? RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Compile function for as-path match. */ +void * +route_match_aspath_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Compile function for as-path match. */ +void +route_match_aspath_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for aspath matching. */ +struct route_map_rule_cmd route_match_aspath_cmd = +{ + "as-path", + route_match_aspath, + route_match_aspath_compile, + route_match_aspath_free +}; + +#if ROUTE_MATCH_ASPATH_OLD +/* `match as-path ASPATH' */ + +/* Match function for as-path match. I assume given object is */ +int +route_match_aspath (void *rule, struct prefix *prefix, void *object) +{ + regex_t *regex; + struct bgp_info *bgp_info; + + regex = rule; + bgp_info = object; + + /* Perform match. */ + return bgp_regexec (regex, bgp_info->attr->aspath); +} + +/* Compile function for as-path match. */ +void * +route_match_aspath_compile (char *arg) +{ + regex_t *regex; + + regex = bgp_regcomp (arg); + if (! regex) + return NULL; + + return regex; +} + +/* Compile function for as-path match. */ +void +route_match_aspath_free (void *rule) +{ + regex_t *regex = rule; + + bgp_regex_free (regex); +} + +/* Route map commands for aspath matching. */ +struct route_map_rule_cmd route_match_aspath_cmd = +{ + "as-path", + route_match_aspath, + route_match_aspath_compile, + route_match_aspath_free +}; +#endif /* ROUTE_MATCH_ASPATH_OLD */ + +/* `match community COMMUNIY' */ +struct rmap_community +{ + char *name; + int exact; +}; + +/* Match function for community match. */ +route_map_result_t +route_match_community (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct community_list *list; + struct bgp_info *bgp_info; + struct rmap_community *rcom; + + if (type == RMAP_BGP) + { + bgp_info = object; + rcom = rule; + + list = community_list_lookup (bgp_clist, rcom->name, COMMUNITY_LIST_MASTER); + if (! list) + return RMAP_NOMATCH; + + if (rcom->exact) + { + if (community_list_exact_match (bgp_info->attr->community, list)) + return RMAP_MATCH; + } + else + { + if (community_list_match (bgp_info->attr->community, list)) + return RMAP_MATCH; + } + } + return RMAP_NOMATCH; +} + +/* Compile function for community match. */ +void * +route_match_community_compile (char *arg) +{ + struct rmap_community *rcom; + int len; + char *p; + + rcom = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_community)); + + p = strchr (arg, ' '); + if (p) + { + len = p - arg; + rcom->name = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1); + memcpy (rcom->name, arg, len); + rcom->exact = 1; + } + else + { + rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); + rcom->exact = 0; + } + return rcom; +} + +/* Compile function for community match. */ +void +route_match_community_free (void *rule) +{ + struct rmap_community *rcom = rule; + + XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom->name); + XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom); +} + +/* Route map commands for community matching. */ +struct route_map_rule_cmd route_match_community_cmd = +{ + "community", + route_match_community, + route_match_community_compile, + route_match_community_free +}; + +/* Match function for extcommunity match. */ +route_map_result_t +route_match_ecommunity (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct community_list *list; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + bgp_info = object; + + list = community_list_lookup (bgp_clist, (char *) rule, + EXTCOMMUNITY_LIST_MASTER); + if (! list) + return RMAP_NOMATCH; + + if (ecommunity_list_match (bgp_info->attr->ecommunity, list)) + return RMAP_MATCH; + } + return RMAP_NOMATCH; +} + +/* Compile function for extcommunity match. */ +void * +route_match_ecommunity_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Compile function for extcommunity match. */ +void +route_match_ecommunity_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for community matching. */ +struct route_map_rule_cmd route_match_ecommunity_cmd = +{ + "extcommunity", + route_match_ecommunity, + route_match_ecommunity_compile, + route_match_ecommunity_free +}; + +/* `match nlri` and `set nlri` are replaced by `address-family ipv4` + and `address-family vpnv4'. */ + +/* `match origin' */ +route_map_result_t +route_match_origin (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_char *origin; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + origin = rule; + bgp_info = object; + + if (bgp_info->attr->origin == *origin) + return RMAP_MATCH; + } + + return RMAP_NOMATCH; +} + +void * +route_match_origin_compile (char *arg) +{ + u_char *origin; + + origin = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_char)); + + if (strcmp (arg, "igp") == 0) + *origin = 0; + else if (strcmp (arg, "egp") == 0) + *origin = 1; + else + *origin = 2; + + return origin; +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_origin_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for origin matching. */ +struct route_map_rule_cmd route_match_origin_cmd = +{ + "origin", + route_match_origin, + route_match_origin_compile, + route_match_origin_free +}; +/* `set ip next-hop IP_ADDRESS' */ + +/* Set nexthop to object. ojbect must be pointer to struct attr. */ +struct rmap_ip_nexthop_set +{ + struct in_addr *address; + int peer_address; +}; + +route_map_result_t +route_set_ip_nexthop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct rmap_ip_nexthop_set *rins = rule; + struct in_addr peer_address; + struct bgp_info *bgp_info; + struct peer *peer; + + if (type == RMAP_BGP) + { + bgp_info = object; + peer = bgp_info->peer; + + if (rins->peer_address) + { + if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN) + && peer->su_remote + && sockunion_family (peer->su_remote) == AF_INET) + { + inet_aton (sockunion_su2str (peer->su_remote), &peer_address); + bgp_info->attr->nexthop = peer_address; + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); + } + else if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT) + && peer->su_local + && sockunion_family (peer->su_local) == AF_INET) + { + inet_aton (sockunion_su2str (peer->su_local), &peer_address); + bgp_info->attr->nexthop = peer_address; + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); + } + } + else + { + /* Set next hop value. */ + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); + bgp_info->attr->nexthop = *rins->address; + } + } + + return RMAP_OKAY; +} + +/* Route map `ip nexthop' compile function. Given string is converted + to struct in_addr structure. */ +void * +route_set_ip_nexthop_compile (char *arg) +{ + struct rmap_ip_nexthop_set *rins; + struct in_addr *address = NULL; + int peer_address = 0; + int ret; + + if (strcmp (arg, "peer-address") == 0) + peer_address = 1; + else + { + address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); + ret = inet_aton (arg, address); + + if (ret == 0) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, address); + return NULL; + } + } + + rins = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_ip_nexthop_set)); + memset (rins, 0, sizeof (struct rmap_ip_nexthop_set)); + + rins->address = address; + rins->peer_address = peer_address; + + return rins; +} + +/* Free route map's compiled `ip nexthop' value. */ +void +route_set_ip_nexthop_free (void *rule) +{ + struct rmap_ip_nexthop_set *rins = rule; + + if (rins->address) + XFREE (MTYPE_ROUTE_MAP_COMPILED, rins->address); + + XFREE (MTYPE_ROUTE_MAP_COMPILED, rins); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_ip_nexthop_cmd = +{ + "ip next-hop", + route_set_ip_nexthop, + route_set_ip_nexthop_compile, + route_set_ip_nexthop_free +}; + +/* `set local-preference LOCAL_PREF' */ + +/* Set local preference. */ +route_map_result_t +route_set_local_pref (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *local_pref; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + local_pref = rule; + bgp_info = object; + + /* Set local preference value. */ + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); + bgp_info->attr->local_pref = *local_pref; + } + + return RMAP_OKAY; +} + +/* set local preference compilation. */ +void * +route_set_local_pref_compile (char *arg) +{ + u_int32_t *local_pref; + char *endptr = NULL; + + /* Local preference value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + *local_pref = strtoul (arg, &endptr, 10); + if (*endptr != '\0' || *local_pref == ULONG_MAX) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, local_pref); + return NULL; + } + return local_pref; +} + +/* Free route map's local preference value. */ +void +route_set_local_pref_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set local preference rule structure. */ +struct route_map_rule_cmd route_set_local_pref_cmd = +{ + "local-preference", + route_set_local_pref, + route_set_local_pref_compile, + route_set_local_pref_free, +}; + +/* `set weight WEIGHT' */ + +/* Set weight. */ +route_map_result_t +route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type, + void *object) +{ + u_int16_t *weight; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + weight = rule; + bgp_info = object; + + /* Set weight value. */ + bgp_info->attr->weight = *weight; + } + + return RMAP_OKAY; +} + +/* set local preference compilation. */ +void * +route_set_weight_compile (char *arg) +{ + u_int16_t *weight; + char *endptr = NULL; + + /* Local preference value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + weight = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int16_t)); + *weight = strtoul (arg, &endptr, 10); + if (*endptr != '\0' || *weight == ULONG_MAX) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, weight); + return NULL; + } + return weight; +} + +/* Free route map's local preference value. */ +void +route_set_weight_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set local preference rule structure. */ +struct route_map_rule_cmd route_set_weight_cmd = +{ + "weight", + route_set_weight, + route_set_weight_compile, + route_set_weight_free, +}; + +/* `set metric METRIC' */ + +/* Set metric to attribute. */ +route_map_result_t +route_set_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + char *metric; + u_int32_t metric_val; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + metric = rule; + bgp_info = object; + + if (! (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) + bgp_info->attr->med = 0; + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + + if (all_digit (metric)) + { + metric_val = strtoul (metric, (char **)NULL, 10); + bgp_info->attr->med = metric_val; + } + else + { + metric_val = strtoul (metric+1, (char **)NULL, 10); + + if (strncmp (metric, "+", 1) == 0) + { + if (bgp_info->attr->med/2 + metric_val/2 > ULONG_MAX/2) + bgp_info->attr->med = ULONG_MAX-1; + else + bgp_info->attr->med += metric_val; + } + else if (strncmp (metric, "-", 1) == 0) + { + if (bgp_info->attr->med <= metric_val) + bgp_info->attr->med = 0; + else + bgp_info->attr->med -= metric_val; + } + } + } + return RMAP_OKAY; +} + +/* set metric compilation. */ +void * +route_set_metric_compile (char *arg) +{ + u_int32_t metric; + char *endptr = NULL; + + if (all_digit (arg)) + { + /* set metric value check*/ + metric = strtoul (arg, &endptr, 10); + if (*endptr != '\0' || metric == ULONG_MAX) + return NULL; + } + else + { + /* set metric +/-value check */ + if ((strncmp (arg, "+", 1) != 0 + && strncmp (arg, "-", 1) != 0) + || (! all_digit (arg+1))) + return NULL; + + metric = strtoul (arg+1, &endptr, 10); + if (*endptr != '\0' || metric == ULONG_MAX) + return NULL; + } + + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `set metric' value. */ +void +route_set_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_metric_cmd = +{ + "metric", + route_set_metric, + route_set_metric_compile, + route_set_metric_free, +}; + +/* `set as-path prepend ASPATH' */ + +/* For AS path prepend mechanism. */ +route_map_result_t +route_set_aspath_prepend (void *rule, struct prefix *prefix, route_map_object_t type, void *object) +{ + struct aspath *aspath; + struct aspath *new; + struct bgp_info *binfo; + + if (type == RMAP_BGP) + { + aspath = rule; + binfo = object; + + if (binfo->attr->aspath->refcnt) + new = aspath_dup (binfo->attr->aspath); + else + new = binfo->attr->aspath; + + aspath_prepend (aspath, new); + binfo->attr->aspath = new; + } + + return RMAP_OKAY; +} + +/* Compile function for as-path prepend. */ +void * +route_set_aspath_prepend_compile (char *arg) +{ + struct aspath *aspath; + + aspath = aspath_str2aspath (arg); + if (! aspath) + return NULL; + return aspath; +} + +/* Compile function for as-path prepend. */ +void +route_set_aspath_prepend_free (void *rule) +{ + struct aspath *aspath = rule; + aspath_free (aspath); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_aspath_prepend_cmd = +{ + "as-path prepend", + route_set_aspath_prepend, + route_set_aspath_prepend_compile, + route_set_aspath_prepend_free, +}; + +/* `set community COMMUNITY' */ +struct rmap_com_set +{ + struct community *com; + int additive; + int none; +}; + +/* For community set mechanism. */ +route_map_result_t +route_set_community (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct rmap_com_set *rcs; + struct bgp_info *binfo; + struct attr *attr; + struct community *new = NULL; + struct community *old; + struct community *merge; + + if (type == RMAP_BGP) + { + rcs = rule; + binfo = object; + attr = binfo->attr; + old = attr->community; + + /* "none" case. */ + if (rcs->none) + { + attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)); + attr->community = NULL; + return RMAP_OKAY; + } + + /* "additive" case. */ + if (rcs->additive && old) + { + merge = community_merge (community_dup (old), rcs->com); + new = community_uniq_sort (merge); + community_free (merge); + } + else + new = community_dup (rcs->com); + + attr->community = new; + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); + } + + return RMAP_OKAY; +} + +/* Compile function for set community. */ +void * +route_set_community_compile (char *arg) +{ + struct rmap_com_set *rcs; + struct community *com = NULL; + char *sp; + int additive = 0; + int none = 0; + + if (strcmp (arg, "none") == 0) + none = 1; + else + { + sp = strstr (arg, "additive"); + + if (sp && sp > arg) + { + /* "additive" keyworkd is included. */ + additive = 1; + *(sp - 1) = '\0'; + } + + com = community_str2com (arg); + + if (additive) + *(sp - 1) = ' '; + + if (! com) + return NULL; + } + + rcs = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set)); + memset (rcs, 0, sizeof (struct rmap_com_set)); + + rcs->com = com; + rcs->additive = additive; + rcs->none = none; + + return rcs; +} + +/* Free function for set community. */ +void +route_set_community_free (void *rule) +{ + struct rmap_com_set *rcs = rule; + + if (rcs->com) + community_free (rcs->com); + XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_community_cmd = +{ + "community", + route_set_community, + route_set_community_compile, + route_set_community_free, +}; + +/* `set comm-list (<1-99>|<100-500>|WORD) delete' */ + +/* For community set mechanism. */ +route_map_result_t +route_set_community_delete (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct community_list *list; + struct community *merge; + struct community *new; + struct community *old; + struct bgp_info *binfo; + + if (type == RMAP_BGP) + { + if (! rule) + return RMAP_OKAY; + + binfo = object; + list = community_list_lookup (bgp_clist, rule, COMMUNITY_LIST_MASTER); + old = binfo->attr->community; + + if (list && old) + { + merge = community_list_match_delete (old, list); + new = community_uniq_sort (merge); + community_free (merge); + + if (new->size == 0) + { + binfo->attr->community = NULL; + binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); + community_free (new); + } + else + { + binfo->attr->community = new; + binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); + } + } + } + + return RMAP_OKAY; +} + +/* Compile function for set community. */ +void * +route_set_community_delete_compile (char *arg) +{ + char *p; + char *str; + int len; + + p = strchr (arg, ' '); + if (p) + { + len = p - arg; + str = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1); + memcpy (str, arg, len); + } + else + str = NULL; + + return str; +} + +/* Free function for set community. */ +void +route_set_community_delete_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_community_delete_cmd = +{ + "comm-list", + route_set_community_delete, + route_set_community_delete_compile, + route_set_community_delete_free, +}; + +/* `set extcommunity rt COMMUNITY' */ + +/* For community set mechanism. */ +route_map_result_t +route_set_ecommunity_rt (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct ecommunity *ecom; + struct ecommunity *new_ecom; + struct ecommunity *old_ecom; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + ecom = rule; + bgp_info = object; + + if (! ecom) + return RMAP_OKAY; + + /* We assume additive for Extended Community. */ + old_ecom = bgp_info->attr->ecommunity; + + if (old_ecom) + new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); + else + new_ecom = ecommunity_dup (ecom); + + bgp_info->attr->ecommunity = new_ecom; + if (old_ecom) + ecommunity_free (old_ecom); + + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); + } + return RMAP_OKAY; +} + +/* Compile function for set community. */ +void * +route_set_ecommunity_rt_compile (char *arg) +{ + struct ecommunity *ecom; + + ecom = ecommunity_str2com (arg, ECOMMUNITY_TYPE_ROUTE_TARGET, 0); + if (! ecom) + return NULL; + return ecom; +} + +/* Free function for set community. */ +void +route_set_ecommunity_rt_free (void *rule) +{ + struct ecommunity *ecom = rule; + ecommunity_free (ecom); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_ecommunity_rt_cmd = +{ + "extcommunity rt", + route_set_ecommunity_rt, + route_set_ecommunity_rt_compile, + route_set_ecommunity_rt_free, +}; + +/* `set extcommunity soo COMMUNITY' */ + +/* For community set mechanism. */ +route_map_result_t +route_set_ecommunity_soo (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct ecommunity *ecom; + struct ecommunity *new_ecom; + struct ecommunity *old_ecom; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + ecom = rule; + bgp_info = object; + + if (! ecom) + return RMAP_OKAY; + + /* We assume additive for Extended Community. */ + old_ecom = bgp_info->attr->ecommunity; + + if (old_ecom) + new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); + else + new_ecom = ecommunity_dup (ecom); + + bgp_info->attr->ecommunity = new_ecom; + if (old_ecom) + ecommunity_free (old_ecom); + + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); + } + return RMAP_OKAY; +} + +/* Compile function for set community. */ +void * +route_set_ecommunity_soo_compile (char *arg) +{ + struct ecommunity *ecom; + + ecom = ecommunity_str2com (arg, ECOMMUNITY_TYPE_SITE_ORIGIN, 0); + if (! ecom) + return NULL; + + return ecom; +} + +/* Free function for set community. */ +void +route_set_ecommunity_soo_free (void *rule) +{ + struct ecommunity *ecom = rule; + ecommunity_free (ecom); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_ecommunity_soo_cmd = +{ + "extcommunity soo", + route_set_ecommunity_soo, + route_set_ecommunity_soo_compile, + route_set_ecommunity_soo_free, +}; + +/* `set extcommunity cost igp COMMUNITY' */ + +/* For community set mechanism. */ +route_map_result_t +route_set_ecommunity_cost_igp (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct ecommunity *ecom; + struct ecommunity *new_ecom; + struct ecommunity *old_ecom; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + ecom = rule; + bgp_info = object; + + if (! ecom) + return RMAP_OKAY; + + /* We assume additive for Extended Community. */ + old_ecom = bgp_info->attr->ecommunity; + + if (old_ecom) + new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); + else + new_ecom = ecommunity_dup (ecom); + + bgp_info->attr->ecommunity = new_ecom; + if (old_ecom) + ecommunity_free (old_ecom); + + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); + } + return RMAP_OKAY; +} + +/* Compile function for set community. */ +void * +route_set_ecommunity_cost_igp_compile (char *arg) +{ + struct ecommunity *ecom; + + ecom = ecommunity_cost_str2com (arg, ECOMMUNITY_COST_POI_IGP); + if (! ecom) + return NULL; + return ecom; +} + +/* Free function for set community. */ +void +route_set_ecommunity_cost_igp_free (void *rule) +{ + struct ecommunity *ecom = rule; + ecommunity_free (ecom); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_ecommunity_cost_igp_cmd = +{ + "extcommunity cost igp", + route_set_ecommunity_cost_igp, + route_set_ecommunity_cost_igp_compile, + route_set_ecommunity_cost_igp_free, +}; + +/* `set origin ORIGIN' */ + +/* For origin set. */ +route_map_result_t +route_set_origin (void *rule, struct prefix *prefix, route_map_object_t type, void *object) +{ + u_char *origin; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + origin = rule; + bgp_info = object; + + bgp_info->attr->origin = *origin; + } + + return RMAP_OKAY; +} + +/* Compile function for origin set. */ +void * +route_set_origin_compile (char *arg) +{ + u_char *origin; + + origin = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_char)); + + if (strcmp (arg, "igp") == 0) + *origin = 0; + else if (strcmp (arg, "egp") == 0) + *origin = 1; + else + *origin = 2; + + return origin; +} + +/* Compile function for origin set. */ +void +route_set_origin_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_origin_cmd = +{ + "origin", + route_set_origin, + route_set_origin_compile, + route_set_origin_free, +}; + +/* `set atomic-aggregate' */ + +/* For atomic aggregate set. */ +route_map_result_t +route_set_atomic_aggregate (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + bgp_info = object; + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + } + + return RMAP_OKAY; +} + +/* Compile function for atomic aggregate. */ +void * +route_set_atomic_aggregate_compile (char *arg) +{ + return (void *)1; +} + +/* Compile function for atomic aggregate. */ +void +route_set_atomic_aggregate_free (void *rule) +{ + return; +} + +/* Set atomic aggregate rule structure. */ +struct route_map_rule_cmd route_set_atomic_aggregate_cmd = +{ + "atomic-aggregate", + route_set_atomic_aggregate, + route_set_atomic_aggregate_compile, + route_set_atomic_aggregate_free, +}; + +/* `set aggregator as AS A.B.C.D' */ +struct aggregator +{ + as_t as; + struct in_addr address; +}; + +route_map_result_t +route_set_aggregator_as (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct bgp_info *bgp_info; + struct aggregator *aggregator; + + if (type == RMAP_BGP) + { + bgp_info = object; + aggregator = rule; + + bgp_info->attr->aggregator_as = aggregator->as; + bgp_info->attr->aggregator_addr = aggregator->address; + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); + } + + return RMAP_OKAY; +} + +void * +route_set_aggregator_as_compile (char *arg) +{ + struct aggregator *aggregator; + char as[10]; + char address[20]; + + aggregator = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct aggregator)); + memset (aggregator, 0, sizeof (struct aggregator)); + + sscanf (arg, "%s %s", as, address); + + aggregator->as = strtoul (as, NULL, 10); + inet_aton (address, &aggregator->address); + + return aggregator; +} + +void +route_set_aggregator_as_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_set_aggregator_as_cmd = +{ + "aggregator as", + route_set_aggregator_as, + route_set_aggregator_as_compile, + route_set_aggregator_as_free, +}; + +#ifdef HAVE_IPV6 +/* `match ipv6 address IP_ACCESS_LIST' */ + +route_map_result_t +route_match_ipv6_address (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + + if (type == RMAP_BGP) + { + alist = access_list_lookup (AFI_IP6, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, prefix) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ipv6_address_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ipv6_address_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_ipv6_address_cmd = +{ + "ipv6 address", + route_match_ipv6_address, + route_match_ipv6_address_compile, + route_match_ipv6_address_free +}; + +/* `match ipv6 next-hop IP_ADDRESS' */ + +route_map_result_t +route_match_ipv6_next_hop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct in6_addr *addr; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + addr = rule; + bgp_info = object; + + if (IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_global, rule)) + return RMAP_MATCH; + + if (bgp_info->attr->mp_nexthop_len == 32 && + IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_local, rule)) + return RMAP_MATCH; + + return RMAP_NOMATCH; + } + + return RMAP_NOMATCH; +} + +void * +route_match_ipv6_next_hop_compile (char *arg) +{ + struct in6_addr *address; + int ret; + + address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr)); + + ret = inet_pton (AF_INET6, arg, address); + if (!ret) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, address); + return NULL; + } + + return address; +} + +void +route_match_ipv6_next_hop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = +{ + "ipv6 next-hop", + route_match_ipv6_next_hop, + route_match_ipv6_next_hop_compile, + route_match_ipv6_next_hop_free +}; + +/* `match ipv6 address prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ipv6_address_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + + if (type == RMAP_BGP) + { + plist = prefix_list_lookup (AFI_IP6, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ipv6_address_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ipv6_address_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = +{ + "ipv6 address prefix-list", + route_match_ipv6_address_prefix_list, + route_match_ipv6_address_prefix_list_compile, + route_match_ipv6_address_prefix_list_free +}; + +/* `set ipv6 nexthop global IP_ADDRESS' */ + +/* Set nexthop to object. ojbect must be pointer to struct attr. */ +route_map_result_t +route_set_ipv6_nexthop_global (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct in6_addr *address; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + address = rule; + bgp_info = object; + + /* Set next hop value. */ + bgp_info->attr->mp_nexthop_global = *address; + + /* Set nexthop length. */ + if (bgp_info->attr->mp_nexthop_len == 0) + bgp_info->attr->mp_nexthop_len = 16; + } + + return RMAP_OKAY; +} + +/* Route map `ip next-hop' compile function. Given string is converted + to struct in_addr structure. */ +void * +route_set_ipv6_nexthop_global_compile (char *arg) +{ + int ret; + struct in6_addr *address; + + address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr)); + + ret = inet_pton (AF_INET6, arg, address); + + if (ret == 0) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, address); + return NULL; + } + + return address; +} + +/* Free route map's compiled `ip next-hop' value. */ +void +route_set_ipv6_nexthop_global_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = +{ + "ipv6 next-hop global", + route_set_ipv6_nexthop_global, + route_set_ipv6_nexthop_global_compile, + route_set_ipv6_nexthop_global_free +}; + +/* `set ipv6 nexthop local IP_ADDRESS' */ + +/* Set nexthop to object. ojbect must be pointer to struct attr. */ +route_map_result_t +route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct in6_addr *address; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + address = rule; + bgp_info = object; + + /* Set next hop value. */ + bgp_info->attr->mp_nexthop_local = *address; + + /* Set nexthop length. */ + if (bgp_info->attr->mp_nexthop_len != 32) + bgp_info->attr->mp_nexthop_len = 32; + } + + return RMAP_OKAY; +} + +/* Route map `ip nexthop' compile function. Given string is converted + to struct in_addr structure. */ +void * +route_set_ipv6_nexthop_local_compile (char *arg) +{ + int ret; + struct in6_addr *address; + + address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr)); + + ret = inet_pton (AF_INET6, arg, address); + + if (ret == 0) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, address); + return NULL; + } + + return address; +} + +/* Free route map's compiled `ip nexthop' value. */ +void +route_set_ipv6_nexthop_local_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = +{ + "ipv6 next-hop local", + route_set_ipv6_nexthop_local, + route_set_ipv6_nexthop_local_compile, + route_set_ipv6_nexthop_local_free +}; +#endif /* HAVE_IPV6 */ + +/* `set vpnv4 nexthop A.B.C.D' */ + +route_map_result_t +route_set_vpnv4_nexthop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct in_addr *address; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + address = rule; + bgp_info = object; + + /* Set next hop value. */ + bgp_info->attr->mp_nexthop_global_in = *address; + } + + return RMAP_OKAY; +} + +void * +route_set_vpnv4_nexthop_compile (char *arg) +{ + int ret; + struct in_addr *address; + + address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); + + ret = inet_aton (arg, address); + + if (ret == 0) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, address); + return NULL; + } + + return address; +} + +void +route_set_vpnv4_nexthop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_vpnv4_nexthop_cmd = +{ + "vpnv4 next-hop", + route_set_vpnv4_nexthop, + route_set_vpnv4_nexthop_compile, + route_set_vpnv4_nexthop_free +}; + +/* `set originator-id' */ + +/* For origin set. */ +route_map_result_t +route_set_originator_id (void *rule, struct prefix *prefix, route_map_object_t type, void *object) +{ + struct in_addr *address; + struct bgp_info *bgp_info; + + if (type == RMAP_BGP) + { + address = rule; + bgp_info = object; + + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); + bgp_info->attr->originator_id = *address; + } + + return RMAP_OKAY; +} + +/* Compile function for originator-id set. */ +void * +route_set_originator_id_compile (char *arg) +{ + int ret; + struct in_addr *address; + + address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); + + ret = inet_aton (arg, address); + + if (ret == 0) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, address); + return NULL; + } + + return address; +} + +/* Compile function for originator_id set. */ +void +route_set_originator_id_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_originator_id_cmd = +{ + "originator-id", + route_set_originator_id, + route_set_originator_id_compile, + route_set_originator_id_free, +}; + +/* Add bgp route map rule. */ +int +bgp_route_match_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Delete bgp route map rule. */ +int +bgp_route_match_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Add bgp route map rule. */ +int +bgp_route_set_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Delete bgp route map rule. */ +int +bgp_route_set_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Hook function for updating route_map assignment. */ +void +bgp_route_map_update () +{ + int i; + afi_t afi; + safi_t safi; + int direct; + struct listnode *nn, *nm; + struct bgp *bgp; + struct peer *peer; + struct peer_group *group; + struct bgp_filter *filter; + struct bgp_node *bn; + struct bgp_static *bgp_static; + + /* For neighbor route-map updates. */ + LIST_LOOP (bm->bgp, bgp, nn) + { + LIST_LOOP (bgp->peer, peer, nm) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + filter = &peer->filter[afi][safi]; + + for (direct = FILTER_IN; direct < FILTER_MAX; direct++) + { + if (filter->map[direct].name) + filter->map[direct].map = + route_map_lookup_by_name (filter->map[direct].name); + else + filter->map[direct].map = NULL; + } + + if (filter->usmap.name) + filter->usmap.map = route_map_lookup_by_name (filter->usmap.name); + else + filter->usmap.map = NULL; + } + } + LIST_LOOP (bgp->group, group, nm) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + filter = &group->conf->filter[afi][safi]; + + for (direct = FILTER_IN; direct < FILTER_MAX; direct++) + { + if (filter->map[direct].name) + filter->map[direct].map = + route_map_lookup_by_name (filter->map[direct].name); + else + filter->map[direct].map = NULL; + } + + if (filter->usmap.name) + filter->usmap.map = route_map_lookup_by_name (filter->usmap.name); + else + filter->usmap.map = NULL; + } + } + } + + /* For default-originate route-map updates. */ + LIST_LOOP (bm->bgp, bgp, nn) + { + LIST_LOOP (bgp->peer, peer, nm) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + if (peer->default_rmap[afi][safi].name) + peer->default_rmap[afi][safi].map = + route_map_lookup_by_name (peer->default_rmap[afi][safi].name); + else + peer->default_rmap[afi][safi].map = NULL; + } + } + } + + /* For network route-map updates. */ + LIST_LOOP (bm->bgp, bgp, nn) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + for (bn = bgp_table_top (bgp->route[afi][safi]); bn; + bn = bgp_route_next (bn)) + if ((bgp_static = bn->info) != NULL) + { + if (bgp_static->rmap.name) + bgp_static->rmap.map = + route_map_lookup_by_name (bgp_static->rmap.name); + else + bgp_static->rmap.map = NULL; + } + } + + /* For redistribute route-map updates. */ + LIST_LOOP (bm->bgp, bgp, nn) + { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name) + bgp->rmap[ZEBRA_FAMILY_IPV4][i].map = + route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name); +#ifdef HAVE_IPV6 + if (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name) + bgp->rmap[ZEBRA_FAMILY_IPV6][i].map = + route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name); +#endif /* HAVE_IPV6 */ + } + } +} + +DEFUN (match_ip_address, + match_ip_address_cmd, + "match ip address (<1-199>|<1300-2699>|WORD)", + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "ip address", argv[0]); +} + +DEFUN (no_match_ip_address, + no_match_ip_address_cmd, + "no match ip address", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n") +{ + if (argc == 0) + return bgp_route_match_delete (vty, vty->index, "ip address", NULL); + + return bgp_route_match_delete (vty, vty->index, "ip address", argv[0]); +} + +ALIAS (no_match_ip_address, + no_match_ip_address_val_cmd, + "no match ip address (<1-199>|<1300-2699>|WORD)", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n"); + +DEFUN (match_ip_next_hop, + match_ip_next_hop_cmd, + "match ip next-hop (<1-199>|<1300-2699>|WORD)", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "ip next-hop", argv[0]); +} + +DEFUN (no_match_ip_next_hop, + no_match_ip_next_hop_cmd, + "no match ip next-hop", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n") +{ + if (argc == 0) + return bgp_route_match_delete (vty, vty->index, "ip next-hop", NULL); + + return bgp_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); +} + +ALIAS (no_match_ip_next_hop, + no_match_ip_next_hop_val_cmd, + "no match ip next-hop (<1-199>|<1300-2699>|WORD)", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n"); + +DEFUN (match_ip_route_source, + match_ip_route_source_cmd, + "match ip route-source (<1-199>|<1300-2699>|WORD)", + MATCH_STR + IP_STR + "Match advertising source address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP standard access-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "ip route-source", argv[0]); +} + +DEFUN (no_match_ip_route_source, + no_match_ip_route_source_cmd, + "no match ip route-source", + NO_STR + MATCH_STR + IP_STR + "Match advertising source address of route\n") +{ + if (argc == 0) + return bgp_route_match_delete (vty, vty->index, "ip route-source", NULL); + + return bgp_route_match_delete (vty, vty->index, "ip route-source", argv[0]); +} + +ALIAS (no_match_ip_route_source, + no_match_ip_route_source_val_cmd, + "no match ip route-source (<1-199>|<1300-2699>|WORD)", + NO_STR + MATCH_STR + IP_STR + "Match advertising source address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP standard access-list name\n"); + +DEFUN (match_ip_address_prefix_list, + match_ip_address_prefix_list_cmd, + "match ip address prefix-list WORD", + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]); +} + +DEFUN (no_match_ip_address_prefix_list, + no_match_ip_address_prefix_list_cmd, + "no match ip address prefix-list", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n") +{ + if (argc == 0) + return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); + + return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]); +} + +ALIAS (no_match_ip_address_prefix_list, + no_match_ip_address_prefix_list_val_cmd, + "no match ip address prefix-list WORD", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n"); + +DEFUN (match_ip_next_hop_prefix_list, + match_ip_next_hop_prefix_list_cmd, + "match ip next-hop prefix-list WORD", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]); +} + +DEFUN (no_match_ip_next_hop_prefix_list, + no_match_ip_next_hop_prefix_list_cmd, + "no match ip next-hop prefix-list", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n") +{ + if (argc == 0) + return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL); + + return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]); +} + +ALIAS (no_match_ip_next_hop_prefix_list, + no_match_ip_next_hop_prefix_list_val_cmd, + "no match ip next-hop prefix-list WORD", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n"); + +DEFUN (match_ip_route_source_prefix_list, + match_ip_route_source_prefix_list_cmd, + "match ip route-source prefix-list WORD", + MATCH_STR + IP_STR + "Match advertising source address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "ip route-source prefix-list", argv[0]); +} + +DEFUN (no_match_ip_route_source_prefix_list, + no_match_ip_route_source_prefix_list_cmd, + "no match ip route-source prefix-list", + NO_STR + MATCH_STR + IP_STR + "Match advertising source address of route\n" + "Match entries of prefix-lists\n") +{ + if (argc == 0) + return bgp_route_match_delete (vty, vty->index, "ip route-source prefix-list", NULL); + + return bgp_route_match_delete (vty, vty->index, "ip route-source prefix-list", argv[0]); +} + +ALIAS (no_match_ip_route_source_prefix_list, + no_match_ip_route_source_prefix_list_val_cmd, + "no match ip route-source prefix-list WORD", + NO_STR + MATCH_STR + IP_STR + "Match advertising source address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n"); + +DEFUN (match_metric, + match_metric_cmd, + "match metric <0-4294967295>", + MATCH_STR + "Match metric of route\n" + "Metric value\n") +{ + return bgp_route_match_add (vty, vty->index, "metric", argv[0]); +} + +DEFUN (no_match_metric, + no_match_metric_cmd, + "no match metric", + NO_STR + MATCH_STR + "Match metric of route\n") +{ + if (argc == 0) + return bgp_route_match_delete (vty, vty->index, "metric", NULL); + + return bgp_route_match_delete (vty, vty->index, "metric", argv[0]); +} + +ALIAS (no_match_metric, + no_match_metric_val_cmd, + "no match metric <0-4294967295>", + NO_STR + MATCH_STR + "Match metric of route\n" + "Metric value\n"); + +DEFUN (match_community, + match_community_cmd, + "match community (<1-99>|<100-500>|WORD)", + MATCH_STR + "Match BGP community list\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "community", argv[0]); +} + +DEFUN (match_community_exact, + match_community_exact_cmd, + "match community (<1-99>|<100-500>|WORD) exact-match", + MATCH_STR + "Match BGP community list\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n" + "Do exact matching of communities\n") +{ + int ret; + char *argstr; + + argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, + strlen (argv[0]) + strlen ("exact-match") + 2); + + sprintf (argstr, "%s exact-match", argv[0]); + + ret = bgp_route_match_add (vty, vty->index, "community", argstr); + + XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr); + + return ret; +} + +DEFUN (no_match_community, + no_match_community_cmd, + "no match community", + NO_STR + MATCH_STR + "Match BGP community list\n") +{ + return bgp_route_match_delete (vty, vty->index, "community", NULL); +} + +ALIAS (no_match_community, + no_match_community_val_cmd, + "no match community (<1-99>|<100-500>|WORD)", + NO_STR + MATCH_STR + "Match BGP community list\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n"); + +ALIAS (no_match_community, + no_match_community_exact_cmd, + "no match community (<1-99>|<100-500>|WORD) exact-match", + NO_STR + MATCH_STR + "Match BGP community list\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n" + "Do exact matching of communities\n"); + +DEFUN (match_ecommunity, + match_ecommunity_cmd, + "match extcommunity (<1-99>|<100-500>|WORD)", + MATCH_STR + "Match BGP/VPN extended community list\n" + "Extended community-list number (standard)\n" + "Extended community-list number (expanded)\n" + "Extended community-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "extcommunity", argv[0]); +} + +DEFUN (no_match_ecommunity, + no_match_ecommunity_cmd, + "no match extcommunity", + NO_STR + MATCH_STR + "Match BGP/VPN extended community list\n") +{ + return bgp_route_match_delete (vty, vty->index, "extcommunity", NULL); +} + +ALIAS (no_match_ecommunity, + no_match_ecommunity_val_cmd, + "no match extcommunity (<1-99>|<100-500>|WORD)", + NO_STR + MATCH_STR + "Match BGP/VPN extended community list\n" + "Extended community-list number (standard)\n" + "Extended community-list number (expanded)\n" + "Extended community-list name\n"); + +DEFUN (match_aspath, + match_aspath_cmd, + "match as-path WORD", + MATCH_STR + "Match BGP AS path list\n" + "AS path access-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "as-path", argv[0]); +} + +DEFUN (no_match_aspath, + no_match_aspath_cmd, + "no match as-path", + NO_STR + MATCH_STR + "Match BGP AS path list\n") +{ + return bgp_route_match_delete (vty, vty->index, "as-path", NULL); +} + +ALIAS (no_match_aspath, + no_match_aspath_val_cmd, + "no match as-path WORD", + NO_STR + MATCH_STR + "Match BGP AS path list\n" + "AS path access-list name\n"); + +DEFUN (match_origin, + match_origin_cmd, + "match origin (egp|igp|incomplete)", + MATCH_STR + "BGP origin code\n" + "remote EGP\n" + "local IGP\n" + "unknown heritage\n") +{ + if (strncmp (argv[0], "igp", 2) == 0) + return bgp_route_match_add (vty, vty->index, "origin", "igp"); + if (strncmp (argv[0], "egp", 1) == 0) + return bgp_route_match_add (vty, vty->index, "origin", "egp"); + if (strncmp (argv[0], "incomplete", 2) == 0) + return bgp_route_match_add (vty, vty->index, "origin", "incomplete"); + + return CMD_WARNING; +} + +DEFUN (no_match_origin, + no_match_origin_cmd, + "no match origin", + NO_STR + MATCH_STR + "BGP origin code\n") +{ + return bgp_route_match_delete (vty, vty->index, "origin", NULL); +} + +ALIAS (no_match_origin, + no_match_origin_val_cmd, + "no match origin (egp|igp|incomplete)", + NO_STR + MATCH_STR + "BGP origin code\n" + "remote EGP\n" + "local IGP\n" + "unknown heritage\n"); + +DEFUN (set_ip_nexthop, + set_ip_nexthop_cmd, + "set ip next-hop A.B.C.D", + SET_STR + IP_STR + "Next hop address\n" + "IP address of next hop\n") +{ + union sockunion su; + int ret; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed Next-hop address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_route_set_add (vty, vty->index, "ip next-hop", argv[0]); +} + +DEFUN (set_ip_nexthop_bgp, + set_ip_nexthop_bgp_cmd, + "set ip next-hop peer-address", + SET_STR + IP_STR + "Next hop address\n" + "Use peer address (for BGP only)\n") +{ + return bgp_route_set_add (vty, vty->index, "ip next-hop", "peer-address"); +} + +DEFUN (no_set_ip_nexthop, + no_set_ip_nexthop_cmd, + "no set ip next-hop", + NO_STR + SET_STR + IP_STR + "Next hop address\n") +{ + return bgp_route_set_delete (vty, vty->index, "ip next-hop", NULL); +} + +ALIAS (no_set_ip_nexthop, + no_set_ip_nexthop_val_cmd, + "no set ip next-hop A.B.C.D", + NO_STR + SET_STR + IP_STR + "Next hop address\n" + "IP address of next hop\n"); + +ALIAS (no_set_ip_nexthop, + no_set_ip_nexthop_val_bgp_cmd, + "no set ip next-hop peer-address", + NO_STR + SET_STR + IP_STR + "Next hop address\n" + "Use peer address (for BGP only)\n"); + +DEFUN (set_metric, + set_metric_cmd, + "set metric <0-4294967295>", + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n") +{ + return bgp_route_set_add (vty, vty->index, "metric", argv[0]); +} + +ALIAS (set_metric, + set_metric_addsub_cmd, + "set metric <+/-metric>", + SET_STR + "Metric value for destination routing protocol\n" + "Add or subtract BGP metric\n"); + +DEFUN (no_set_metric, + no_set_metric_cmd, + "no set metric", + NO_STR + SET_STR + "Metric value for destination routing protocol\n") +{ + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "metric", NULL); + + return bgp_route_set_delete (vty, vty->index, "metric", argv[0]); +} + +ALIAS (no_set_metric, + no_set_metric_val_cmd, + "no set metric <0-4294967295>", + NO_STR + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n"); + +DEFUN (set_local_pref, + set_local_pref_cmd, + "set local-preference <0-4294967295>", + SET_STR + "BGP local preference path attribute\n" + "Preference value\n") +{ + return bgp_route_set_add (vty, vty->index, "local-preference", argv[0]); +} + +DEFUN (no_set_local_pref, + no_set_local_pref_cmd, + "no set local-preference", + NO_STR + SET_STR + "BGP local preference path attribute\n") +{ + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "local-preference", NULL); + + return bgp_route_set_delete (vty, vty->index, "local-preference", argv[0]); +} + +ALIAS (no_set_local_pref, + no_set_local_pref_val_cmd, + "no set local-preference <0-4294967295>", + NO_STR + SET_STR + "BGP local preference path attribute\n" + "Preference value\n"); + +DEFUN (set_weight, + set_weight_cmd, + "set weight <0-65535>", + SET_STR + "BGP weight for routing table\n" + "Weight value\n") +{ + return bgp_route_set_add (vty, vty->index, "weight", argv[0]); +} + +DEFUN (no_set_weight, + no_set_weight_cmd, + "no set weight", + NO_STR + SET_STR + "BGP weight for routing table\n") +{ + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "weight", NULL); + + return bgp_route_set_delete (vty, vty->index, "weight", argv[0]); +} + +ALIAS (no_set_weight, + no_set_weight_val_cmd, + "no set weight <0-65535>", + NO_STR + SET_STR + "BGP weight for routing table\n" + "Weight value\n"); + +DEFUN (set_aspath_prepend, + set_aspath_prepend_cmd, + "set as-path prepend .<1-65535>", + SET_STR + "Prepend string for a BGP AS-path attribute\n" + "Prepend to the as-path\n" + "AS number\n") +{ + int ret; + char *str; + + str = argv_concat (argv, argc, 0); + ret = bgp_route_set_add (vty, vty->index, "as-path prepend", str); + XFREE (MTYPE_TMP, str); + + return ret; +} + +DEFUN (no_set_aspath_prepend, + no_set_aspath_prepend_cmd, + "no set as-path prepend", + NO_STR + SET_STR + "Prepend string for a BGP AS-path attribute\n" + "Prepend to the as-path\n") +{ + return bgp_route_set_delete (vty, vty->index, "as-path prepend", NULL); +} + +ALIAS (no_set_aspath_prepend, + no_set_aspath_prepend_val_cmd, + "no set as-path prepend .<1-65535>", + NO_STR + SET_STR + "Prepend string for a BGP AS-path attribute\n" + "Prepend to the as-path\n" + "AS number\n"); + +DEFUN (set_community, + set_community_cmd, + "set community .AA:NN", + SET_STR + "BGP community attribute\n" + "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n") +{ + int i; + int first = 0; + int additive = 0; + struct buffer *b; + struct community *com = NULL; + char *str; + char *argstr; + int ret; + + b = buffer_new (1024); + + for (i = 0; i < argc; i++) + { + if (strncmp (argv[i], "additive", strlen (argv[i])) == 0) + { + additive = 1; + continue; + } + + if (first) + buffer_putc (b, ' '); + else + first = 1; + + if (strncmp (argv[i], "internet", strlen (argv[i])) == 0) + { + buffer_putstr (b, "internet"); + continue; + } + if (strncmp (argv[i], "local-AS", strlen (argv[i])) == 0) + { + buffer_putstr (b, "local-AS"); + continue; + } + if (strncmp (argv[i], "no-a", strlen ("no-a")) == 0 + && strncmp (argv[i], "no-advertise", strlen (argv[i])) == 0) + { + buffer_putstr (b, "no-advertise"); + continue; + } + if (strncmp (argv[i], "no-e", strlen ("no-e"))== 0 + && strncmp (argv[i], "no-export", strlen (argv[i])) == 0) + { + buffer_putstr (b, "no-export"); + continue; + } + buffer_putstr (b, argv[i]); + } + buffer_putc (b, '\0'); + + /* Fetch result string then compile it to communities attribute. */ + str = buffer_getstr (b); + buffer_free (b); + + if (str) + { + com = community_str2com (str); + free (str); + } + + /* Can't compile user input into communities attribute. */ + if (! com) + { + vty_out (vty, "%% Malformed communities attribute%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Set communites attribute string. */ + str = community_str (com); + + if (additive) + { + argstr = XCALLOC (MTYPE_TMP, strlen (str) + strlen (" additive") + 1); + strcpy (argstr, str); + strcpy (argstr + strlen (str), " additive"); + ret = bgp_route_set_add (vty, vty->index, "community", argstr); + XFREE (MTYPE_TMP, argstr); + } + else + ret = bgp_route_set_add (vty, vty->index, "community", str); + + community_free (com); + + return ret; +} + +DEFUN (set_community_none, + set_community_none_cmd, + "set community none", + SET_STR + "BGP community attribute\n" + "No community attribute\n") +{ + return bgp_route_set_add (vty, vty->index, "community", "none"); +} + +DEFUN (no_set_community, + no_set_community_cmd, + "no set community", + NO_STR + SET_STR + "BGP community attribute\n") +{ + return bgp_route_set_delete (vty, vty->index, "community", NULL); +} + +ALIAS (no_set_community, + no_set_community_val_cmd, + "no set community .AA:NN", + NO_STR + SET_STR + "BGP community attribute\n" + "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n"); + +ALIAS (no_set_community, + no_set_community_none_cmd, + "no set community none", + NO_STR + SET_STR + "BGP community attribute\n" + "No community attribute\n"); + +DEFUN (set_community_delete, + set_community_delete_cmd, + "set comm-list (<1-99>|<100-500>|WORD) delete", + SET_STR + "set BGP community list (for deletion)\n" + "Community-list number (standard)\n" + "Communitly-list number (expanded)\n" + "Community-list name\n" + "Delete matching communities\n") +{ + char *str; + + str = XCALLOC (MTYPE_TMP, strlen (argv[0]) + strlen (" delete") + 1); + strcpy (str, argv[0]); + strcpy (str + strlen (argv[0]), " delete"); + + bgp_route_set_add (vty, vty->index, "comm-list", str); + + XFREE (MTYPE_TMP, str); + return CMD_SUCCESS; +} + +DEFUN (no_set_community_delete, + no_set_community_delete_cmd, + "no set comm-list", + NO_STR + SET_STR + "set BGP community list (for deletion)\n") +{ + return bgp_route_set_delete (vty, vty->index, "comm-list", NULL); +} + +ALIAS (no_set_community_delete, + no_set_community_delete_val_cmd, + "no set comm-list (<1-99>|<100-500>|WORD) delete", + NO_STR + SET_STR + "set BGP community list (for deletion)\n" + "Community-list number (standard)\n" + "Communitly-list number (expanded)\n" + "Community-list name\n" + "Delete matching communities\n"); + +DEFUN (set_ecommunity_rt, + set_ecommunity_rt_cmd, + "set extcommunity rt .ASN:nn_or_IP-address:nn", + SET_STR + "BGP extended community attribute\n" + "Route Target extened communityt\n" + "VPN extended community\n") +{ + struct ecommunity *ecom; + int ret; + char *str; + + str = argv_concat (argv, argc, 0); + ecom = ecommunity_str2com (str, ECOMMUNITY_TYPE_ROUTE_TARGET, 0); + XFREE (MTYPE_TMP, str); + if (! ecom) + { + vty_out (vty, "%% Malformed communities attribute%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_RMAP); + ret = bgp_route_set_add (vty, vty->index, "extcommunity rt", ecom->str); + ecommunity_free (ecom); + + return ret; +} + +DEFUN (no_set_ecommunity_rt, + no_set_ecommunity_rt_cmd, + "no set extcommunity rt", + NO_STR + SET_STR + "BGP extended community attribute\n" + "Route Target extened communityt\n") +{ + return bgp_route_set_delete (vty, vty->index, "extcommunity rt", NULL); +} + +ALIAS (no_set_ecommunity_rt, + no_set_ecommunity_rt_val_cmd, + "no set extcommunity rt .ASN:nn_or_IP-address:nn", + NO_STR + SET_STR + "BGP extended community attribute\n" + "Route Target extened communityt\n" + "VPN extended community\n"); + +DEFUN (set_ecommunity_soo, + set_ecommunity_soo_cmd, + "set extcommunity soo .ASN:nn_or_IP-address:nn", + SET_STR + "BGP extended community attribute\n" + "Site-of-Origin extended community\n" + "VPN extended community\n") +{ + struct ecommunity *ecom; + int ret; + char *str; + + str = argv_concat (argv, argc, 0); + ecom = ecommunity_str2com (str, ECOMMUNITY_TYPE_SITE_ORIGIN, 0); + XFREE (MTYPE_TMP, str); + if (! ecom) + { + vty_out (vty, "%% Malformed communities attribute%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_RMAP); + ret = bgp_route_set_add (vty, vty->index, "extcommunity soo", ecom->str); + ecommunity_free (ecom); + + return ret; +} + +DEFUN (no_set_ecommunity_soo, + no_set_ecommunity_soo_cmd, + "no set extcommunity soo", + NO_STR + SET_STR + "BGP extended community attribute\n" + "Site-of-Origin extended community\n") +{ + return bgp_route_set_delete (vty, vty->index, "extcommunity soo", NULL); +} + +ALIAS (no_set_ecommunity_soo, + no_set_ecommunity_soo_val_cmd, + "no set extcommunity soo .ASN:nn_or_IP-address:nn", + NO_STR + SET_STR + "BGP extended community attribute\n" + "Site-of-Origin extended community\n" + "VPN extended community\n"); + +DEFUN (set_ecommunity_cost_igp, + set_ecommunity_cost_igp_cmd, + "set extcommunity cost igp <0-255> <0-4294967295>", + SET_STR + "BGP extended community attribute\n" + "Cost extended community\n" + "Compare following IGP cost comparison\n" + "Community ID\n" + "Cost Value\n" + "VPN extended community\n") +{ + int ret; + char *str; + + str = argv_concat (argv, argc, 0); + ret = bgp_route_set_add (vty, vty->index, "extcommunity cost igp", str); + XFREE (MTYPE_TMP, str); + + return ret; +} + +DEFUN (no_set_ecommunity_cost_igp, + no_set_ecommunity_cost_igp_cmd, + "no set extcommunity cost igp", + NO_STR + SET_STR + "BGP extended community attribute\n" + "Cost extended community\n" + "Compare following IGP cost comparison\n") +{ + return bgp_route_set_delete (vty, vty->index, "extcommunity cost igp", NULL); +} + +ALIAS (no_set_ecommunity_cost_igp, + no_set_ecommunity_cost_igp_val_cmd, + "no set extcommunity cost igp <0-255> <0-4294967295>", + NO_STR + SET_STR + "BGP extended community attribute\n" + "Cost extended community\n" + "Compare following IGP cost comparison\n" + "Community ID\n" + "Cost Value\n" + "VPN extended community\n") + +DEFUN (set_origin, + set_origin_cmd, + "set origin (egp|igp|incomplete)", + SET_STR + "BGP origin code\n" + "remote EGP\n" + "local IGP\n" + "unknown heritage\n") +{ + if (strncmp (argv[0], "igp", 2) == 0) + return bgp_route_set_add (vty, vty->index, "origin", "igp"); + if (strncmp (argv[0], "egp", 1) == 0) + return bgp_route_set_add (vty, vty->index, "origin", "egp"); + if (strncmp (argv[0], "incomplete", 2) == 0) + return bgp_route_set_add (vty, vty->index, "origin", "incomplete"); + + return CMD_WARNING; +} + +DEFUN (no_set_origin, + no_set_origin_cmd, + "no set origin", + NO_STR + SET_STR + "BGP origin code\n") +{ + return bgp_route_set_delete (vty, vty->index, "origin", NULL); +} + +ALIAS (no_set_origin, + no_set_origin_val_cmd, + "no set origin (egp|igp|incomplete)", + NO_STR + SET_STR + "BGP origin code\n" + "remote EGP\n" + "local IGP\n" + "unknown heritage\n"); + +DEFUN (set_atomic_aggregate, + set_atomic_aggregate_cmd, + "set atomic-aggregate", + SET_STR + "BGP atomic aggregate attribute\n" ) +{ + return bgp_route_set_add (vty, vty->index, "atomic-aggregate", NULL); +} + +DEFUN (no_set_atomic_aggregate, + no_set_atomic_aggregate_cmd, + "no set atomic-aggregate", + NO_STR + SET_STR + "BGP atomic aggregate attribute\n" ) +{ + return bgp_route_set_delete (vty, vty->index, "atomic-aggregate", NULL); +} + +DEFUN (set_aggregator_as, + set_aggregator_as_cmd, + "set aggregator as <1-65535> A.B.C.D", + SET_STR + "BGP aggregator attribute\n" + "AS number of aggregator\n" + "AS number\n" + "IP address of aggregator\n") +{ + int ret; + as_t as; + struct in_addr address; + char *endptr = NULL; + char *argstr; + + as = strtoul (argv[0], &endptr, 10); + if (as == 0 || as == ULONG_MAX || *endptr != '\0') + { + vty_out (vty, "AS path value malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = inet_aton (argv[1], &address); + if (ret == 0) + { + vty_out (vty, "Aggregator IP address is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, + strlen (argv[0]) + strlen (argv[1]) + 2); + + sprintf (argstr, "%s %s", argv[0], argv[1]); + + ret = bgp_route_set_add (vty, vty->index, "aggregator as", argstr); + + XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr); + + return ret; +} + +DEFUN (no_set_aggregator_as, + no_set_aggregator_as_cmd, + "no set aggregator as", + NO_STR + SET_STR + "BGP aggregator attribute\n" + "AS number of aggregator\n") +{ + int ret; + as_t as; + struct in_addr address; + char *endptr = NULL; + char *argstr; + + if (argv == 0) + return bgp_route_set_delete (vty, vty->index, "aggregator as", NULL); + + as = strtoul (argv[0], &endptr, 10); + if (as == 0 || as == ULONG_MAX || *endptr != '\0') + { + vty_out (vty, "AS path value malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = inet_aton (argv[1], &address); + if (ret == 0) + { + vty_out (vty, "Aggregator IP address is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, + strlen (argv[0]) + strlen (argv[1]) + 2); + + sprintf (argstr, "%s %s", argv[0], argv[1]); + + ret = bgp_route_set_delete (vty, vty->index, "aggregator as", argstr); + + XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr); + + return ret; +} + +ALIAS (no_set_aggregator_as, + no_set_aggregator_as_val_cmd, + "no set aggregator as <1-65535> A.B.C.D", + NO_STR + SET_STR + "BGP aggregator attribute\n" + "AS number of aggregator\n" + "AS number\n" + "IP address of aggregator\n"); + + +#ifdef HAVE_IPV6 +DEFUN (match_ipv6_address, + match_ipv6_address_cmd, + "match ipv6 address WORD", + MATCH_STR + IPV6_STR + "Match IPv6 address of route\n" + "IPv6 access-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "ipv6 address", argv[0]); +} + +DEFUN (no_match_ipv6_address, + no_match_ipv6_address_cmd, + "no match ipv6 address WORD", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 address of route\n" + "IPv6 access-list name\n") +{ + return bgp_route_match_delete (vty, vty->index, "ipv6 address", argv[0]); +} + +DEFUN (match_ipv6_next_hop, + match_ipv6_next_hop_cmd, + "match ipv6 next-hop X:X::X:X", + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "IPv6 address of next hop\n") +{ + return bgp_route_match_add (vty, vty->index, "ipv6 next-hop", argv[0]); +} + +DEFUN (no_match_ipv6_next_hop, + no_match_ipv6_next_hop_cmd, + "no match ipv6 next-hop X:X::X:X", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "IPv6 address of next hop\n") +{ + return bgp_route_match_delete (vty, vty->index, "ipv6 next-hop", argv[0]); +} + +DEFUN (match_ipv6_address_prefix_list, + match_ipv6_address_prefix_list_cmd, + "match ipv6 address prefix-list WORD", + MATCH_STR + IPV6_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return bgp_route_match_add (vty, vty->index, "ipv6 address prefix-list", argv[0]); +} + +DEFUN (no_match_ipv6_address_prefix_list, + no_match_ipv6_address_prefix_list_cmd, + "no match ipv6 address prefix-list WORD", + NO_STR + MATCH_STR + IPV6_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return bgp_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]); +} + +DEFUN (set_ipv6_nexthop_global, + set_ipv6_nexthop_global_cmd, + "set ipv6 next-hop global X:X::X:X", + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 global address\n" + "IPv6 address of next hop\n") +{ + return bgp_route_set_add (vty, vty->index, "ipv6 next-hop global", argv[0]); +} + +DEFUN (no_set_ipv6_nexthop_global, + no_set_ipv6_nexthop_global_cmd, + "no set ipv6 next-hop global", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 global address\n") +{ + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", NULL); + + return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", argv[0]); +} + +ALIAS (no_set_ipv6_nexthop_global, + no_set_ipv6_nexthop_global_val_cmd, + "no set ipv6 next-hop global X:X::X:X", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 global address\n" + "IPv6 address of next hop\n"); + +DEFUN (set_ipv6_nexthop_local, + set_ipv6_nexthop_local_cmd, + "set ipv6 next-hop local X:X::X:X", + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 local address\n" + "IPv6 address of next hop\n") +{ + return bgp_route_set_add (vty, vty->index, "ipv6 next-hop local", argv[0]); +} + +DEFUN (no_set_ipv6_nexthop_local, + no_set_ipv6_nexthop_local_cmd, + "no set ipv6 next-hop local", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 local address\n") +{ + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", NULL); + + return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", argv[0]); +} + +ALIAS (no_set_ipv6_nexthop_local, + no_set_ipv6_nexthop_local_val_cmd, + "no set ipv6 next-hop local X:X::X:X", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 local address\n" + "IPv6 address of next hop\n"); +#endif /* HAVE_IPV6 */ + +DEFUN (set_vpnv4_nexthop, + set_vpnv4_nexthop_cmd, + "set vpnv4 next-hop A.B.C.D", + SET_STR + "VPNv4 information\n" + "VPNv4 next-hop address\n" + "IP address of next hop\n") +{ + return bgp_route_set_add (vty, vty->index, "vpnv4 next-hop", argv[0]); +} + +DEFUN (no_set_vpnv4_nexthop, + no_set_vpnv4_nexthop_cmd, + "no set vpnv4 next-hop", + NO_STR + SET_STR + "VPNv4 information\n" + "VPNv4 next-hop address\n") +{ + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", NULL); + + return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", argv[0]); +} + +ALIAS (no_set_vpnv4_nexthop, + no_set_vpnv4_nexthop_val_cmd, + "no set vpnv4 next-hop A.B.C.D", + NO_STR + SET_STR + "VPNv4 information\n" + "VPNv4 next-hop address\n" + "IP address of next hop\n"); + +DEFUN (set_originator_id, + set_originator_id_cmd, + "set originator-id A.B.C.D", + SET_STR + "BGP originator ID attribute\n" + "IP address of originator\n") +{ + return bgp_route_set_add (vty, vty->index, "originator-id", argv[0]); +} + +DEFUN (no_set_originator_id, + no_set_originator_id_cmd, + "no set originator-id", + NO_STR + SET_STR + "BGP originator ID attribute\n") +{ + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "originator-id", NULL); + + return bgp_route_set_delete (vty, vty->index, "originator-id", argv[0]); +} + +ALIAS (no_set_originator_id, + no_set_originator_id_val_cmd, + "no set originator-id A.B.C.D", + NO_STR + SET_STR + "BGP originator ID attribute\n" + "IP address of originator\n"); + + +/* Initialization of route map. */ +void +bgp_route_map_init () +{ + route_map_init (); + route_map_init_vty (); + route_map_add_hook (bgp_route_map_update); + route_map_delete_hook (bgp_route_map_update); + + route_map_install_match (&route_match_ip_address_cmd); + route_map_install_match (&route_match_ip_next_hop_cmd); + route_map_install_match (&route_match_ip_route_source_cmd); + route_map_install_match (&route_match_ip_address_prefix_list_cmd); + route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); + route_map_install_match (&route_match_ip_route_source_prefix_list_cmd); + route_map_install_match (&route_match_aspath_cmd); + route_map_install_match (&route_match_community_cmd); + route_map_install_match (&route_match_ecommunity_cmd); + route_map_install_match (&route_match_metric_cmd); + route_map_install_match (&route_match_origin_cmd); + + route_map_install_set (&route_set_ip_nexthop_cmd); + route_map_install_set (&route_set_local_pref_cmd); + route_map_install_set (&route_set_weight_cmd); + route_map_install_set (&route_set_metric_cmd); + route_map_install_set (&route_set_aspath_prepend_cmd); + route_map_install_set (&route_set_origin_cmd); + route_map_install_set (&route_set_atomic_aggregate_cmd); + route_map_install_set (&route_set_aggregator_as_cmd); + route_map_install_set (&route_set_community_cmd); + route_map_install_set (&route_set_community_delete_cmd); + route_map_install_set (&route_set_vpnv4_nexthop_cmd); + route_map_install_set (&route_set_originator_id_cmd); + route_map_install_set (&route_set_ecommunity_rt_cmd); + route_map_install_set (&route_set_ecommunity_soo_cmd); + route_map_install_set (&route_set_ecommunity_cost_igp_cmd); + + install_element (RMAP_NODE, &match_ip_address_cmd); + install_element (RMAP_NODE, &no_match_ip_address_cmd); + install_element (RMAP_NODE, &no_match_ip_address_val_cmd); + install_element (RMAP_NODE, &match_ip_next_hop_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd); + install_element (RMAP_NODE, &match_ip_route_source_cmd); + install_element (RMAP_NODE, &no_match_ip_route_source_cmd); + install_element (RMAP_NODE, &no_match_ip_route_source_val_cmd); + + install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); + install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd); + install_element (RMAP_NODE, &match_ip_route_source_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_route_source_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_route_source_prefix_list_val_cmd); + + install_element (RMAP_NODE, &match_aspath_cmd); + install_element (RMAP_NODE, &no_match_aspath_cmd); + install_element (RMAP_NODE, &no_match_aspath_val_cmd); + install_element (RMAP_NODE, &match_metric_cmd); + install_element (RMAP_NODE, &no_match_metric_cmd); + install_element (RMAP_NODE, &no_match_metric_val_cmd); + install_element (RMAP_NODE, &match_community_cmd); + install_element (RMAP_NODE, &match_community_exact_cmd); + install_element (RMAP_NODE, &no_match_community_cmd); + install_element (RMAP_NODE, &no_match_community_val_cmd); + install_element (RMAP_NODE, &no_match_community_exact_cmd); + install_element (RMAP_NODE, &match_ecommunity_cmd); + install_element (RMAP_NODE, &no_match_ecommunity_cmd); + install_element (RMAP_NODE, &no_match_ecommunity_val_cmd); + install_element (RMAP_NODE, &match_origin_cmd); + install_element (RMAP_NODE, &no_match_origin_cmd); + install_element (RMAP_NODE, &no_match_origin_val_cmd); + + install_element (RMAP_NODE, &set_ip_nexthop_cmd); + install_element (RMAP_NODE, &set_ip_nexthop_bgp_cmd); + install_element (RMAP_NODE, &no_set_ip_nexthop_cmd); + install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd); + install_element (RMAP_NODE, &no_set_ip_nexthop_val_bgp_cmd); + install_element (RMAP_NODE, &set_local_pref_cmd); + install_element (RMAP_NODE, &no_set_local_pref_cmd); + install_element (RMAP_NODE, &no_set_local_pref_val_cmd); + install_element (RMAP_NODE, &set_weight_cmd); + install_element (RMAP_NODE, &no_set_weight_cmd); + install_element (RMAP_NODE, &no_set_weight_val_cmd); + install_element (RMAP_NODE, &set_metric_cmd); + install_element (RMAP_NODE, &set_metric_addsub_cmd); + install_element (RMAP_NODE, &no_set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_val_cmd); + install_element (RMAP_NODE, &set_aspath_prepend_cmd); + install_element (RMAP_NODE, &no_set_aspath_prepend_cmd); + install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd); + install_element (RMAP_NODE, &set_origin_cmd); + install_element (RMAP_NODE, &no_set_origin_cmd); + install_element (RMAP_NODE, &no_set_origin_val_cmd); + install_element (RMAP_NODE, &set_atomic_aggregate_cmd); + install_element (RMAP_NODE, &no_set_atomic_aggregate_cmd); + install_element (RMAP_NODE, &set_aggregator_as_cmd); + install_element (RMAP_NODE, &no_set_aggregator_as_cmd); + install_element (RMAP_NODE, &no_set_aggregator_as_val_cmd); + install_element (RMAP_NODE, &set_community_cmd); + install_element (RMAP_NODE, &set_community_none_cmd); + install_element (RMAP_NODE, &no_set_community_cmd); + install_element (RMAP_NODE, &no_set_community_val_cmd); + install_element (RMAP_NODE, &no_set_community_none_cmd); + install_element (RMAP_NODE, &set_community_delete_cmd); + install_element (RMAP_NODE, &no_set_community_delete_cmd); + install_element (RMAP_NODE, &no_set_community_delete_val_cmd); + install_element (RMAP_NODE, &set_ecommunity_rt_cmd); + install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd); + install_element (RMAP_NODE, &no_set_ecommunity_rt_val_cmd); + install_element (RMAP_NODE, &set_ecommunity_soo_cmd); + install_element (RMAP_NODE, &no_set_ecommunity_soo_cmd); + install_element (RMAP_NODE, &no_set_ecommunity_soo_val_cmd); + install_element (RMAP_NODE, &set_ecommunity_cost_igp_cmd); + install_element (RMAP_NODE, &no_set_ecommunity_cost_igp_cmd); + install_element (RMAP_NODE, &no_set_ecommunity_cost_igp_val_cmd); + install_element (RMAP_NODE, &set_vpnv4_nexthop_cmd); + install_element (RMAP_NODE, &no_set_vpnv4_nexthop_cmd); + install_element (RMAP_NODE, &no_set_vpnv4_nexthop_val_cmd); + install_element (RMAP_NODE, &set_originator_id_cmd); + install_element (RMAP_NODE, &no_set_originator_id_cmd); + install_element (RMAP_NODE, &no_set_originator_id_val_cmd); + +#ifdef HAVE_IPV6 + route_map_install_match (&route_match_ipv6_address_cmd); + route_map_install_match (&route_match_ipv6_next_hop_cmd); + route_map_install_match (&route_match_ipv6_address_prefix_list_cmd); + route_map_install_set (&route_set_ipv6_nexthop_global_cmd); + route_map_install_set (&route_set_ipv6_nexthop_local_cmd); + + install_element (RMAP_NODE, &match_ipv6_address_cmd); + install_element (RMAP_NODE, &no_match_ipv6_address_cmd); + install_element (RMAP_NODE, &match_ipv6_next_hop_cmd); + install_element (RMAP_NODE, &no_match_ipv6_next_hop_cmd); + install_element (RMAP_NODE, &match_ipv6_address_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd); + install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd); + install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd); + install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd); + install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd); + install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd); + install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd); +#endif /* HAVE_IPV6 */ +} diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c new file mode 100644 index 0000000..7907333 --- /dev/null +++ b/bgpd/bgp_snmp.c @@ -0,0 +1,878 @@ +/* BGP4 SNMP support + Copyright (C) 1999, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#ifdef HAVE_SNMP + +#ifdef HAVE_NETSNMP +#include +#endif /* HAVE_NETSNMP */ + +#include +#include +#include + +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "command.h" +#include "thread.h" +#include "smux.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_fsm.h" + +/* BGP4-MIB described in RFC1657. */ +#define BGP4MIB 1,3,6,1,2,1,15 + +/* BGP TRAP. */ +#define BGPESTABLISHED 1 +#define BGPBACKWARDTRANSITION 2 + +/* Zebra enterprise BGP MIB. This variable is used for register + OSPF MIB to SNMP agent under SMUX protocol. */ +#define BGPDMIB 1,3,6,1,4,1,3317,1,2,2 + +/* BGP MIB bgpVersion. */ +#define BGPVERSION 0 + +/* BGP MIB bgpLocalAs. */ +#define BGPLOCALAS 0 + +/* BGP MIB bgpPeerTable. */ +#define BGPPEERIDENTIFIER 1 +#define BGPPEERSTATE 2 +#define BGPPEERADMINSTATUS 3 +#define BGPPEERNEGOTIATEDVERSION 4 +#define BGPPEERLOCALADDR 5 +#define BGPPEERLOCALPORT 6 +#define BGPPEERREMOTEADDR 7 +#define BGPPEERREMOTEPORT 8 +#define BGPPEERREMOTEAS 9 +#define BGPPEERINUPDATES 10 +#define BGPPEEROUTUPDATES 11 +#define BGPPEERINTOTALMESSAGES 12 +#define BGPPEEROUTTOTALMESSAGES 13 +#define BGPPEERLASTERROR 14 +#define BGPPEERFSMESTABLISHEDTRANSITIONS 15 +#define BGPPEERFSMESTABLISHEDTIME 16 +#define BGPPEERCONNECTRETRYINTERVAL 17 +#define BGPPEERHOLDTIME 18 +#define BGPPEERKEEPALIVE 19 +#define BGPPEERHOLDTIMECONFIGURED 20 +#define BGPPEERKEEPALIVECONFIGURED 21 +#define BGPPEERMINASORIGINATIONINTERVAL 22 +#define BGPPEERMINROUTEADVERTISEMENTINTERVAL 23 +#define BGPPEERINUPDATEELAPSEDTIME 24 + +/* BGP MIB bgpIdentifier. */ +#define BGPIDENTIFIER 0 + +/* BGP MIB bgpRcvdPathAttrTable */ +#define BGPPATHATTRPEER 1 +#define BGPPATHATTRDESTNETWORK 2 +#define BGPPATHATTRORIGIN 3 +#define BGPPATHATTRASPATH 4 +#define BGPPATHATTRNEXTHOP 5 +#define BGPPATHATTRINTERASMETRIC 6 + +/* BGP MIB bgp4PathAttrTable. */ +#define BGP4PATHATTRPEER 1 +#define BGP4PATHATTRIPADDRPREFIXLEN 2 +#define BGP4PATHATTRIPADDRPREFIX 3 +#define BGP4PATHATTRORIGIN 4 +#define BGP4PATHATTRASPATHSEGMENT 5 +#define BGP4PATHATTRNEXTHOP 6 +#define BGP4PATHATTRMULTIEXITDISC 7 +#define BGP4PATHATTRLOCALPREF 8 +#define BGP4PATHATTRATOMICAGGREGATE 9 +#define BGP4PATHATTRAGGREGATORAS 10 +#define BGP4PATHATTRAGGREGATORADDR 11 +#define BGP4PATHATTRCALCLOCALPREF 12 +#define BGP4PATHATTRBEST 13 +#define BGP4PATHATTRUNKNOWN 14 + +/* SNMP value hack. */ +#define INTEGER ASN_INTEGER +#define INTEGER32 ASN_INTEGER +#define COUNTER32 ASN_COUNTER +#define OCTET_STRING ASN_OCTET_STR +#define IPADDRESS ASN_IPADDRESS +#define GAUGE32 ASN_UNSIGNED + +/* Declare static local variables for convenience. */ +SNMP_LOCAL_VARIABLES + +/* BGP-MIB instances. */ +oid bgp_oid [] = { BGP4MIB }; +oid bgpd_oid [] = { BGPDMIB }; + +/* IP address 0.0.0.0. */ +static struct in_addr bgp_empty_addr = {0}; + +/* Hook functions. */ +static u_char *bgpVersion (); +static u_char *bgpLocalAs (); +static u_char *bgpPeerTable (); +static u_char *bgpRcvdPathAttrTable (); +static u_char *bgpIdentifier (); +static u_char *bgp4PathAttrTable (); +/* static u_char *bgpTraps (); */ + +struct variable bgp_variables[] = +{ + /* BGP version. */ + {BGPVERSION, OCTET_STRING, RONLY, bgpVersion, + 1, {1}}, + /* BGP local AS. */ + {BGPLOCALAS, INTEGER, RONLY, bgpLocalAs, + 1, {2}}, + /* BGP peer table. */ + {BGPPEERIDENTIFIER, IPADDRESS, RONLY, bgpPeerTable, + 3, {3, 1, 1}}, + {BGPPEERSTATE, INTEGER, RONLY, bgpPeerTable, + 3, {3, 1, 2}}, + {BGPPEERADMINSTATUS, INTEGER, RWRITE, bgpPeerTable, + 3, {3, 1, 3}}, + {BGPPEERNEGOTIATEDVERSION, INTEGER32, RONLY, bgpPeerTable, + 3, {3, 1, 4}}, + {BGPPEERLOCALADDR, IPADDRESS, RONLY, bgpPeerTable, + 3, {3, 1, 5}}, + {BGPPEERLOCALPORT, INTEGER, RONLY, bgpPeerTable, + 3, {3, 1, 6}}, + {BGPPEERREMOTEADDR, IPADDRESS, RONLY, bgpPeerTable, + 3, {3, 1, 7}}, + {BGPPEERREMOTEPORT, INTEGER, RONLY, bgpPeerTable, + 3, {3, 1, 8}}, + {BGPPEERREMOTEAS, INTEGER, RONLY, bgpPeerTable, + 3, {3, 1, 9}}, + {BGPPEERINUPDATES, COUNTER32, RONLY, bgpPeerTable, + 3, {3, 1, 10}}, + {BGPPEEROUTUPDATES, COUNTER32, RONLY, bgpPeerTable, + 3, {3, 1, 11}}, + {BGPPEERINTOTALMESSAGES, COUNTER32, RONLY, bgpPeerTable, + 3, {3, 1, 12}}, + {BGPPEEROUTTOTALMESSAGES, COUNTER32, RONLY, bgpPeerTable, + 3, {3, 1, 13}}, + {BGPPEERLASTERROR, OCTET_STRING, RONLY, bgpPeerTable, + 3, {3, 1, 14}}, + {BGPPEERFSMESTABLISHEDTRANSITIONS, COUNTER32, RONLY, bgpPeerTable, + 3, {3, 1, 15}}, + {BGPPEERFSMESTABLISHEDTIME, GAUGE32, RONLY, bgpPeerTable, + 3, {3, 1, 16}}, + {BGPPEERCONNECTRETRYINTERVAL, INTEGER, RWRITE, bgpPeerTable, + 3, {3, 1, 17}}, + {BGPPEERHOLDTIME, INTEGER, RONLY, bgpPeerTable, + 3, {3, 1, 18}}, + {BGPPEERKEEPALIVE, INTEGER, RONLY, bgpPeerTable, + 3, {3, 1, 19}}, + {BGPPEERHOLDTIMECONFIGURED, INTEGER, RWRITE, bgpPeerTable, + 3, {3, 1, 20}}, + {BGPPEERKEEPALIVECONFIGURED, INTEGER, RWRITE, bgpPeerTable, + 3, {3, 1, 21}}, + {BGPPEERMINASORIGINATIONINTERVAL, INTEGER, RWRITE, bgpPeerTable, + 3, {3, 1, 22}}, + {BGPPEERMINROUTEADVERTISEMENTINTERVAL, INTEGER, RWRITE, bgpPeerTable, + 3, {3, 1, 23}}, + {BGPPEERINUPDATEELAPSEDTIME, GAUGE32, RONLY, bgpPeerTable, + 3, {3, 1, 24}}, + /* BGP identifier. */ + {BGPIDENTIFIER, IPADDRESS, RONLY, bgpIdentifier, + 1, {4}}, + /* BGP received path attribute table. */ + {BGPPATHATTRPEER, IPADDRESS, RONLY, bgpRcvdPathAttrTable, + 3, {5, 1, 1}}, + {BGPPATHATTRDESTNETWORK, IPADDRESS, RONLY, bgpRcvdPathAttrTable, + 3, {5, 1, 2}}, + {BGPPATHATTRORIGIN, INTEGER, RONLY, bgpRcvdPathAttrTable, + 3, {5, 1, 3}}, + {BGPPATHATTRASPATH, OCTET_STRING, RONLY, bgpRcvdPathAttrTable, + 3, {5, 1, 4}}, + {BGPPATHATTRNEXTHOP, IPADDRESS, RONLY, bgpRcvdPathAttrTable, + 3, {5, 1, 5}}, + {BGPPATHATTRINTERASMETRIC, INTEGER32, RONLY, bgpRcvdPathAttrTable, + 3, {5, 1, 6}}, + /* BGP-4 received path attribute table. */ + {BGP4PATHATTRPEER, IPADDRESS, RONLY, bgp4PathAttrTable, + 3, {6, 1, 1}}, + {BGP4PATHATTRIPADDRPREFIXLEN, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 2}}, + {BGP4PATHATTRIPADDRPREFIX, IPADDRESS, RONLY, bgp4PathAttrTable, + 3, {6, 1, 3}}, + {BGP4PATHATTRORIGIN, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 4}}, + {BGP4PATHATTRASPATHSEGMENT, OCTET_STRING, RONLY, bgp4PathAttrTable, + 3, {6, 1, 5}}, + {BGP4PATHATTRNEXTHOP, IPADDRESS, RONLY, bgp4PathAttrTable, + 3, {6, 1, 6}}, + {BGP4PATHATTRMULTIEXITDISC, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 7}}, + {BGP4PATHATTRLOCALPREF, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 8}}, + {BGP4PATHATTRATOMICAGGREGATE, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 9}}, + {BGP4PATHATTRAGGREGATORAS, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 10}}, + {BGP4PATHATTRAGGREGATORADDR, IPADDRESS, RONLY, bgp4PathAttrTable, + 3, {6, 1, 11}}, + {BGP4PATHATTRCALCLOCALPREF, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 12}}, + {BGP4PATHATTRBEST, INTEGER, RONLY, bgp4PathAttrTable, + 3, {6, 1, 13}}, + {BGP4PATHATTRUNKNOWN, OCTET_STRING, RONLY, bgp4PathAttrTable, + 3, {6, 1, 14}}, +}; + +static u_char * +bgpVersion (struct variable *v, oid name[], size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + static u_char version; + + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Retrun BGP version. Zebra bgpd only support version 4. */ + version = (0x80 >> (BGP_VERSION_4 - 1)); + + /* Return octet string length 1. */ + *var_len = 1; + return (u_char *)&version; +} + +static u_char * +bgpLocalAs (struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + struct bgp *bgp; + + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Get BGP structure. */ + bgp = bgp_get_default (); + if (! bgp) + return NULL; + + return SNMP_INTEGER (bgp->as); +} + +struct peer * +peer_lookup_addr_ipv4 (struct in_addr *src) +{ + struct bgp *bgp; + struct peer *peer; + struct listnode *nn; + struct in_addr addr; + int ret; + + bgp = bgp_get_default (); + if (! bgp) + return NULL; + + LIST_LOOP (bgp->peer, peer, nn) + { + ret = inet_pton (AF_INET, peer->host, &addr); + if (ret > 0) + { + if (IPV4_ADDR_SAME (&addr, src)) + return peer; + } + } + return NULL; +} + +struct peer * +bgp_peer_lookup_next (struct in_addr *src) +{ + struct bgp *bgp; + struct peer *peer; + struct listnode *nn; + struct in_addr *p; + union sockunion su; + int ret; + + memset (&su, 0, sizeof (union sockunion)); + + bgp = bgp_get_default (); + if (! bgp) + return NULL; + + LIST_LOOP (bgp->peer, peer, nn) + { + ret = inet_pton (AF_INET, peer->host, &su.sin.sin_addr); + if (ret > 0) + { + p = &su.sin.sin_addr; + + if (ntohl (p->s_addr) > ntohl (src->s_addr)) + { + src->s_addr = p->s_addr; + return peer; + } + } + } + return NULL; +} + +struct peer * +bgpPeerTable_lookup (struct variable *v, oid name[], size_t *length, + struct in_addr *addr, int exact) +{ + struct peer *peer = NULL; + int len; + + if (exact) + { + /* Check the length. */ + if (*length - v->namelen != sizeof (struct in_addr)) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, addr); + + peer = peer_lookup_addr_ipv4 (addr); + return peer; + } + else + { + len = *length - v->namelen; + if (len > 4) len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + peer = bgp_peer_lookup_next (addr); + + if (peer == NULL) + return NULL; + + oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); + *length = sizeof (struct in_addr) + v->namelen; + + return peer; + } + return NULL; +} + +/* BGP write methods. */ +int +write_bgpPeerTable (int action, u_char *var_val, + u_char var_val_type, size_t var_val_len, + u_char *statP, oid *name, size_t length, + struct variable *v) +{ + struct in_addr addr; + struct peer *peer; + long intval; + int bigsize = SNMP_MAX_LEN; + + if (var_val_type != ASN_INTEGER) + { + return SNMP_ERR_WRONGTYPE; + } + if (var_val_len != sizeof (long)) + { + return SNMP_ERR_WRONGLENGTH; + } + + if (! asn_parse_int(var_val, &bigsize, &var_val_type, + &intval, sizeof(long))) + { + return SNMP_ERR_WRONGENCODING; + } + + memset (&addr, 0, sizeof (struct in_addr)); + + peer = bgpPeerTable_lookup (v, name, &length, &addr, 1); + if (! peer) + return SNMP_ERR_NOSUCHNAME; + + printf ("val: %ld\n", intval); + + switch (v->magic) + { + case BGPPEERADMINSTATUS: +#define BGP_PeerAdmin_stop 1 +#define BGP_PeerAdmin_start 2 + /* When the peer is established, */ + if (intval == BGP_PeerAdmin_stop) + BGP_EVENT_ADD (peer, BGP_Stop); + else if (intval == BGP_PeerAdmin_start) + ; /* Do nothing. */ + else + return SNMP_ERR_NOSUCHNAME; + break; + case BGPPEERHOLDTIMECONFIGURED: + SET_FLAG (peer->config, PEER_CONFIG_TIMER); + peer->holdtime = intval; + peer->v_holdtime = intval; + break; + case BGPPEERKEEPALIVECONFIGURED: + SET_FLAG (peer->config, PEER_CONFIG_TIMER); + peer->keepalive = intval; + peer->v_keepalive = intval; + break; + case BGPPEERMINASORIGINATIONINTERVAL: + peer->v_asorig = intval; + break; + case BGPPEERMINROUTEADVERTISEMENTINTERVAL: + peer->v_routeadv = intval; + break; + } + return SNMP_ERR_NOERROR; +} + +u_char * +bgpPeerTable (struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + static struct in_addr addr; + struct peer *peer; + + *write_method = NULL; + memset (&addr, 0, sizeof (struct in_addr)); + + peer = bgpPeerTable_lookup (v, name, length, &addr, exact); + if (! peer) + return NULL; + + switch (v->magic) + { + case BGPPEERIDENTIFIER: + return SNMP_IPADDRESS (peer->remote_id); + break; + case BGPPEERSTATE: + return SNMP_INTEGER (peer->status); + break; + case BGPPEERADMINSTATUS: + *write_method = write_bgpPeerTable; +#define BGP_PeerAdmin_stop 1 +#define BGP_PeerAdmin_start 2 + if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) + return SNMP_INTEGER (BGP_PeerAdmin_stop); + else + return SNMP_INTEGER (BGP_PeerAdmin_start); + break; + case BGPPEERNEGOTIATEDVERSION: + return SNMP_INTEGER (BGP_VERSION_4); + break; + case BGPPEERLOCALADDR: + if (peer->su_local) + return SNMP_IPADDRESS (peer->su_local->sin.sin_addr); + else + return SNMP_IPADDRESS (bgp_empty_addr); + break; + case BGPPEERLOCALPORT: + if (peer->su_local) + return SNMP_INTEGER (ntohs (peer->su_local->sin.sin_port)); + else + return SNMP_INTEGER (0); + break; + case BGPPEERREMOTEADDR: + if (peer->su_remote) + return SNMP_IPADDRESS (peer->su_remote->sin.sin_addr); + else + return SNMP_IPADDRESS (bgp_empty_addr); + break; + case BGPPEERREMOTEPORT: + if (peer->su_remote) + return SNMP_INTEGER (ntohs (peer->su_remote->sin.sin_port)); + else + return SNMP_INTEGER (0); + break; + case BGPPEERREMOTEAS: + return SNMP_INTEGER (peer->as); + break; + case BGPPEERINUPDATES: + return SNMP_INTEGER (peer->update_in); + break; + case BGPPEEROUTUPDATES: + return SNMP_INTEGER (peer->update_out); + break; + case BGPPEERINTOTALMESSAGES: + return SNMP_INTEGER (peer->open_in + peer->update_in + + peer->keepalive_in + peer->notify_in + + peer->refresh_in + peer->dynamic_cap_in); + break; + case BGPPEEROUTTOTALMESSAGES: + return SNMP_INTEGER (peer->open_out + peer->update_out + + peer->keepalive_out + peer->notify_out + + peer->refresh_out + peer->dynamic_cap_out); + break; + case BGPPEERLASTERROR: + { + static u_char lasterror[2]; + lasterror[0] = peer->notify.code; + lasterror[1] = peer->notify.subcode; + *var_len = 2; + return (u_char *)&lasterror; + } + break; + case BGPPEERFSMESTABLISHEDTRANSITIONS: + return SNMP_INTEGER (peer->established); + break; + case BGPPEERFSMESTABLISHEDTIME: + if (peer->uptime == 0) + return SNMP_INTEGER (0); + else + return SNMP_INTEGER (time (NULL) - peer->uptime); + break; + case BGPPEERCONNECTRETRYINTERVAL: + *write_method = write_bgpPeerTable; + return SNMP_INTEGER (peer->v_connect); + break; + case BGPPEERHOLDTIME: + return SNMP_INTEGER (peer->v_holdtime); + break; + case BGPPEERKEEPALIVE: + return SNMP_INTEGER (peer->v_keepalive); + break; + case BGPPEERHOLDTIMECONFIGURED: + *write_method = write_bgpPeerTable; + if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) + return SNMP_INTEGER (peer->holdtime); + else + return SNMP_INTEGER (peer->v_holdtime); + break; + case BGPPEERKEEPALIVECONFIGURED: + *write_method = write_bgpPeerTable; + if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) + return SNMP_INTEGER (peer->keepalive); + else + return SNMP_INTEGER (peer->v_keepalive); + break; + case BGPPEERMINASORIGINATIONINTERVAL: + *write_method = write_bgpPeerTable; + return SNMP_INTEGER (peer->v_asorig); + break; + case BGPPEERMINROUTEADVERTISEMENTINTERVAL: + *write_method = write_bgpPeerTable; + return SNMP_INTEGER (peer->v_routeadv); + break; + case BGPPEERINUPDATEELAPSEDTIME: + if (peer->update_time == 0) + return SNMP_INTEGER (0); + else + return SNMP_INTEGER (time (NULL) - peer->update_time); + break; + default: + return NULL; + break; + } + return NULL; +} + +u_char * +bgpIdentifier (struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + struct bgp *bgp; + + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + bgp = bgp_get_default (); + if (!bgp) + return NULL; + + return SNMP_IPADDRESS (bgp->router_id); +} + +u_char * +bgpRcvdPathAttrTable (struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + /* Received Path Attribute Table. This table contains, one entry + per path to a network, path attributes received from all peers + running BGP version 3 or less. This table is obsolete, having + been replaced in functionality with the bgp4PathAttrTable. */ + return NULL; +} + +struct bgp_info * +bgp4PathAttrLookup (struct variable *v, oid name[], size_t *length, + struct bgp *bgp, struct prefix_ipv4 *addr, int exact) +{ + oid *offset; + int offsetlen; + struct bgp_info *binfo; + struct bgp_info *min; + struct bgp_node *rn; + union sockunion su; + int len; + struct in_addr paddr; + +#define BGP_PATHATTR_ENTRY_OFFSET \ + (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE) + + if (exact) + { + if (*length - v->namelen != BGP_PATHATTR_ENTRY_OFFSET) + return NULL; + + /* Set OID offset for prefix. */ + offset = name + v->namelen; + oid2in_addr (offset, IN_ADDR_SIZE, &addr->prefix); + offset += IN_ADDR_SIZE; + + /* Prefix length. */ + addr->prefixlen = *offset; + offset++; + + /* Peer address. */ + su.sin.sin_family = AF_INET; + oid2in_addr (offset, IN_ADDR_SIZE, &su.sin.sin_addr); + + /* Lookup node. */ + rn = bgp_node_lookup (bgp->rib[AFI_IP][SAFI_UNICAST], + (struct prefix *) addr); + if (rn) + { + bgp_unlock_node (rn); + + for (binfo = rn->info; binfo; binfo = binfo->next) + if (sockunion_same (&binfo->peer->su, &su)) + return binfo; + } + } + else + { + offset = name + v->namelen; + offsetlen = *length - v->namelen; + len = offsetlen; + + if (offsetlen == 0) + rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_UNICAST]); + else + { + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, &addr->prefix); + + offset += IN_ADDR_SIZE; + offsetlen -= IN_ADDR_SIZE; + + if (offsetlen > 0) + addr->prefixlen = *offset; + else + addr->prefixlen = len * 8; + + rn = bgp_node_get (bgp->rib[AFI_IP][SAFI_UNICAST], + (struct prefix *) addr); + + offset++; + offsetlen--; + } + + if (offsetlen > 0) + { + len = offsetlen; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, &paddr); + } + else + paddr.s_addr = 0; + + if (! rn) + return NULL; + + do + { + min = NULL; + + for (binfo = rn->info; binfo; binfo = binfo->next) + { + if (binfo->peer->su.sin.sin_family == AF_INET + && ntohl (paddr.s_addr) + < ntohl (binfo->peer->su.sin.sin_addr.s_addr)) + { + if (min) + { + if (ntohl (binfo->peer->su.sin.sin_addr.s_addr) + < ntohl (min->peer->su.sin.sin_addr.s_addr)) + min = binfo; + } + else + min = binfo; + } + } + + if (min) + { + *length = v->namelen + BGP_PATHATTR_ENTRY_OFFSET; + + offset = name + v->namelen; + oid_copy_addr (offset, &rn->p.u.prefix4, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + *offset = rn->p.prefixlen; + offset++; + oid_copy_addr (offset, &min->peer->su.sin.sin_addr, + IN_ADDR_SIZE); + addr->prefix = rn->p.u.prefix4; + addr->prefixlen = rn->p.prefixlen; + + bgp_unlock_node (rn); + + return min; + } + + paddr.s_addr = 0; + } + while ((rn = bgp_route_next (rn)) != NULL); + } + return NULL; +} + +u_char * +bgp4PathAttrTable (struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + struct bgp *bgp; + struct bgp_info *binfo; + struct prefix_ipv4 addr; + + bgp = bgp_get_default (); + if (! bgp) + return NULL; + + memset (&addr, 0, sizeof (struct prefix_ipv4)); + + binfo = bgp4PathAttrLookup (v, name, length, bgp, &addr, exact); + if (! binfo) + return NULL; + + switch (v->magic) + { + case BGP4PATHATTRPEER: /* 1 */ + return SNMP_IPADDRESS (binfo->peer->su.sin.sin_addr); + break; + case BGP4PATHATTRIPADDRPREFIXLEN: /* 2 */ + return SNMP_INTEGER (addr.prefixlen); + break; + case BGP4PATHATTRIPADDRPREFIX: /* 3 */ + return SNMP_IPADDRESS (addr.prefix); + break; + case BGP4PATHATTRORIGIN: /* 4 */ + return SNMP_INTEGER (binfo->attr->origin); + break; + case BGP4PATHATTRASPATHSEGMENT: /* 5 */ + *var_len = binfo->attr->aspath->length; + return (u_char *) binfo->attr->aspath->data; + break; + case BGP4PATHATTRNEXTHOP: /* 6 */ + return SNMP_IPADDRESS (binfo->attr->nexthop); + break; + case BGP4PATHATTRMULTIEXITDISC: /* 7 */ + return SNMP_INTEGER (binfo->attr->med); + break; + case BGP4PATHATTRLOCALPREF: /* 8 */ + return SNMP_INTEGER (binfo->attr->local_pref); + break; + case BGP4PATHATTRATOMICAGGREGATE: /* 9 */ + return SNMP_INTEGER (1); + break; + case BGP4PATHATTRAGGREGATORAS: /* 10 */ + return SNMP_INTEGER (binfo->attr->aggregator_as); + break; + case BGP4PATHATTRAGGREGATORADDR: /* 11 */ + return SNMP_IPADDRESS (binfo->attr->aggregator_addr); + break; + case BGP4PATHATTRCALCLOCALPREF: /* 12 */ + return SNMP_INTEGER (-1); + break; + case BGP4PATHATTRBEST: /* 13 */ +#define BGP4_PathAttrBest_false 1 +#define BGP4_PathAttrBest_true 2 + if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) + return SNMP_INTEGER (BGP4_PathAttrBest_true); + else + return SNMP_INTEGER (BGP4_PathAttrBest_false); + break; + case BGP4PATHATTRUNKNOWN: /* 14 */ + *var_len = 0; + return NULL; + break; + } + return NULL; +} + +/* BGP Traps. */ +struct trap_object bgpTrapList[] = +{ + {bgpPeerTable, 3, {3, 1, BGPPEERLASTERROR}}, + {bgpPeerTable, 3, {3, 1, BGPPEERSTATE}} +}; + +void +bgpTrapEstablished (struct peer *peer) +{ + int ret; + struct in_addr addr; + oid index[sizeof (oid) * IN_ADDR_SIZE]; + + ret = inet_aton (peer->host, &addr); + if (ret == 0) + return; + + oid_copy_addr (index, &addr, IN_ADDR_SIZE); + + smux_trap (bgp_oid, sizeof bgp_oid / sizeof (oid), + index, IN_ADDR_SIZE, + bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), + bm->start_time - time (NULL), BGPESTABLISHED); +} + +void +bgpTrapBackwardTransition (struct peer *peer) +{ + int ret; + struct in_addr addr; + oid index[sizeof (oid) * IN_ADDR_SIZE]; + + ret = inet_aton (peer->host, &addr); + if (ret == 0) + return; + + oid_copy_addr (index, &addr, IN_ADDR_SIZE); + + smux_trap (bgp_oid, sizeof bgp_oid / sizeof (oid), + index, IN_ADDR_SIZE, + bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), + bm->start_time - time (NULL), BGPBACKWARDTRANSITION); +} + +void +bgp_snmp_init () +{ + smux_init (bgpd_oid, sizeof bgpd_oid / sizeof (oid)); + REGISTER_MIB("mibII/bgp", bgp_variables, variable, bgp_oid); + smux_start (); +} +#endif /* HAVE_SNMP */ diff --git a/bgpd/bgp_snmp.h b/bgpd/bgp_snmp.h new file mode 100644 index 0000000..a8af032 --- /dev/null +++ b/bgpd/bgp_snmp.h @@ -0,0 +1,23 @@ +/* BGP4 SNMP support + Copyright (C) 1999, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +void bgp_snmp_init (); +void bgpTrapEstablished (struct peer *); +void bgpTrapBackwardTransition (struct peer *); diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c new file mode 100644 index 0000000..a2a3c97 --- /dev/null +++ b/bgpd/bgp_table.c @@ -0,0 +1,489 @@ +/* BGP routing table + Copyright (C) 1998, 2001 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "prefix.h" +#include "memory.h" +#include "sockunion.h" +#include "vty.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" + +void bgp_node_delete (struct bgp_node *); +void bgp_table_free (struct bgp_table *); + +struct bgp_table * +bgp_table_init (void) +{ + struct bgp_table *rt; + + rt = XMALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table)); + memset (rt, 0, sizeof (struct bgp_table)); + return rt; +} + +void +bgp_table_finish (struct bgp_table *rt) +{ + bgp_table_free (rt); +} + +struct bgp_node * +bgp_node_create () +{ + struct bgp_node *rn; + + rn = (struct bgp_node *) XMALLOC (MTYPE_BGP_NODE, sizeof (struct bgp_node)); + memset (rn, 0, sizeof (struct bgp_node)); + return rn; +} + +/* Allocate new route node with prefix set. */ +struct bgp_node * +bgp_node_set (struct bgp_table *table, struct prefix *prefix) +{ + struct bgp_node *node; + + node = bgp_node_create (); + + prefix_copy (&node->p, prefix); + node->table = table; + + return node; +} + +/* Free route node. */ +void +bgp_node_free (struct bgp_node *node) +{ + XFREE (MTYPE_BGP_NODE, node); +} + +/* Free route table. */ +void +bgp_table_free (struct bgp_table *rt) +{ + struct bgp_node *tmp_node; + struct bgp_node *node; + + if (rt == NULL) + return; + + node = rt->top; + + while (node) + { + if (node->l_left) + { + node = node->l_left; + continue; + } + + if (node->l_right) + { + node = node->l_right; + continue; + } + + tmp_node = node; + node = node->parent; + + if (node != NULL) + { + if (node->l_left == tmp_node) + node->l_left = NULL; + else + node->l_right = NULL; + + bgp_node_free (tmp_node); + } + else + { + bgp_node_free (tmp_node); + break; + } + } + + XFREE (MTYPE_BGP_TABLE, rt); + return; +} + +/* Utility mask array. */ +static u_char maskbit[] = +{ + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff +}; + +/* Common prefix route genaration. */ +static void +route_common (struct prefix *n, struct prefix *p, struct prefix *new) +{ + int i; + u_char diff; + u_char mask; + + u_char *np = (u_char *)&n->u.prefix; + u_char *pp = (u_char *)&p->u.prefix; + u_char *newp = (u_char *)&new->u.prefix; + + for (i = 0; i < p->prefixlen / 8; i++) + { + if (np[i] == pp[i]) + newp[i] = np[i]; + else + break; + } + + new->prefixlen = i * 8; + + if (new->prefixlen != p->prefixlen) + { + diff = np[i] ^ pp[i]; + mask = 0x80; + while (new->prefixlen < p->prefixlen && !(mask & diff)) + { + mask >>= 1; + new->prefixlen++; + } + newp[i] = np[i] & maskbit[new->prefixlen % 8]; + } +} + +/* Macro version of check_bit (). */ +#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1) + +/* Check bit of the prefix. */ +static int +check_bit (u_char *prefix, u_char prefixlen) +{ + int offset; + int shift; + u_char *p = (u_char *)prefix; + + assert (prefixlen <= 128); + + offset = prefixlen / 8; + shift = 7 - (prefixlen % 8); + + return (p[offset] >> shift & 1); +} + +/* Macro version of set_link (). */ +#define SET_LINK(X,Y) (X)->link[CHECK_BIT(&(Y)->prefix,(X)->prefixlen)] = (Y);\ + (Y)->parent = (X) + +static void +set_link (struct bgp_node *node, struct bgp_node *new) +{ + int bit; + + bit = check_bit (&new->p.u.prefix, node->p.prefixlen); + + assert (bit == 0 || bit == 1); + + node->link[bit] = new; + new->parent = node; +} + +/* Lock node. */ +struct bgp_node * +bgp_lock_node (struct bgp_node *node) +{ + node->lock++; + return node; +} + +/* Unlock node. */ +void +bgp_unlock_node (struct bgp_node *node) +{ + node->lock--; + + if (node->lock == 0) + bgp_node_delete (node); +} + +/* Find matched prefix. */ +struct bgp_node * +bgp_node_match (struct bgp_table *table, struct prefix *p) +{ + struct bgp_node *node; + struct bgp_node *matched; + + matched = NULL; + node = table->top; + + /* Walk down tree. If there is matched route then store it to + matched. */ + while (node && node->p.prefixlen <= p->prefixlen && + prefix_match (&node->p, p)) + { + if (node->info) + matched = node; + node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + } + + /* If matched route found, return it. */ + if (matched) + return bgp_lock_node (matched); + + return NULL; +} + +struct bgp_node * +bgp_node_match_ipv4 (struct bgp_table *table, struct in_addr *addr) +{ + struct prefix_ipv4 p; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = *addr; + + return bgp_node_match (table, (struct prefix *) &p); +} + +#ifdef HAVE_IPV6 +struct bgp_node * +bgp_node_match_ipv6 (struct bgp_table *table, struct in6_addr *addr) +{ + struct prefix_ipv6 p; + + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_PREFIXLEN; + p.prefix = *addr; + + return bgp_node_match (table, (struct prefix *) &p); +} +#endif /* HAVE_IPV6 */ + +/* Lookup same prefix node. Return NULL when we can't find route. */ +struct bgp_node * +bgp_node_lookup (struct bgp_table *table, struct prefix *p) +{ + struct bgp_node *node; + + node = table->top; + + while (node && node->p.prefixlen <= p->prefixlen && + prefix_match (&node->p, p)) + { + if (node->p.prefixlen == p->prefixlen && node->info) + return bgp_lock_node (node); + + node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + } + + return NULL; +} + +/* Add node to routing table. */ +struct bgp_node * +bgp_node_get (struct bgp_table *table, struct prefix *p) +{ + struct bgp_node *new; + struct bgp_node *node; + struct bgp_node *match; + + match = NULL; + node = table->top; + while (node && node->p.prefixlen <= p->prefixlen && + prefix_match (&node->p, p)) + { + if (node->p.prefixlen == p->prefixlen) + { + bgp_lock_node (node); + return node; + } + match = node; + node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + } + + if (node == NULL) + { + new = bgp_node_set (table, p); + if (match) + set_link (match, new); + else + table->top = new; + } + else + { + new = bgp_node_create (); + route_common (&node->p, p, &new->p); + new->p.family = p->family; + new->table = table; + set_link (new, node); + + if (match) + set_link (match, new); + else + table->top = new; + + if (new->p.prefixlen != p->prefixlen) + { + match = new; + new = bgp_node_set (table, p); + set_link (match, new); + } + } + bgp_lock_node (new); + + return new; +} + +/* Delete node from the routing table. */ +void +bgp_node_delete (struct bgp_node *node) +{ + struct bgp_node *child; + struct bgp_node *parent; + + assert (node->lock == 0); + assert (node->info == NULL); + + if (node->l_left && node->l_right) + return; + + if (node->l_left) + child = node->l_left; + else + child = node->l_right; + + parent = node->parent; + + if (child) + child->parent = parent; + + if (parent) + { + if (parent->l_left == node) + parent->l_left = child; + else + parent->l_right = child; + } + else + node->table->top = child; + + bgp_node_free (node); + + /* If parent node is stub then delete it also. */ + if (parent && parent->lock == 0) + bgp_node_delete (parent); +} + +/* Get fist node and lock it. This function is useful when one want + to lookup all the node exist in the routing table. */ +struct bgp_node * +bgp_table_top (struct bgp_table *table) +{ + /* If there is no node in the routing table return NULL. */ + if (table->top == NULL) + return NULL; + + /* Lock the top node and return it. */ + bgp_lock_node (table->top); + return table->top; +} + +/* Unlock current node and lock next node then return it. */ +struct bgp_node * +bgp_route_next (struct bgp_node *node) +{ + struct bgp_node *next; + struct bgp_node *start; + + /* Node may be deleted from bgp_unlock_node so we have to preserve + next node's pointer. */ + + if (node->l_left) + { + next = node->l_left; + bgp_lock_node (next); + bgp_unlock_node (node); + return next; + } + if (node->l_right) + { + next = node->l_right; + bgp_lock_node (next); + bgp_unlock_node (node); + return next; + } + + start = node; + while (node->parent) + { + if (node->parent->l_left == node && node->parent->l_right) + { + next = node->parent->l_right; + bgp_lock_node (next); + bgp_unlock_node (start); + return next; + } + node = node->parent; + } + bgp_unlock_node (start); + return NULL; +} + +/* Unlock current node and lock next node until limit. */ +struct bgp_node * +bgp_route_next_until (struct bgp_node *node, struct bgp_node *limit) +{ + struct bgp_node *next; + struct bgp_node *start; + + /* Node may be deleted from bgp_unlock_node so we have to preserve + next node's pointer. */ + + if (node->l_left) + { + next = node->l_left; + bgp_lock_node (next); + bgp_unlock_node (node); + return next; + } + if (node->l_right) + { + next = node->l_right; + bgp_lock_node (next); + bgp_unlock_node (node); + return next; + } + + start = node; + while (node->parent && node != limit) + { + if (node->parent->l_left == node && node->parent->l_right) + { + next = node->parent->l_right; + bgp_lock_node (next); + bgp_unlock_node (start); + return next; + } + node = node->parent; + } + bgp_unlock_node (start); + return NULL; +} diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h new file mode 100644 index 0000000..52eb6a4 --- /dev/null +++ b/bgpd/bgp_table.h @@ -0,0 +1,65 @@ +/* BGP routing table + Copyright (C) 1998, 2001 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +struct bgp_table +{ + struct bgp_node *top; +}; + +struct bgp_node +{ + struct prefix p; + + struct bgp_table *table; + struct bgp_node *parent; + struct bgp_node *link[2]; +#define l_left link[0] +#define l_right link[1] + + unsigned int lock; + + void *info; + + struct bgp_adj_out *adj_out; + + struct bgp_adj_in *adj_in; + + void *aggregate; + + struct bgp_node *prn; +}; + +struct bgp_table *bgp_table_init (void); +void bgp_table_finish (struct bgp_table *); +void bgp_unlock_node (struct bgp_node *node); +void bgp_node_delete (struct bgp_node *node); +struct bgp_node *bgp_table_top (struct bgp_table *); +struct bgp_node *bgp_route_next (struct bgp_node *); +struct bgp_node *bgp_route_next_until (struct bgp_node *, struct bgp_node *); +struct bgp_node *bgp_node_get (struct bgp_table *, struct prefix *); +struct bgp_node *bgp_node_lookup (struct bgp_table *, struct prefix *); +struct bgp_node *bgp_lock_node (struct bgp_node *node); +struct bgp_node *bgp_node_match (struct bgp_table *, struct prefix *); +struct bgp_node *bgp_node_match_ipv4 (struct bgp_table *, + struct in_addr *); +#ifdef HAVE_IPV6 +struct bgp_node *bgp_node_match_ipv6 (struct bgp_table *, + struct in6_addr *); +#endif /* HAVE_IPV6 */ diff --git a/bgpd/bgp_tcpsig.c b/bgpd/bgp_tcpsig.c new file mode 100644 index 0000000..ffd9999 --- /dev/null +++ b/bgpd/bgp_tcpsig.c @@ -0,0 +1,573 @@ +/* BGP TCP signature related functions + Copyright (C) 2004 Hiroki Nakano; Thanks to Okabe lab. (Kyoto University) + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#ifdef HAVE_OPENBSD_TCP_SIGNATURE +#include +#endif /* HAVE_OPENBSD_TCP_SIGNATURE */ + +#include "log.h" +#include "memory.h" +#include "sockunion.h" +#include "vty.h" +#include "bgpd/bgpd.h" +#include "bgpd/bgp_network.h" +#include "bgpd/bgp_tcpsig.h" + +#ifdef HAVE_OPENBSD_TCP_SIGNATURE + +#define IOVEC_SIZE 20 +#define MAX_KEY_LEN 80 + +#define SADBALIGN sizeof(u_int64_t) +#define LENUNIT(x) ((x) / SADBALIGN) +#define EXTLEN(x) (((struct sadb_ext *)(x))->sadb_ext_len * SADBALIGN) +#define PADUP(x) (((x) + (SADBALIGN - 1)) & ~(SADBALIGN - 1)) + +static u_int32_t bgp_pfkey_sadb_msg_seq = 1; +static int bgp_pfkey_sd = -1; + +int bgp_pfkey_init(void); + +#define PUSH_IOVEC(base,len) ((*iovsizep) > 0 ? \ + ((*iovp)->iov_base = (base), \ + (*iovp)->iov_len = (len), \ + (*iovp)++, \ + (*iovsizep)--) : \ + ((*iovsizep) = -1)) + +struct bgp_pfkey_sadb_msg { + struct sadb_msg header; +}; + +int +bgp_pfkey_build_sadb_msg(u_int8_t mtype, + struct bgp_pfkey_sadb_msg *sp, + struct iovec **iovp, int *iovsizep) +{ + memset(sp, 0, sizeof(*sp)); + + sp->header.sadb_msg_version = PF_KEY_V2; + sp->header.sadb_msg_type = mtype; + sp->header.sadb_msg_satype = SADB_X_SATYPE_TCPSIGNATURE; + sp->header.sadb_msg_len = LENUNIT(sizeof(sp->header)); + sp->header.sadb_msg_seq = bgp_pfkey_sadb_msg_seq++; + sp->header.sadb_msg_pid = getpid(); + + PUSH_IOVEC(&sp->header, sizeof(sp->header)); + + return sp->header.sadb_msg_len; +} + +struct bgp_pfkey_sadb_sa { + struct sadb_sa header; +}; + +int +bgp_pfkey_build_sadb_sa(u_int32_t spi, + struct bgp_pfkey_sadb_sa *sp, + struct iovec **iovp, int *iovsizep) +{ + memset(sp, 0, sizeof(*sp)); + + sp->header.sadb_sa_len = LENUNIT(sizeof(sp->header)); + sp->header.sadb_sa_exttype = SADB_EXT_SA; + sp->header.sadb_sa_spi = spi; + sp->header.sadb_sa_replay = 0; + sp->header.sadb_sa_state = SADB_SASTATE_MATURE; + sp->header.sadb_sa_auth = 0; + sp->header.sadb_sa_encrypt = 0; + + PUSH_IOVEC(&sp->header, sizeof(sp->header)); + + return sp->header.sadb_sa_len; +} + +struct bgp_pfkey_sadb_address { + struct sadb_address header; + struct sockaddr_storage ss; +}; + +int +bgp_pfkey_build_sadb_address(union sockunion *su, + struct bgp_pfkey_sadb_address *sp, + struct iovec **iovp, int *iovsizep) +{ + int paddedsslen; + + memset(sp, 0, sizeof(*sp)); + + switch (su->sa.sa_family) { + case AF_INET: + ((struct sockaddr_in *)&sp->ss)->sin_family = AF_INET; + ((struct sockaddr_in *)&sp->ss)->sin_len = sizeof(struct sockaddr_in); + ((struct sockaddr_in *)&sp->ss)->sin_addr = su->sin.sin_addr; + break; + case AF_INET6: + ((struct sockaddr_in6 *)&sp->ss)->sin6_family = AF_INET6; + ((struct sockaddr_in6 *)&sp->ss)->sin6_len = sizeof(struct sockaddr_in6); + ((struct sockaddr_in6 *)&sp->ss)->sin6_addr = su->sin6.sin6_addr; + break; + default: + return -1; + } + paddedsslen = PADUP(((struct sockaddr *)&sp->ss)->sa_len); + + sp->header.sadb_address_len = LENUNIT(sizeof(sp->header) + paddedsslen); + sp->header.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + + PUSH_IOVEC(&sp->header, sizeof(sp->header)); + PUSH_IOVEC(&sp->ss, paddedsslen); + + return sp->header.sadb_address_len; +} + +struct bgp_pfkey_sadb_key { + struct sadb_key header; + char keybuf[PADUP(MAX_KEY_LEN)]; +}; + +int +bgp_pfkey_build_sadb_key(char *key, int keylen, + struct bgp_pfkey_sadb_key *sp, + struct iovec **iovp, int *iovsizep) +{ + int paddedkeylen; + + if (keylen < 0 || keylen > MAX_KEY_LEN) + return -1; + + memset(sp, 0, sizeof(*sp)); + + memcpy(sp->keybuf, key, keylen); + paddedkeylen = PADUP(keylen); + + sp->header.sadb_key_len = LENUNIT(sizeof(sp->header) + paddedkeylen); + sp->header.sadb_key_exttype = SADB_EXT_KEY_AUTH; + sp->header.sadb_key_bits = 8 * keylen; + + PUSH_IOVEC(&sp->header, sizeof(sp->header)); + PUSH_IOVEC(sp->keybuf, paddedkeylen); + + return sp->header.sadb_key_len; +} + +struct bgp_pfkey_sadb_spirange { + struct sadb_spirange header; +}; + +int +bgp_pfkey_build_sadb_spirange(struct bgp_pfkey_sadb_spirange *sp, + struct iovec **iovp, int *iovsizep) +{ + memset(sp, 0, sizeof(*sp)); + + sp->header.sadb_spirange_len = LENUNIT(sizeof(sp->header)); + sp->header.sadb_spirange_exttype = SADB_EXT_SPIRANGE; + sp->header.sadb_spirange_min = 0x100; + sp->header.sadb_spirange_max = 0xffffffff; + + PUSH_IOVEC(&sp->header, sizeof(sp->header)); + + return sp->header.sadb_spirange_len; +} + + +int +bgp_pfkey_write(int fd, struct iovec *iov, int iovcnt) +{ + int i, len, rlen; + + len = 0; + for (i = 0; i < iovcnt; i++) + len += iov[i].iov_len; + + rlen = writev(fd, iov, iovcnt); + if (rlen == -1) + { + zlog_err("pfkey writev: %s", strerror(errno)); + return -1; + } + else if (rlen != len) + { + zlog_err("pfkey writev: len=%d ret=%d", len, rlen); + return -1; + } + + return 0; +} + +int +bgp_pfkey_read(int fd, void **bufp, int *lenp) +{ + struct sadb_msg smsg; + void *msgbuf; + int msglen, rlen; + + rlen = recv(fd, &smsg, sizeof(smsg), MSG_PEEK); + if (rlen == -1) + { + zlog_err("pfkey recv: %s", strerror(errno)); + return -1; + } + if (rlen != sizeof(smsg)) + { + zlog_err("pfkey recv: len=%d ret=%d", sizeof(smsg), rlen); + return -1; + } + + if (smsg.sadb_msg_errno != 0 || + smsg.sadb_msg_errno != ESRCH) + { + zlog_err("pfkey read msg: %s", strerror(smsg.sadb_msg_errno)); + read(fd, &smsg, sizeof(smsg)); /* get rid of error message */ + return -1; + } + + msglen = smsg.sadb_msg_len * SADBALIGN; + msgbuf = XMALLOC(MTYPE_TMP, msglen); + + rlen = read(fd, msgbuf, msglen); + if (rlen == -1) + { + zlog_err("pfkey read: %s", strerror(errno)); + XFREE(MTYPE_TMP, msgbuf); + return -1; + } + if (rlen != msglen) + { + zlog_err("pfkey read: len=%d ret=%d", msglen, rlen); + XFREE(MTYPE_TMP, msgbuf); + return -1; + } + + *bufp = msgbuf; + *lenp = msglen; + + return 0; +} + +int +bgp_pfkey_search_ext(void *buf, u_int16_t exttype, void **prevp) +{ + struct sadb_msg *msg; + struct sadb_ext *p, *last; + u_int32_t len; + + msg = buf; + len = msg->sadb_msg_len * SADBALIGN; + last = (struct sadb_ext *)(((u_int8_t *)msg) + len); + + p = *prevp ? *prevp : (struct sadb_ext *)(msg + 1); + while ((u_int8_t *)p < (u_int8_t *)last) + { + if (p->sadb_ext_type == exttype) + { + *prevp = p; + return 0; /* found */ + } + + p = (struct sadb_ext *)(((u_int8_t *)p) + EXTLEN(p)); + } + + return -1; /* not found */ +} + +int +bgp_pfkey_getspi(union sockunion *src, union sockunion *dst, u_int32_t *spip) +{ + struct iovec iovbuf[IOVEC_SIZE], *iov; + int iovcnt, iovrest; + struct bgp_pfkey_sadb_msg s_msg; + struct bgp_pfkey_sadb_spirange s_spirange; + struct bgp_pfkey_sadb_address s_srcaddr, s_dstaddr; + int len; + void *buf; + int buflen; + struct sadb_sa *ext_sa; + + if (bgp_pfkey_sd == -1) + { + bgp_pfkey_init(); + if (bgp_pfkey_sd == -1) + return -1; + } + + iov = iovbuf; + iovcnt = iovrest = sizeof(iov) / sizeof(iov[0]); + + len = bgp_pfkey_build_sadb_msg(SADB_GETSPI, &s_msg, &iov, &iovrest); + len += bgp_pfkey_build_sadb_spirange(&s_spirange, &iov, &iovrest); + len += bgp_pfkey_build_sadb_address(dst, &s_dstaddr, &iov, &iovrest); + len += bgp_pfkey_build_sadb_address(src, &s_srcaddr, &iov, &iovrest); + + s_msg.header.sadb_msg_len = len; + iovcnt -= iovrest; + + if (bgp_pfkey_write(bgp_pfkey_sd, iov, iovcnt) != 0) + { + zlog_err("pfkey getspi: fail to write request"); + return -1; + } + + if (bgp_pfkey_read(bgp_pfkey_sd, &buf, &buflen) != 0) + { + zlog_err("pfkey getspi: fail to read reply"); + return -1; + } + + if (bgp_pfkey_search_ext(buf, SADB_EXT_SA, (void **)&ext_sa) != 0) + { + zlog_err("pfkey getspi: no SA extention"); + XFREE(MTYPE_TMP, buf); + return -1; + } + + *spip = ext_sa->sadb_sa_spi; + + XFREE(MTYPE_TMP, buf); + return 0; +} + +int +bgp_pfkey_update(u_int32_t spi, union sockunion *src, union sockunion *dst, + char *key) +{ + struct iovec iovbuf[IOVEC_SIZE], *iov; + int iovcnt, iovrest; + struct bgp_pfkey_sadb_msg s_msg; + struct bgp_pfkey_sadb_sa s_sa; + struct bgp_pfkey_sadb_address s_srcaddr, s_dstaddr; + struct bgp_pfkey_sadb_key s_key; + int len; + void *buf; + int buflen; + + if (bgp_pfkey_sd == -1) + { + bgp_pfkey_init(); + if (bgp_pfkey_sd == -1) + return -1; + } + + iov = iovbuf; + iovcnt = iovrest = sizeof(iov) / sizeof(iov[0]); + + len = bgp_pfkey_build_sadb_msg(SADB_UPDATE, &s_msg, &iov, &iovrest); + len += bgp_pfkey_build_sadb_sa(spi, &s_sa, &iov, &iovrest); + len += bgp_pfkey_build_sadb_address(dst, &s_dstaddr, &iov, &iovrest); + len += bgp_pfkey_build_sadb_address(src, &s_srcaddr, &iov, &iovrest); + len += bgp_pfkey_build_sadb_key(key, strlen(key), &s_key, &iov, &iovrest); + + s_msg.header.sadb_msg_len = len; + iovcnt -= iovrest; + + if (bgp_pfkey_write(bgp_pfkey_sd, iov, iovcnt) != 0) + { + zlog_err("pfkey update: fail to write request"); + return -1; + } + + if (bgp_pfkey_read(bgp_pfkey_sd, &buf, &buflen) != 0) + { + zlog_err("pfkey update: fail to read reply"); + return -1; + } + + XFREE(MTYPE_TMP, buf); + + return 0; +} + +int +bgp_pfkey_delete(u_int32_t spi, union sockunion *src, union sockunion *dst) +{ + struct iovec iovbuf[IOVEC_SIZE], *iov; + int iovcnt, iovrest; + struct bgp_pfkey_sadb_msg s_msg; + struct bgp_pfkey_sadb_sa s_sa; + struct bgp_pfkey_sadb_address s_srcaddr, s_dstaddr; + int len; + void *buf; + int buflen; + + if (bgp_pfkey_sd == -1) + { + bgp_pfkey_init(); + if (bgp_pfkey_sd == -1) + return -1; + } + + iov = iovbuf; + iovcnt = iovrest = sizeof(iov) / sizeof(iov[0]); + + len = bgp_pfkey_build_sadb_msg(SADB_DELETE, &s_msg, &iov, &iovrest); + len += bgp_pfkey_build_sadb_sa(spi, &s_sa, &iov, &iovrest); + len += bgp_pfkey_build_sadb_address(dst, &s_dstaddr, &iov, &iovrest); + len += bgp_pfkey_build_sadb_address(src, &s_srcaddr, &iov, &iovrest); + + s_msg.header.sadb_msg_len = len; + iovcnt -= iovrest; + + if (bgp_pfkey_write(bgp_pfkey_sd, iov, iovcnt) != 0) + { + zlog_err("pfkey delete: fail to write request"); + return -1; + } + + if (bgp_pfkey_read(bgp_pfkey_sd, &buf, &buflen) != 0) + { + zlog_err("pfkey delete: fail to read reply"); + return -1; + } + + XFREE(MTYPE_TMP, buf); + + return 0; +} + +int +bgp_pfkey_init(void) +{ + bgp_pfkey_sd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); + if (bgp_pfkey_sd == -1) + { + zlog_warn("pfkey socket: %s", strerror(errno)); + return -1; + } + return 0; +} + +/*----------------------------------------------------------------*/ + +int +bgp_tcpsig_pfkey_set(struct peer *p) +{ + if (!p->update_source) + return -1; + + if (p->spi_out == 0) + if (bgp_pfkey_getspi(p->update_source, &p->su, &p->spi_out) != 0) + return -1; + + if (bgp_pfkey_update(p->spi_out, + p->update_source, &p->su, p->password) != 0) + return -1; + + if (p->spi_in == 0) + if (bgp_pfkey_getspi(&p->su, p->update_source, &p->spi_in) != 0) + return -1; + + if (bgp_pfkey_update(p->spi_in, + &p->su, p->update_source, p->password) != 0) + return -1; + + return 0; +} + +int +bgp_tcpsig_pfkey_unset(struct peer *p) +{ + if (!p->update_source) + return -1; + + if (p->spi_out != 0) + if (bgp_pfkey_delete(p->spi_out, p->update_source, &p->su) != 0) + return -1; + p->spi_out = 0; + + if (p->spi_in != 0) + if (bgp_pfkey_delete(p->spi_in, &p->su, p->update_source) != 0) + return -1; + p->spi_in = 0; + + return 0; +} + +#endif /* HAVE_OPENBSD_TCP_SIGNATURE */ + +/*----------------------------------------------------------------*/ +#ifdef HAVE_LINUX_TCP_SIGNATURE +int +bgp_tcpsig_set (int sock, struct peer *peer) +{ + struct tcp_rfc2385_cmd cmd; + int ret; + + if (sockunion_family (&peer->su) != AF_INET) + return 0; /* XXX */ + + cmd.command = TCP_MD5_AUTH_ADD; + cmd.address = peer->su.sin.sin_addr.s_addr; + cmd.keylen = strlen (peer->password); + cmd.key = peer->password; + + ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd); + + return ret; +} +#endif /* HAVE_LINUX_TCP_SIGNATURE */ + +#ifdef HAVE_OPENBSD_TCP_SIGNATURE +int +bgp_tcpsig_set (int sock, struct peer *peer) +{ + int cmd = 1; + int ret = 0; + + if (peer) + ret = bgp_tcpsig_pfkey_set(peer); + + if (ret == 0 && sock != -1) + ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &cmd, sizeof cmd); + + return ret; +} +#endif /* HAVE_OPENBSD_TCP_SIGNATURE */ + +#ifdef HAVE_LINUX_TCP_SIGNATURE +int +bgp_tcpsig_unset (int sock, struct peer *peer) +{ + struct tcp_rfc2385_cmd cmd; + int ret; + + if (sockunion_family (&peer->su) != AF_INET) + return 0; /* XXX */ + + cmd.command = TCP_MD5_AUTH_DEL; + cmd.address = peer->su.sin.sin_addr.s_addr; + cmd.keylen = strlen (peer->password); + cmd.key = peer->password; + + ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd); + + return ret; +} +#endif /* HAVE_LINUX_TCP_SIGNATURE */ + +#ifdef HAVE_OPENBSD_TCP_SIGNATURE +int +bgp_tcpsig_unset (int sock, struct peer *peer) +{ + return bgp_tcpsig_pfkey_unset(peer); +} +#endif /* HAVE_OPENBSD_TCP_SIGNATURE */ diff --git a/bgpd/bgp_tcpsig.h b/bgpd/bgp_tcpsig.h new file mode 100644 index 0000000..9bcff17 --- /dev/null +++ b/bgpd/bgp_tcpsig.h @@ -0,0 +1,24 @@ +/* BGP TCP signature related functions + Copyright (C) 2004 Hiroki Nakano + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifdef HAVE_TCP_SIGNATURE +int bgp_tcpsig_set(int, struct peer *); +int bgp_tcpsig_unset(int, struct peer *); +#endif /* HAVE_TCP_SIGNATURE */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c new file mode 100644 index 0000000..0260411 --- /dev/null +++ b/bgpd/bgp_vty.c @@ -0,0 +1,9691 @@ +/* BGP VTY interface. + Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro + + This file is part of GNU Zebra. + + GNU Zebra 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, or (at your option) any + later version. + + GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include + +#include "command.h" +#include "prefix.h" +#include "plist.h" +#include "buffer.h" +#include "linklist.h" +#include "stream.h" +#include "thread.h" +#include "log.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_open.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_zebra.h" + +/* Utility function to get address family from current node. */ +afi_t +bgp_node_afi (struct vty *vty) +{ + if (vty->node == BGP_IPV6_NODE) + return AFI_IP6; + return AFI_IP; +} + +/* Utility function to get subsequent address family from current + node. */ +safi_t +bgp_node_safi (struct vty *vty) +{ + if (vty->node == BGP_VPNV4_NODE) + return SAFI_MPLS_VPN; + if (vty->node == BGP_IPV4M_NODE) + return SAFI_MULTICAST; + return SAFI_UNICAST; +} + +int +peer_address_self_check (union sockunion *su) +{ + struct interface *ifp = NULL; + + if (su->sa.sa_family == AF_INET) + ifp = if_lookup_by_ipv4_exact (&su->sin.sin_addr); +#ifdef HAVE_IPV6 + else if (su->sa.sa_family == AF_INET6) + ifp = if_lookup_by_ipv6_exact (&su->sin6.sin6_addr); +#endif /* HAVE IPV6 */ + + if (ifp) + return 1; + + return 0; +} + +/* Utility function for looking up peer from VTY. */ +struct peer * +peer_lookup_vty (struct vty *vty, char *ip_str) +{ + int ret; + struct bgp *bgp; + union sockunion su; + struct peer *peer; + + bgp = vty->index; + + ret = str2sockunion (ip_str, &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", ip_str, VTY_NEWLINE); + return NULL; + } + + peer = peer_lookup (bgp, &su); + if (! peer) + { + vty_out (vty, "%% Specify remote-as or peer-group commands first%s", VTY_NEWLINE); + return NULL; + } + return peer; +} + +/* Utility function for looking up peer or peer group. */ +struct peer * +peer_and_group_lookup_vty (struct vty *vty, char *peer_str) +{ + int ret; + struct bgp *bgp; + union sockunion su; + struct peer *peer; + struct peer_group *group; + + bgp = vty->index; + + ret = str2sockunion (peer_str, &su); + if (ret == 0) + { + peer = peer_lookup (bgp, &su); + if (peer) + return peer; + } + else + { + group = peer_group_lookup (bgp, peer_str); + if (group) + return group->conf; + } + + vty_out (vty, "%% Specify remote-as or peer-group commands first%s", + VTY_NEWLINE); + + return NULL; +} + +int +bgp_vty_return (struct vty *vty, int ret) +{ + char *str = NULL; + + switch (ret) + { + case BGP_ERR_INVALID_VALUE: + str = "Invalid value"; + break; + case BGP_ERR_INVALID_FLAG: + str = "Invalid flag"; + break; + case BGP_ERR_PEER_INACTIVE: + str = "Activate the neighbor for the address family first"; + break; + case BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER: + str = "Invalid command for a peer-group member"; + break; + case BGP_ERR_PEER_GROUP_SHUTDOWN: + str = "Peer-group has been shutdown. Activate the peer-group first"; + break; + case BGP_ERR_PEER_GROUP_HAS_THE_FLAG: + str = "This peer is a peer-group member. Please change peer-group configuration"; + break; + case BGP_ERR_PEER_FLAG_CONFLICT: + str = "Can't set override-capability and strict-capability-match at the same time"; + break; + case BGP_ERR_PEER_GROUP_MEMBER_EXISTS: + str = "No activate for peergroup can be given only if peer-group has no members"; + break; + case BGP_ERR_PEER_BELONGS_TO_GROUP: + str = "No activate for an individual peer-group member is invalid"; + break; + case BGP_ERR_PEER_GROUP_AF_UNCONFIGURED: + str = "Activate the peer-group for the address family first"; + break; + case BGP_ERR_PEER_GROUP_NO_REMOTE_AS: + str = "Specify remote-as or peer-group remote AS first"; + break; + case BGP_ERR_PEER_GROUP_CANT_CHANGE: + str = "Cannot change the peer-group. Deconfigure first"; + break; + case BGP_ERR_PEER_GROUP_MISMATCH: + str = "Cannot have different peer-group for the neighbor"; + break; + case BGP_ERR_PEER_FILTER_CONFLICT: + str = "Prefix/distribute list can not co-exist"; + break; + case BGP_ERR_NOT_INTERNAL_PEER: + str = "Invalid command. Not an internal neighbor"; + break; + case BGP_ERR_REMOVE_PRIVATE_AS: + str = "Private AS cannot be removed for IBGP peers"; + break; + case BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP: + str = "Local-AS allowed only for EBGP peers"; + break; + case BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS: + str = "Cannot have local-as same as BGP AS number"; + break; + } + if (str) + { + vty_out (vty, "%% %s%s", str, VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +/* BGP global configuration. */ + +DEFUN (bgp_multiple_instance_func, + bgp_multiple_instance_cmd, + "bgp multiple-instance", + BGP_STR + "Enable bgp multiple instance\n") +{ + bgp_option_set (BGP_OPT_MULTIPLE_INSTANCE); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_multiple_instance, + no_bgp_multiple_instance_cmd, + "no bgp multiple-instance", + NO_STR + BGP_STR + "BGP multiple instance\n") +{ + int ret; + + ret = bgp_option_unset (BGP_OPT_MULTIPLE_INSTANCE); + if (ret < 0) + { + vty_out (vty, "%% There are more than two BGP instances%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +DEFUN (bgp_config_type, + bgp_config_type_cmd, + "bgp config-type (cisco|zebra)", + BGP_STR + "Configuration type\n" + "cisco\n" + "zebra\n") +{ + if (strncmp (argv[0], "c", 1) == 0) + bgp_option_set (BGP_OPT_CONFIG_CISCO); + else + bgp_option_unset (BGP_OPT_CONFIG_CISCO); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_config_type, + no_bgp_config_type_cmd, + "no bgp config-type", + NO_STR + BGP_STR + "Display configuration type\n") +{ + bgp_option_unset (BGP_OPT_CONFIG_CISCO); + return CMD_SUCCESS; +} + +DEFUN (no_synchronization, + no_synchronization_cmd, + "no synchronization", + NO_STR + "Perform IGP synchronization\n") +{ + return CMD_SUCCESS; +} + +DEFUN (no_auto_summary, + no_auto_summary_cmd, + "no auto-summary", + NO_STR + "Enable automatic network number summarization\n") +{ + return CMD_SUCCESS; +} + +DEFUN (neighbor_version, + neighbor_version_cmd, + NEIGHBOR_CMD "version <4-4>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Set the BGP version to match a neighbor\n" + "Neighbor's BGP version\n") +{ + return CMD_SUCCESS; +} + +/* "router bgp" commands. */ +DEFUN (router_bgp, + router_bgp_cmd, + "router bgp <1-65535>", + ROUTER_STR + BGP_STR + AS_STR) +{ + int ret; + as_t as; + struct bgp *bgp; + char *name = NULL; + + VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, 65535); + + if (argc == 2) + name = argv[1]; + + ret = bgp_get (&bgp, &as, name); + switch (ret) + { + case BGP_ERR_MULTIPLE_INSTANCE_NOT_SET: + vty_out (vty, "Please specify 'bgp multiple-instance' first%s", + VTY_NEWLINE); + return CMD_WARNING; + break; + case BGP_ERR_AS_MISMATCH: + vty_out (vty, "BGP is already running; AS is %d%s", as, VTY_NEWLINE); + return CMD_WARNING; + break; + case BGP_ERR_INSTANCE_MISMATCH: + vty_out (vty, "BGP view name and AS number mismatch%s", VTY_NEWLINE); + vty_out (vty, "BGP instance is already running; AS is %d%s", + as, VTY_NEWLINE); + return CMD_WARNING; + break; + } + + vty->node = BGP_NODE; + vty->index = bgp; + + return CMD_SUCCESS; +} + +ALIAS (router_bgp, + router_bgp_view_cmd, + "router bgp <1-65535> view WORD", + ROUTER_STR + BGP_STR + AS_STR + "BGP view\n" + "view name\n"); + +/* "no router bgp" commands. */ +DEFUN (no_router_bgp, + no_router_bgp_cmd, + "no router bgp <1-65535>", + NO_STR + ROUTER_STR + BGP_STR + AS_STR) +{ + as_t as; + struct bgp *bgp; + char *name = NULL; + + VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, 65535); + + if (argc == 2) + name = argv[1]; + + /* Lookup bgp structure. */ + bgp = bgp_lookup (as, name); + if (! bgp) + { + vty_out (vty, "%% Can't find BGP instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_delete (bgp); + + return CMD_SUCCESS; +} + +ALIAS (no_router_bgp, + no_router_bgp_view_cmd, + "no router bgp <1-65535> view WORD", + NO_STR + ROUTER_STR + BGP_STR + AS_STR + "BGP view\n" + "view name\n"); + +/* BGP router-id. */ + +DEFUN (bgp_router_id, + bgp_router_id_cmd, + "bgp router-id A.B.C.D", + BGP_STR + "Override configured router identifier\n" + "Manually configured router identifier\n") +{ + int ret; + struct in_addr id; + struct bgp *bgp; + + bgp = vty->index; + + ret = inet_aton (argv[0], &id); + if (! ret) + { + vty_out (vty, "%% Malformed bgp router identifier%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_router_id_set (bgp, &id); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_router_id, + no_bgp_router_id_cmd, + "no bgp router-id", + NO_STR + BGP_STR + "Override configured router identifier\n") +{ + int ret; + struct in_addr id; + struct bgp *bgp; + + bgp = vty->index; + + if (argc == 1) + { + ret = inet_aton (argv[0], &id); + if (! ret) + { + vty_out (vty, "%% Malformed BGP router identifier%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (! IPV4_ADDR_SAME (&bgp->router_id, &id)) + { + vty_out (vty, "%% BGP router-id doesn't match%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + bgp_router_id_unset (bgp); + + return CMD_SUCCESS; +} + +ALIAS (no_bgp_router_id, + no_bgp_router_id_val_cmd, + "no bgp router-id A.B.C.D", + NO_STR + BGP_STR + "Override configured router identifier\n" + "Manually configured router identifier\n"); + +/* BGP Cluster ID. */ + +DEFUN (bgp_cluster_id, + bgp_cluster_id_cmd, + "bgp cluster-id A.B.C.D", + BGP_STR + "Configure Route-Reflector Cluster-id\n" + "Route-Reflector Cluster-id in IP address format\n") +{ + int ret; + struct bgp *bgp; + struct in_addr cluster; + + bgp = vty->index; + + ret = inet_aton (argv[0], &cluster); + if (! ret) + { + vty_out (vty, "%% Malformed bgp cluster identifier%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_cluster_id_set (bgp, &cluster); + + return CMD_SUCCESS; +} + +ALIAS (bgp_cluster_id, + bgp_cluster_id32_cmd, + "bgp cluster-id <1-4294967295>", + BGP_STR + "Configure Route-Reflector Cluster-id\n" + "Route-Reflector Cluster-id as 32 bit quantity\n"); + +DEFUN (no_bgp_cluster_id, + no_bgp_cluster_id_cmd, + "no bgp cluster-id", + NO_STR + BGP_STR + "Configure Route-Reflector Cluster-id\n") +{ + int ret; + struct bgp *bgp; + struct in_addr cluster; + + bgp = vty->index; + + if (argc == 1) + { + ret = inet_aton (argv[0], &cluster); + if (! ret) + { + vty_out (vty, "%% Malformed bgp cluster identifier%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + bgp_cluster_id_unset (bgp); + + return CMD_SUCCESS; +} + +ALIAS (no_bgp_cluster_id, + no_bgp_cluster_id_arg_cmd, + "no bgp cluster-id A.B.C.D", + NO_STR + BGP_STR + "Configure Route-Reflector Cluster-id\n" + "Route-Reflector Cluster-id in IP address format\n"); + +DEFUN (bgp_confederation_identifier, + bgp_confederation_identifier_cmd, + "bgp confederation identifier <1-65535>", + "BGP specific commands\n" + "AS confederation parameters\n" + "AS number\n" + "Set routing domain confederation AS\n") +{ + struct bgp *bgp; + as_t as; + + bgp = vty->index; + + VTY_GET_INTEGER ("AS", as, argv[0]); + + bgp_confederation_id_set (bgp, as); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_confederation_identifier, + no_bgp_confederation_identifier_cmd, + "no bgp confederation identifier", + NO_STR + "BGP specific commands\n" + "AS confederation parameters\n" + "AS number\n") +{ + struct bgp *bgp; + as_t as; + + bgp = vty->index; + + if (argc == 1) + VTY_GET_INTEGER ("AS", as, argv[0]); + + bgp_confederation_id_unset (bgp); + + return CMD_SUCCESS; +} + +ALIAS (no_bgp_confederation_identifier, + no_bgp_confederation_identifier_arg_cmd, + "no bgp confederation identifier <1-65535>", + NO_STR + "BGP specific commands\n" + "AS confederation parameters\n" + "AS number\n" + "Set routing domain confederation AS\n"); + +DEFUN (bgp_confederation_peers, + bgp_confederation_peers_cmd, + "bgp confederation peers .<1-65535>", + "BGP specific commands\n" + "AS confederation parameters\n" + "Peer ASs in BGP confederation\n" + AS_STR) +{ + struct bgp *bgp; + as_t as; + int i; + + bgp = vty->index; + + for (i = 0; i < argc; i++) + { + VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, 65535); + + if (bgp->as == as) + { + vty_out (vty, "%% Local member-AS not allowed in confed peer list%s", + VTY_NEWLINE); + continue; + } + + bgp_confederation_peers_add (bgp, as); + } + return CMD_SUCCESS; +} + +DEFUN (no_bgp_confederation_peers, + no_bgp_confederation_peers_cmd, + "no bgp confederation peers .<1-65535>", + NO_STR + "BGP specific commands\n" + "AS confederation parameters\n" + "Peer ASs in BGP confederation\n" + AS_STR) +{ + struct bgp *bgp; + as_t as; + int i; + + bgp = vty->index; + + for (i = 0; i < argc; i++) + { + VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, 65535); + + bgp_confederation_peers_remove (bgp, as); + } + return CMD_SUCCESS; +} + +/* BGP timers. */ + +DEFUN (bgp_timers, + bgp_timers_cmd, + "timers bgp <0-65535> <0-65535>", + "Adjust routing timers\n" + "BGP timers\n" + "Keepalive interval\n" + "Holdtime\n") +{ + struct bgp *bgp; + unsigned long keepalive = 0; + unsigned long holdtime = 0; + + bgp = vty->index; + + VTY_GET_INTEGER ("keepalive", keepalive, argv[0]); + VTY_GET_INTEGER ("holdtime", holdtime, argv[1]); + + /* Holdtime value check. */ + if (holdtime < 3 && holdtime != 0) + { + vty_out (vty, "%% hold time value must be either 0 or greater than 3%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_timers_set (bgp, keepalive, holdtime); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_timers, + no_bgp_timers_cmd, + "no timers bgp", + NO_STR + "Adjust routing timers\n" + "BGP timers\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_timers_unset (bgp); + + return CMD_SUCCESS; +} + +ALIAS (no_bgp_timers, + no_bgp_timers_arg_cmd, + "no timers bgp <0-65535> <0-65535>", + NO_STR + "Adjust routing timers\n" + "BGP timers\n" + "Keepalive interval\n" + "Holdtime\n"); + +DEFUN (bgp_client_to_client_reflection, + bgp_client_to_client_reflection_cmd, + "bgp client-to-client reflection", + "BGP specific commands\n" + "Configure client to client route reflection\n" + "reflection of routes allowed\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_client_to_client_reflection, + no_bgp_client_to_client_reflection_cmd, + "no bgp client-to-client reflection", + NO_STR + "BGP specific commands\n" + "Configure client to client route reflection\n" + "reflection of routes allowed\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT); + return CMD_SUCCESS; +} + +/* "bgp always-compare-med" configuration. */ +DEFUN (bgp_always_compare_med, + bgp_always_compare_med_cmd, + "bgp always-compare-med", + "BGP specific commands\n" + "Allow comparing MED from different neighbors\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_ALWAYS_COMPARE_MED); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_always_compare_med, + no_bgp_always_compare_med_cmd, + "no bgp always-compare-med", + NO_STR + "BGP specific commands\n" + "Allow comparing MED from different neighbors\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_ALWAYS_COMPARE_MED); + return CMD_SUCCESS; +} + +/* "bgp deterministic-med" configuration. */ +DEFUN (bgp_deterministic_med, + bgp_deterministic_med_cmd, + "bgp deterministic-med", + "BGP specific commands\n" + "Pick the best-MED path among paths advertised from the neighboring AS\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_DETERMINISTIC_MED); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_deterministic_med, + no_bgp_deterministic_med_cmd, + "no bgp deterministic-med", + NO_STR + "BGP specific commands\n" + "Pick the best-MED path among paths advertised from the neighboring AS\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_DETERMINISTIC_MED); + return CMD_SUCCESS; +} + +/* "bgp graceful-restart" configuration. */ +DEFUN (bgp_graceful_restart, + bgp_graceful_restart_cmd, + "bgp graceful-restart", + "BGP specific commands\n" + "Graceful restart capability parameters\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_GRACEFUL_RESTART); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_graceful_restart, + no_bgp_graceful_restart_cmd, + "no bgp graceful-restart", + NO_STR + "BGP specific commands\n" + "Graceful restart capability parameters\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_GRACEFUL_RESTART); + return CMD_SUCCESS; +} + +DEFUN (bgp_graceful_restart_stalepath_time, + bgp_graceful_restart_stalepath_time_cmd, + "bgp graceful-restart stalepath-time <1-3600>", + "BGP specific commands\n" + "Graceful restart capability parameters\n" + "Set the max time to hold onto restarting peer's stale paths\n" + "Delay value (seconds)\n") +{ + struct bgp *bgp; + u_int32_t stalepath; + + bgp = vty->index; + if (! bgp) + return CMD_WARNING; + + VTY_GET_INTEGER_RANGE ("stalepath-time", stalepath, argv[0], 1, 3600); + bgp->stalepath_time = stalepath; + return CMD_SUCCESS; +} + +DEFUN (no_bgp_graceful_restart_stalepath_time, + no_bgp_graceful_restart_stalepath_time_cmd, + "no bgp graceful-restart stalepath-time", + NO_STR + "BGP specific commands\n" + "Graceful restart capability parameters\n" + "Set the max time to hold onto restarting peer's stale paths\n") +{ + struct bgp *bgp; + + bgp = vty->index; + if (! bgp) + return CMD_WARNING; + + bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + return CMD_SUCCESS; +} + +ALIAS (no_bgp_graceful_restart_stalepath_time, + no_bgp_graceful_restart_stalepath_time_val_cmd, + "no bgp graceful-restart stalepath-time <1-3600>", + NO_STR + "BGP specific commands\n" + "Graceful restart capability parameters\n" + "Set the max time to hold onto restarting peer's stale paths\n" + "Delay value (seconds)\n") + +/* "bgp fast-external-failover" configuration. */ +DEFUN (bgp_fast_external_failover, + bgp_fast_external_failover_cmd, + "bgp fast-external-failover", + BGP_STR + "Immediately reset session if a link to a directly connected external peer goes down\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_fast_external_failover, + no_bgp_fast_external_failover_cmd, + "no bgp fast-external-failover", + NO_STR + BGP_STR + "Immediately reset session if a link to a directly connected external peer goes down\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER); + return CMD_SUCCESS; +} + +/* "bgp enforce-first-as" configuration. */ +DEFUN (bgp_enforce_first_as, + bgp_enforce_first_as_cmd, + "bgp enforce-first-as", + BGP_STR + "Enforce the first AS for EBGP routes(default)\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_NO_ENFORCE_FIRST_AS); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_enforce_first_as, + no_bgp_enforce_first_as_cmd, + "no bgp enforce-first-as", + NO_STR + BGP_STR + "Enforce the first AS for EBGP routes(default)\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_NO_ENFORCE_FIRST_AS); + return CMD_SUCCESS; +} + +/* "bgp bestpath compare-routerid" configuration. */ +DEFUN (bgp_bestpath_compare_router_id, + bgp_bestpath_compare_router_id_cmd, + "bgp bestpath compare-routerid", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "Compare router-id for identical EBGP paths\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_COMPARE_ROUTER_ID); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_bestpath_compare_router_id, + no_bgp_bestpath_compare_router_id_cmd, + "no bgp bestpath compare-routerid", + NO_STR + "BGP specific commands\n" + "Change the default bestpath selection\n" + "Compare router-id for identical EBGP paths\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_COMPARE_ROUTER_ID); + return CMD_SUCCESS; +} + +/* "bgp bestpath cost-community ignore" configuration. */ +DEFUN (bgp_bestpath_cost_community_ignore, + bgp_bestpath_cost_community_ignore_cmd, + "bgp bestpath cost-community ignore", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "cost community\n" + "Ignore cost communities in bestpath selection\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_COST_COMMUNITY_IGNORE); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_bestpath_cost_community_ignore, + no_bgp_bestpath_cost_community_ignore_cmd, + "no bgp bestpath cost-community ignore", + NO_STR + "BGP specific commands\n" + "Change the default bestpath selection\n" + "cost community\n" + "Ignore cost communities in bestpath selection\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_COST_COMMUNITY_IGNORE); + return CMD_SUCCESS; +} + + +/* "bgp bestpath as-path ignore" configuration. */ +DEFUN (bgp_bestpath_aspath_ignore, + bgp_bestpath_aspath_ignore_cmd, + "bgp bestpath as-path ignore", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "AS-path attribute\n" + "Ignore as-path length in selecting a route\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_ASPATH_IGNORE); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_bestpath_aspath_ignore, + no_bgp_bestpath_aspath_ignore_cmd, + "no bgp bestpath as-path ignore", + NO_STR + "BGP specific commands\n" + "Change the default bestpath selection\n" + "AS-path attribute\n" + "Ignore as-path length in selecting a route\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_ASPATH_IGNORE); + return CMD_SUCCESS; +} + +/* "bgp log-neighbor-changes" configuration. */ +DEFUN (bgp_log_neighbor_changes, + bgp_log_neighbor_changes_cmd, + "bgp log-neighbor-changes", + "BGP specific commands\n" + "Log neighbor up/down and reset reason\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_log_neighbor_changes, + no_bgp_log_neighbor_changes_cmd, + "no bgp log-neighbor-changes", + NO_STR + "BGP specific commands\n" + "Log neighbor up/down and reset reason\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES); + return CMD_SUCCESS; +} + +/* "bgp bestpath med" configuration. */ +DEFUN (bgp_bestpath_med, + bgp_bestpath_med_cmd, + "bgp bestpath med (confed|missing-as-worst)", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Compare MED among confederation paths\n" + "Treat missing MED as the least preferred one\n") +{ + struct bgp *bgp; + + bgp = vty->index; + + if (strncmp (argv[0], "confed", 1) == 0) + bgp_flag_set (bgp, BGP_FLAG_MED_CONFED); + else + bgp_flag_set (bgp, BGP_FLAG_MED_MISSING_AS_WORST); + + return CMD_SUCCESS; +} + +DEFUN (bgp_bestpath_med2, + bgp_bestpath_med2_cmd, + "bgp bestpath med confed missing-as-worst", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Compare MED among confederation paths\n" + "Treat missing MED as the least preferred one\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_MED_CONFED); + bgp_flag_set (bgp, BGP_FLAG_MED_MISSING_AS_WORST); + return CMD_SUCCESS; +} + +ALIAS (bgp_bestpath_med2, + bgp_bestpath_med3_cmd, + "bgp bestpath med missing-as-worst confed", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Treat missing MED as the least preferred one\n" + "Compare MED among confederation paths\n"); + +DEFUN (no_bgp_bestpath_med, + no_bgp_bestpath_med_cmd, + "no bgp bestpath med (confed|missing-as-worst)", + NO_STR + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Compare MED among confederation paths\n" + "Treat missing MED as the least preferred one\n") +{ + struct bgp *bgp; + + bgp = vty->index; + + if (strncmp (argv[0], "confed", 1) == 0) + bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED); + else + bgp_flag_unset (bgp, BGP_FLAG_MED_MISSING_AS_WORST); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_bestpath_med2, + no_bgp_bestpath_med2_cmd, + "no bgp bestpath med confed missing-as-worst", + NO_STR + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Compare MED among confederation paths\n" + "Treat missing MED as the least preferred one\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED); + bgp_flag_unset (bgp, BGP_FLAG_MED_MISSING_AS_WORST); + return CMD_SUCCESS; +} + +ALIAS (no_bgp_bestpath_med2, + no_bgp_bestpath_med3_cmd, + "no bgp bestpath med missing-as-worst confed", + NO_STR + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Treat missing MED as the least preferred one\n" + "Compare MED among confederation paths\n"); + +/* "no bgp default ipv4-unicast". */ +DEFUN (no_bgp_default_ipv4_unicast, + no_bgp_default_ipv4_unicast_cmd, + "no bgp default ipv4-unicast", + NO_STR + "BGP specific commands\n" + "Configure BGP defaults\n" + "Activate ipv4-unicast for a peer by default\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_NO_DEFAULT_IPV4); + return CMD_SUCCESS; +} + +DEFUN (bgp_default_ipv4_unicast, + bgp_default_ipv4_unicast_cmd, + "bgp default ipv4-unicast", + "BGP specific commands\n" + "Configure BGP defaults\n" + "Activate ipv4-unicast for a peer by default\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_NO_DEFAULT_IPV4); + return CMD_SUCCESS; +} + +/* "bgp import-check" configuration. */ +DEFUN (bgp_network_import_check, + bgp_network_import_check_cmd, + "bgp network import-check", + "BGP specific commands\n" + "BGP network command\n" + "Check BGP network route exists in IGP\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_network_import_check, + no_bgp_network_import_check_cmd, + "no bgp network import-check", + NO_STR + "BGP specific commands\n" + "BGP network command\n" + "Check BGP network route exists in IGP\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK); + return CMD_SUCCESS; +} + +DEFUN (bgp_default_local_preference, + bgp_default_local_preference_cmd, + "bgp default local-preference <0-4294967295>", + "BGP specific commands\n" + "Configure BGP defaults\n" + "local preference (higher=more preferred)\n" + "Configure default local preference value\n") +{ + struct bgp *bgp; + u_int32_t local_pref; + + bgp = vty->index; + + VTY_GET_INTEGER ("local preference", local_pref, argv[0]); + + bgp_default_local_preference_set (bgp, local_pref); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_default_local_preference, + no_bgp_default_local_preference_cmd, + "no bgp default local-preference", + NO_STR + "BGP specific commands\n" + "Configure BGP defaults\n" + "local preference (higher=more preferred)\n") +{ + struct bgp *bgp; + + bgp = vty->index; + bgp_default_local_preference_unset (bgp); + return CMD_SUCCESS; +} + +ALIAS (no_bgp_default_local_preference, + no_bgp_default_local_preference_val_cmd, + "no bgp default local-preference <0-4294967295>", + NO_STR + "BGP specific commands\n" + "Configure BGP defaults\n" + "local preference (higher=more preferred)\n" + "Configure default local preference value\n"); + +static int +peer_remote_as_vty (struct vty *vty, char *peer_str, char *as_str, afi_t afi, + safi_t safi) +{ + int ret; + struct bgp *bgp; + as_t as; + union sockunion su; + + bgp = vty->index; + + /* Get AS number. */ + VTY_GET_INTEGER_RANGE ("AS", as, as_str, 1, 65535); + + /* If peer is peer group, call proper function. */ + ret = str2sockunion (peer_str, &su); + if (ret < 0) + { + ret = peer_group_remote_as (bgp, peer_str, &as); + if (ret < 0) + { + vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; + } + + if (peer_address_self_check (&su)) + { + vty_out (vty, "%% Can not configure the local system as neighbor%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = peer_remote_as (bgp, &su, &as, afi, safi); + + /* This peer belongs to peer group. */ + switch (ret) + { + case BGP_ERR_PEER_GROUP_MEMBER: + vty_out (vty, "%% Peer-group AS %d. Cannot configure remote-as for member%s", as, VTY_NEWLINE); + return CMD_WARNING; + break; + case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT: + vty_out (vty, "%% The AS# can not be changed from %d to %s, peer-group members must be all internal or all external%s", as, as_str, VTY_NEWLINE); + return CMD_WARNING; + break; + } + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_remote_as, + neighbor_remote_as_cmd, + NEIGHBOR_CMD2 "remote-as <1-65535>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a BGP neighbor\n" + AS_STR) +{ + return peer_remote_as_vty (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST); +} + +DEFUN (neighbor_peer_group, + neighbor_peer_group_cmd, + "neighbor WORD peer-group", + NEIGHBOR_STR + "Neighbor tag\n" + "Configure peer-group\n") +{ + struct bgp *bgp; + struct peer_group *group; + + bgp = vty->index; + + group = peer_group_get (bgp, argv[0]); + if (! group) + return CMD_WARNING; + + return CMD_SUCCESS; +} + +DEFUN (no_neighbor, + no_neighbor_cmd, + NO_NEIGHBOR_CMD2, + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2) +{ + int ret; + union sockunion su; + struct peer_group *group; + struct peer *peer; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + group = peer_group_lookup (vty->index, argv[0]); + if (group) + peer_group_delete (group); + else + { + vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + peer = peer_lookup (vty->index, &su); + if (peer) + peer_delete (peer); + } + + return CMD_SUCCESS; +} + +ALIAS (no_neighbor, + no_neighbor_remote_as_cmd, + NO_NEIGHBOR_CMD "remote-as <1-65535>", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Specify a BGP neighbor\n" + AS_STR); + +DEFUN (no_neighbor_peer_group, + no_neighbor_peer_group_cmd, + "no neighbor WORD peer-group", + NO_STR + NEIGHBOR_STR + "Neighbor tag\n" + "Configure peer-group\n") +{ + struct peer_group *group; + + group = peer_group_lookup (vty->index, argv[0]); + if (group) + peer_group_delete (group); + else + { + vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +DEFUN (no_neighbor_peer_group_remote_as, + no_neighbor_peer_group_remote_as_cmd, + "no neighbor WORD remote-as <1-65535>", + NO_STR + NEIGHBOR_STR + "Neighbor tag\n" + "Specify a BGP neighbor\n" + AS_STR) +{ + struct peer_group *group; + + group = peer_group_lookup (vty->index, argv[0]); + if (group) + peer_group_remote_as_delete (group); + else + { + vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +DEFUN (neighbor_local_as, + neighbor_local_as_cmd, + NEIGHBOR_CMD2 "local-as <1-65535>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a local-as number\n" + "AS number used as local AS\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_local_as_set (peer, atoi (argv[1]), 0); + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_local_as_no_prepend, + neighbor_local_as_no_prepend_cmd, + NEIGHBOR_CMD2 "local-as <1-65535> no-prepend", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a local-as number\n" + "AS number used as local AS\n" + "Do not prepend local-as to updates from ebgp peers\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_local_as_set (peer, atoi (argv[1]), 1); + return bgp_vty_return (vty, ret); +} + +DEFUN (no_neighbor_local_as, + no_neighbor_local_as_cmd, + NO_NEIGHBOR_CMD2 "local-as", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a local-as number\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_local_as_unset (peer); + return bgp_vty_return (vty, ret); +} + +ALIAS (no_neighbor_local_as, + no_neighbor_local_as_val_cmd, + NO_NEIGHBOR_CMD2 "local-as <1-65535>", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a local-as number\n" + "AS number used as local AS\n"); + +ALIAS (no_neighbor_local_as, + no_neighbor_local_as_val2_cmd, + NO_NEIGHBOR_CMD2 "local-as <1-65535> no-prepend", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify a local-as number\n" + "AS number used as local AS\n" + "Do not prepend local-as to updates from ebgp peers\n"); + +#ifdef HAVE_TCP_SIGNATURE +DEFUN (neighbor_password, + neighbor_password_cmd, + NEIGHBOR_CMD2 "password LINE", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Set a password\n" + "The password\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_password_set (peer, argv[1]); + return bgp_vty_return (vty, ret); +} + +DEFUN (no_neighbor_password, + no_neighbor_password_cmd, + NO_NEIGHBOR_CMD2 "password", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Set a password\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_password_unset (peer); + return bgp_vty_return (vty, ret); +} +#endif /* HAVE_TCP_SIGNATURE */ + +DEFUN (neighbor_activate, + neighbor_activate_cmd, + NEIGHBOR_CMD2 "activate", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Enable the Address Family for this Neighbor\n") +{ + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + peer_activate (peer, bgp_node_afi (vty), bgp_node_safi (vty)); + + return CMD_SUCCESS; +} + +DEFUN (no_neighbor_activate, + no_neighbor_activate_cmd, + NO_NEIGHBOR_CMD2 "activate", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Enable the Address Family for this Neighbor\n") +{ + int ret; + struct peer *peer; + + /* Lookup peer. */ + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_deactivate (peer, bgp_node_afi (vty), bgp_node_safi (vty)); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_set_peer_group, + neighbor_set_peer_group_cmd, + NEIGHBOR_CMD "peer-group WORD", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Member of the peer-group\n" + "peer-group name\n") +{ + int ret; + as_t as; + union sockunion su; + struct bgp *bgp; + struct peer_group *group; + + bgp = vty->index; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + group = peer_group_lookup (bgp, argv[1]); + if (! group) + { + vty_out (vty, "%% Configure the peer-group first%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (peer_address_self_check (&su)) + { + vty_out (vty, "%% Can not configure the local system as neighbor%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = peer_group_bind (bgp, &su, group, bgp_node_afi (vty), + bgp_node_safi (vty), &as); + + if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT) + { + vty_out (vty, "%% Peer with AS %d cannot be in this peer-group, members must be all internal or all external%s", as, VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_vty_return (vty, ret); +} + +DEFUN (no_neighbor_set_peer_group, + no_neighbor_set_peer_group_cmd, + NO_NEIGHBOR_CMD "peer-group WORD", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Member of the peer-group\n" + "peer-group name\n") +{ + int ret; + struct bgp *bgp; + struct peer *peer; + struct peer_group *group; + + bgp = vty->index; + + peer = peer_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + group = peer_group_lookup (bgp, argv[1]); + if (! group) + { + vty_out (vty, "%% Configure the peer-group first%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = peer_group_unbind (bgp, peer, group, bgp_node_afi (vty), + bgp_node_safi (vty)); + + return bgp_vty_return (vty, ret); +} + +int +peer_flag_modify_vty (struct vty *vty, char *ip_str, u_int16_t flag, int set) +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + if (set) + ret = peer_flag_set (peer, flag); + else + ret = peer_flag_unset (peer, flag); + + return bgp_vty_return (vty, ret); +} + +int +peer_flag_set_vty (struct vty *vty, char *ip_str, u_int16_t flag) +{ + return peer_flag_modify_vty (vty, ip_str, flag, 1); +} + +int +peer_flag_unset_vty (struct vty *vty, char *ip_str, u_int16_t flag) +{ + return peer_flag_modify_vty (vty, ip_str, flag, 0); +} + +/* neighbor trasport connection-mode. */ +DEFUN (neighbor_transport_connection_mode, + neighbor_transport_connection_mode_cmd, + NEIGHBOR_CMD2 "transport connection-mode (active|passive)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Transport options\n" + "Specify passive or active connection\n" + "Actively establish the TCP session\n" + "Passively establish the TCP session\n") +{ + int ret; + + if (strncmp (argv[1], "a", 1) == 0) + { + ret = peer_flag_unset_vty (vty, argv[0], PEER_FLAG_CONNECT_MODE_PASSIVE); + if (ret == CMD_SUCCESS) + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_CONNECT_MODE_ACTIVE); + else + return CMD_WARNING; + } + else if (strncmp (argv[1], "p", 1) == 0) + { + ret = peer_flag_unset_vty (vty, argv[0], PEER_FLAG_CONNECT_MODE_ACTIVE); + if (ret == CMD_SUCCESS) + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_CONNECT_MODE_PASSIVE); + else + return CMD_WARNING; + } + else + return CMD_WARNING; +} + +DEFUN (no_neighbor_transport_connection_mode, + no_neighbor_transport_connection_mode_cmd, + NO_NEIGHBOR_CMD2 "transport connection-mode", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Transport options\n" + "Specify passive or active connection\n") +{ + int ret; + + ret = peer_flag_unset_vty (vty, argv[0], PEER_FLAG_CONNECT_MODE_PASSIVE); + if (ret == CMD_SUCCESS) + return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_CONNECT_MODE_ACTIVE); + else + return CMD_WARNING; +} + +ALIAS (no_neighbor_transport_connection_mode, + no_neighbor_transport_connection_mode_val_cmd, + NO_NEIGHBOR_CMD2 "transport connection-mode (active|passive)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Transport options\n" + "Specify passive or active connection\n" + "Actively establish the TCP session\n" + "Passively establish the TCP session\n") + +DEFUN (neighbor_passive, + neighbor_passive_cmd, + NEIGHBOR_CMD2 "passive", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Don't send open messages to this neighbor\n") +{ + int ret; + + ret = peer_flag_unset_vty (vty, argv[0], PEER_FLAG_CONNECT_MODE_ACTIVE); + if (ret == CMD_SUCCESS) + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_CONNECT_MODE_PASSIVE); + else + return CMD_WARNING; +} + +/* neighbor shutdown. */ +DEFUN (neighbor_shutdown, + neighbor_shutdown_cmd, + NEIGHBOR_CMD2 "shutdown", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Administratively shut down this neighbor\n") +{ + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_SHUTDOWN); +} + +DEFUN (no_neighbor_shutdown, + no_neighbor_shutdown_cmd, + NO_NEIGHBOR_CMD2 "shutdown", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Administratively shut down this neighbor\n") +{ + return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_SHUTDOWN); +} + +/* neighbor capability dynamic. */ +DEFUN (neighbor_capability_dynamic, + neighbor_capability_dynamic_cmd, + NEIGHBOR_CMD2 "capability dynamic", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Advertise capability to the peer\n" + "Advertise dynamic capability to this neighbor\n") +{ + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_DYNAMIC_CAPABILITY); +} + +DEFUN (no_neighbor_capability_dynamic, + no_neighbor_capability_dynamic_cmd, + NO_NEIGHBOR_CMD2 "capability dynamic", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Advertise capability to the peer\n" + "Advertise dynamic capability to this neighbor\n") +{ + return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DYNAMIC_CAPABILITY); +} + +/* neighbor dont-capability-negotiate */ +DEFUN (neighbor_dont_capability_negotiate, + neighbor_dont_capability_negotiate_cmd, + NEIGHBOR_CMD2 "dont-capability-negotiate", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Do not perform capability negotiation\n") +{ + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY); +} + +DEFUN (no_neighbor_dont_capability_negotiate, + no_neighbor_dont_capability_negotiate_cmd, + NO_NEIGHBOR_CMD2 "dont-capability-negotiate", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Do not perform capability negotiation\n") +{ + return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY); +} + +int +peer_af_flag_modify_vty (struct vty *vty, char *peer_str, afi_t afi, + safi_t safi, u_int16_t flag, int set) +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, peer_str); + if (! peer) + return CMD_WARNING; + + if (set) + ret = peer_af_flag_set (peer, afi, safi, flag); + else + ret = peer_af_flag_unset (peer, afi, safi, flag); + + return bgp_vty_return (vty, ret); +} + +int +peer_af_flag_set_vty (struct vty *vty, char *peer_str, afi_t afi, + safi_t safi, u_int16_t flag) +{ + return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 1); +} + +int +peer_af_flag_unset_vty (struct vty *vty, char *peer_str, afi_t afi, + safi_t safi, u_int16_t flag) +{ + return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 0); +} + +/* neighbor capability orf prefix-list. */ +DEFUN (neighbor_capability_orf_prefix, + neighbor_capability_orf_prefix_cmd, + NEIGHBOR_CMD2 "capability orf prefix-list (both|send|receive)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Advertise capability to the peer\n" + "Advertise ORF capability to the peer\n" + "Advertise prefixlist ORF capability to this neighbor\n" + "Capability to SEND and RECEIVE the ORF to/from this neighbor\n" + "Capability to RECEIVE the ORF from this neighbor\n" + "Capability to SEND the ORF to this neighbor\n") +{ + u_int16_t flag = 0; + + if (strncmp (argv[1], "s", 1) == 0) + flag = PEER_FLAG_ORF_PREFIX_SM; + else if (strncmp (argv[1], "r", 1) == 0) + flag = PEER_FLAG_ORF_PREFIX_RM; + else if (strncmp (argv[1], "b", 1) == 0) + flag = PEER_FLAG_ORF_PREFIX_SM|PEER_FLAG_ORF_PREFIX_RM; + else + return CMD_WARNING; + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flag); +} + +DEFUN (no_neighbor_capability_orf_prefix, + no_neighbor_capability_orf_prefix_cmd, + NO_NEIGHBOR_CMD2 "capability orf prefix-list (both|send|receive)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Advertise capability to the peer\n" + "Advertise ORF capability to the peer\n" + "Advertise prefixlist ORF capability to this neighbor\n" + "Capability to SEND and RECEIVE the ORF to/from this neighbor\n" + "Capability to RECEIVE the ORF from this neighbor\n" + "Capability to SEND the ORF to this neighbor\n") +{ + u_int16_t flag = 0; + + if (strncmp (argv[1], "s", 1) == 0) + flag = PEER_FLAG_ORF_PREFIX_SM; + else if (strncmp (argv[1], "r", 1) == 0) + flag = PEER_FLAG_ORF_PREFIX_RM; + else if (strncmp (argv[1], "b", 1) == 0) + flag = PEER_FLAG_ORF_PREFIX_SM|PEER_FLAG_ORF_PREFIX_RM; + else + return CMD_WARNING; + + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flag); +} + +/* neighbor next-hop-self. */ +DEFUN (neighbor_nexthop_self, + neighbor_nexthop_self_cmd, + NEIGHBOR_CMD2 "next-hop-self", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Disable the next hop calculation for this neighbor\n") +{ + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF); +} + +DEFUN (no_neighbor_nexthop_self, + no_neighbor_nexthop_self_cmd, + NO_NEIGHBOR_CMD2 "next-hop-self", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Disable the next hop calculation for this neighbor\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF); +} + +/* neighbor remove-private-AS. */ +DEFUN (neighbor_remove_private_as, + neighbor_remove_private_as_cmd, + NEIGHBOR_CMD2 "remove-private-AS", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Remove private AS number from outbound updates\n") +{ + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_REMOVE_PRIVATE_AS); +} + +DEFUN (no_neighbor_remove_private_as, + no_neighbor_remove_private_as_cmd, + NO_NEIGHBOR_CMD2 "remove-private-AS", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Remove private AS number from outbound updates\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_REMOVE_PRIVATE_AS); +} + +/* neighbor send-community. */ +DEFUN (neighbor_send_community, + neighbor_send_community_cmd, + NEIGHBOR_CMD2 "send-community", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Send Community attribute to this neighbor\n") +{ + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_COMMUNITY); +} + +DEFUN (no_neighbor_send_community, + no_neighbor_send_community_cmd, + NO_NEIGHBOR_CMD2 "send-community", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Send Community attribute to this neighbor\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_COMMUNITY); +} + +/* neighbor send-community extended. */ +DEFUN (neighbor_send_community_type, + neighbor_send_community_type_cmd, + NEIGHBOR_CMD2 "send-community (both|extended|standard)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Send Community attribute to this neighbor\n" + "Send Standard and Extended Community attributes\n" + "Send Extended Community attributes\n" + "Send Standard Community attributes\n") +{ + if (strncmp (argv[1], "s", 1) == 0) + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_COMMUNITY); + if (strncmp (argv[1], "e", 1) == 0) + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_EXT_COMMUNITY); + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + (PEER_FLAG_SEND_COMMUNITY| + PEER_FLAG_SEND_EXT_COMMUNITY)); +} + +DEFUN (no_neighbor_send_community_type, + no_neighbor_send_community_type_cmd, + NO_NEIGHBOR_CMD2 "send-community (both|extended|standard)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Send Community attribute to this neighbor\n" + "Send Standard and Extended Community attributes\n" + "Send Extended Community attributes\n" + "Send Standard Community attributes\n") +{ + if (strncmp (argv[1], "s", 1) == 0) + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_COMMUNITY); + if (strncmp (argv[1], "e", 1) == 0) + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_EXT_COMMUNITY); + + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + (PEER_FLAG_SEND_COMMUNITY | + PEER_FLAG_SEND_EXT_COMMUNITY)); +} + +/* neighbor soft-reconfig. */ +DEFUN (neighbor_soft_reconfiguration, + neighbor_soft_reconfiguration_cmd, + NEIGHBOR_CMD2 "soft-reconfiguration inbound", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Per neighbor soft reconfiguration\n" + "Allow inbound soft reconfiguration for this neighbor\n") +{ + return peer_af_flag_set_vty (vty, argv[0], + bgp_node_afi (vty), bgp_node_safi (vty), + PEER_FLAG_SOFT_RECONFIG); +} + +DEFUN (no_neighbor_soft_reconfiguration, + no_neighbor_soft_reconfiguration_cmd, + NO_NEIGHBOR_CMD2 "soft-reconfiguration inbound", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Per neighbor soft reconfiguration\n" + "Allow inbound soft reconfiguration for this neighbor\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], + bgp_node_afi (vty), bgp_node_safi (vty), + PEER_FLAG_SOFT_RECONFIG); +} + +DEFUN (neighbor_route_reflector_client, + neighbor_route_reflector_client_cmd, + NEIGHBOR_CMD2 "route-reflector-client", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Configure a neighbor as Route Reflector client\n") +{ + struct peer *peer; + + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_REFLECTOR_CLIENT); +} + +DEFUN (no_neighbor_route_reflector_client, + no_neighbor_route_reflector_client_cmd, + NO_NEIGHBOR_CMD2 "route-reflector-client", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Configure a neighbor as Route Reflector client\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_REFLECTOR_CLIENT); +} + +/* neighbor route-server-client. */ +DEFUN (neighbor_route_server_client, + neighbor_route_server_client_cmd, + NEIGHBOR_CMD2 "route-server-client", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Configure a neighbor as Route Server client\n") +{ + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_RSERVER_CLIENT); +} + +DEFUN (no_neighbor_route_server_client, + no_neighbor_route_server_client_cmd, + NO_NEIGHBOR_CMD2 "route-server-client", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Configure a neighbor as Route Server client\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_RSERVER_CLIENT); +} + +DEFUN (neighbor_attr_unchanged, + neighbor_attr_unchanged_cmd, + NEIGHBOR_CMD2 "attribute-unchanged", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n") +{ + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + (PEER_FLAG_AS_PATH_UNCHANGED | + PEER_FLAG_NEXTHOP_UNCHANGED | + PEER_FLAG_MED_UNCHANGED)); +} + +DEFUN (neighbor_attr_unchanged1, + neighbor_attr_unchanged1_cmd, + NEIGHBOR_CMD2 "attribute-unchanged (as-path|next-hop|med)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") +{ + u_int16_t flags = 0; + + if (strncmp (argv[1], "as-path", 1) == 0) + SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); + else if (strncmp (argv[1], "next-hop", 1) == 0) + SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + else if (strncmp (argv[1], "med", 1) == 0) + SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +DEFUN (neighbor_attr_unchanged2, + neighbor_attr_unchanged2_cmd, + NEIGHBOR_CMD2 "attribute-unchanged as-path (next-hop|med)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") +{ + u_int16_t flags = PEER_FLAG_AS_PATH_UNCHANGED; + + if (strncmp (argv[1], "next-hop", 1) == 0) + SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + else if (strncmp (argv[1], "med", 1) == 0) + SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); + +} + +DEFUN (neighbor_attr_unchanged3, + neighbor_attr_unchanged3_cmd, + NEIGHBOR_CMD2 "attribute-unchanged next-hop (as-path|med)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "As-path attribute\n" + "Med attribute\n") +{ + u_int16_t flags = PEER_FLAG_NEXTHOP_UNCHANGED; + + if (strncmp (argv[1], "as-path", 1) == 0) + SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); + else if (strncmp (argv[1], "med", 1) == 0) + SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +DEFUN (neighbor_attr_unchanged4, + neighbor_attr_unchanged4_cmd, + NEIGHBOR_CMD2 "attribute-unchanged med (as-path|next-hop)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "As-path attribute\n" + "Nexthop attribute\n") +{ + u_int16_t flags = PEER_FLAG_MED_UNCHANGED; + + if (strncmp (argv[1], "as-path", 1) == 0) + SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); + else if (strncmp (argv[1], "next-hop", 1) == 0) + SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +ALIAS (neighbor_attr_unchanged, + neighbor_attr_unchanged5_cmd, + NEIGHBOR_CMD2 "attribute-unchanged as-path next-hop med", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n"); + +ALIAS (neighbor_attr_unchanged, + neighbor_attr_unchanged6_cmd, + NEIGHBOR_CMD2 "attribute-unchanged as-path med next-hop", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Med attribute\n" + "Nexthop attribute\n"); + +ALIAS (neighbor_attr_unchanged, + neighbor_attr_unchanged7_cmd, + NEIGHBOR_CMD2 "attribute-unchanged next-hop med as-path", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "Med attribute\n" + "As-path attribute\n"); + +ALIAS (neighbor_attr_unchanged, + neighbor_attr_unchanged8_cmd, + NEIGHBOR_CMD2 "attribute-unchanged next-hop as-path med", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "As-path attribute\n" + "Med attribute\n"); + +ALIAS (neighbor_attr_unchanged, + neighbor_attr_unchanged9_cmd, + NEIGHBOR_CMD2 "attribute-unchanged med next-hop as-path", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "Nexthop attribute\n" + "As-path attribute\n"); + +ALIAS (neighbor_attr_unchanged, + neighbor_attr_unchanged10_cmd, + NEIGHBOR_CMD2 "attribute-unchanged med as-path next-hop", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "As-path attribute\n" + "Nexthop attribute\n"); + +DEFUN (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n") +{ + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + (PEER_FLAG_AS_PATH_UNCHANGED | + PEER_FLAG_NEXTHOP_UNCHANGED | + PEER_FLAG_MED_UNCHANGED)); +} + +DEFUN (no_neighbor_attr_unchanged1, + no_neighbor_attr_unchanged1_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged (as-path|next-hop|med)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") +{ + u_int16_t flags = 0; + + if (strncmp (argv[1], "as-path", 1) == 0) + SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); + else if (strncmp (argv[1], "next-hop", 1) == 0) + SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + else if (strncmp (argv[1], "med", 1) == 0) + SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +DEFUN (no_neighbor_attr_unchanged2, + no_neighbor_attr_unchanged2_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged as-path (next-hop|med)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") +{ + u_int16_t flags = PEER_FLAG_AS_PATH_UNCHANGED; + + if (strncmp (argv[1], "next-hop", 1) == 0) + SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + else if (strncmp (argv[1], "med", 1) == 0) + SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +DEFUN (no_neighbor_attr_unchanged3, + no_neighbor_attr_unchanged3_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop (as-path|med)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "As-path attribute\n" + "Med attribute\n") +{ + u_int16_t flags = PEER_FLAG_NEXTHOP_UNCHANGED; + + if (strncmp (argv[1], "as-path", 1) == 0) + SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); + else if (strncmp (argv[1], "med", 1) == 0) + SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +DEFUN (no_neighbor_attr_unchanged4, + no_neighbor_attr_unchanged4_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged med (as-path|next-hop)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "As-path attribute\n" + "Nexthop attribute\n") +{ + u_int16_t flags = PEER_FLAG_MED_UNCHANGED; + + if (strncmp (argv[1], "as-path", 1) == 0) + SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); + else if (strncmp (argv[1], "next-hop", 1) == 0) + SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + + return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), flags); +} + +ALIAS (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged5_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged as-path next-hop med", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n"); + +ALIAS (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged6_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged as-path med next-hop", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Med attribute\n" + "Nexthop attribute\n"); + +ALIAS (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged7_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop med as-path", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "Med attribute\n" + "As-path attribute\n"); + +ALIAS (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged8_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop as-path med", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "As-path attribute\n" + "Med attribute\n"); + +ALIAS (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged9_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged med next-hop as-path", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "Nexthop attribute\n" + "As-path attribute\n"); + +ALIAS (no_neighbor_attr_unchanged, + no_neighbor_attr_unchanged10_cmd, + NO_NEIGHBOR_CMD2 "attribute-unchanged med as-path next-hop", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "As-path attribute\n" + "Nexthop attribute\n"); + +/* EBGP multihop configuration. */ +int +peer_ebgp_multihop_set_vty (struct vty *vty, char *ip_str, char *ttl_str) +{ + struct peer *peer; + int ttl; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + if (! ttl_str) + ttl = TTL_MAX; + else + VTY_GET_INTEGER_RANGE ("TTL", ttl, ttl_str, 1, 255); + + peer_ebgp_multihop_set (peer, ttl); + + return CMD_SUCCESS; +} + +int +peer_ebgp_multihop_unset_vty (struct vty *vty, char *ip_str) +{ + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + peer_ebgp_multihop_unset (peer); + + return CMD_SUCCESS; +} + +/* neighbor ebgp-multihop. */ +DEFUN (neighbor_ebgp_multihop, + neighbor_ebgp_multihop_cmd, + NEIGHBOR_CMD2 "ebgp-multihop", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Allow EBGP neighbors not on directly connected networks\n") +{ + return peer_ebgp_multihop_set_vty (vty, argv[0], NULL); +} + +DEFUN (neighbor_ebgp_multihop_ttl, + neighbor_ebgp_multihop_ttl_cmd, + NEIGHBOR_CMD2 "ebgp-multihop <1-255>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Allow EBGP neighbors not on directly connected networks\n" + "maximum hop count\n") +{ + return peer_ebgp_multihop_set_vty (vty, argv[0], argv[1]); +} + +DEFUN (no_neighbor_ebgp_multihop, + no_neighbor_ebgp_multihop_cmd, + NO_NEIGHBOR_CMD2 "ebgp-multihop", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Allow EBGP neighbors not on directly connected networks\n") +{ + return peer_ebgp_multihop_unset_vty (vty, argv[0]); +} + +ALIAS (no_neighbor_ebgp_multihop, + no_neighbor_ebgp_multihop_ttl_cmd, + NO_NEIGHBOR_CMD2 "ebgp-multihop <1-255>", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Allow EBGP neighbors not on directly connected networks\n" + "maximum hop count\n"); + +/* disable-connected-check */ +DEFUN (neighbor_disable_connected_check, + neighbor_disable_connected_check_cmd, + NEIGHBOR_CMD2 "disable-connected-check", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "one-hop away EBGP peer using loopback address\n") +{ + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_DISABLE_CONNECTED_CHECK); +} + +DEFUN (no_neighbor_disable_connected_check, + no_neighbor_disable_connected_check_cmd, + NO_NEIGHBOR_CMD2 "disable-connected-check", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "one-hop away EBGP peer using loopback address\n") +{ + return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DISABLE_CONNECTED_CHECK); +} + +/* Enforce multihop. */ +ALIAS (neighbor_disable_connected_check, + neighbor_enforce_multihop_cmd, + NEIGHBOR_CMD2 "enforce-multihop", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Enforce EBGP neighbors perform multihop\n"); + +DEFUN (neighbor_description, + neighbor_description_cmd, + NEIGHBOR_CMD2 "description .LINE", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Neighbor specific description\n" + "Up to 80 characters describing this neighbor\n") +{ + struct peer *peer; + struct buffer *b; + char *str; + int i; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + if (argc == 1) + return CMD_SUCCESS; + + /* Make string from buffer. This function should be provided by + buffer.c. */ + b = buffer_new (1024); + for (i = 1; i < argc; i++) + { + buffer_putstr (b, (u_char *)argv[i]); + buffer_putc (b, ' '); + } + buffer_putc (b, '\0'); + str = buffer_getstr (b); + buffer_free (b); + + peer_description_set (peer, str); + + free (str); + + return CMD_SUCCESS; +} + +DEFUN (no_neighbor_description, + no_neighbor_description_cmd, + NO_NEIGHBOR_CMD2 "description", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Neighbor specific description\n") +{ + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + peer_description_unset (peer); + + return CMD_SUCCESS; +} + +ALIAS (no_neighbor_description, + no_neighbor_description_val_cmd, + NO_NEIGHBOR_CMD2 "description .LINE", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Neighbor specific description\n" + "Up to 80 characters describing this neighbor\n"); + +/* Neighbor update-source. */ +int +peer_update_source_vty (struct vty *vty, char *peer_str, char *source_str) +{ + struct peer *peer; + union sockunion *su; + + peer = peer_and_group_lookup_vty (vty, peer_str); + if (! peer) + return CMD_WARNING; + + if (source_str) + { + su = sockunion_str2su (source_str); + if (su) + { + peer_update_source_addr_set (peer, su); + sockunion_free (su); + } + else + peer_update_source_if_set (peer, source_str); + } + else + peer_update_source_unset (peer); + + return CMD_SUCCESS; +} + +DEFUN (neighbor_update_source, + neighbor_update_source_cmd, + NEIGHBOR_CMD2 "update-source WORD", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Source of routing updates\n" + "Interface name\n") +{ + return peer_update_source_vty (vty, argv[0], argv[1]); +} + +DEFUN (no_neighbor_update_source, + no_neighbor_update_source_cmd, + NO_NEIGHBOR_CMD2 "update-source", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Source of routing updates\n" + "Interface name\n") +{ + return peer_update_source_vty (vty, argv[0], NULL); +} + +int +peer_default_originate_set_vty (struct vty *vty, char *peer_str, afi_t afi, + safi_t safi, char *rmap, int set) +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, peer_str); + if (! peer) + return CMD_WARNING; + + if (set) + ret = peer_default_originate_set (peer, afi, safi, rmap); + else + ret = peer_default_originate_unset (peer, afi, safi); + + return bgp_vty_return (vty, ret); +} + +/* neighbor default-originate. */ +DEFUN (neighbor_default_originate, + neighbor_default_originate_cmd, + NEIGHBOR_CMD2 "default-originate", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Originate default route to this neighbor\n") +{ + return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), NULL, 1); +} + +DEFUN (neighbor_default_originate_rmap, + neighbor_default_originate_rmap_cmd, + NEIGHBOR_CMD2 "default-originate route-map WORD", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Originate default route to this neighbor\n" + "Route-map to specify criteria to originate default\n" + "route-map name\n") +{ + return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], 1); +} + +DEFUN (no_neighbor_default_originate, + no_neighbor_default_originate_cmd, + NO_NEIGHBOR_CMD2 "default-originate", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Originate default route to this neighbor\n") +{ + return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), NULL, 0); +} + +ALIAS (no_neighbor_default_originate, + no_neighbor_default_originate_rmap_cmd, + NO_NEIGHBOR_CMD2 "default-originate route-map WORD", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Originate default route to this neighbor\n" + "Route-map to specify criteria to originate default\n" + "route-map name\n"); + +/* Set neighbor's BGP port. */ +int +peer_port_vty (struct vty *vty, char *ip_str, int afi, char *port_str) +{ + struct peer *peer; + u_int16_t port; + struct servent *sp; + + peer = peer_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + if (! port_str) + { + sp = getservbyname ("bgp", "tcp"); + port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port); + } + else + { + VTY_GET_INTEGER("port", port, port_str); + } + + peer_port_set (peer, port); + + return CMD_SUCCESS; +} + +/* Set specified peer's BGP port. */ +DEFUN (neighbor_port, + neighbor_port_cmd, + NEIGHBOR_CMD "port <0-65535>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Neighbor's BGP port\n" + "TCP port number\n") +{ + return peer_port_vty (vty, argv[0], AFI_IP, argv[1]); +} + +DEFUN (no_neighbor_port, + no_neighbor_port_cmd, + NO_NEIGHBOR_CMD "port", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Neighbor's BGP port\n") +{ + return peer_port_vty (vty, argv[0], AFI_IP, NULL); +} + +ALIAS (no_neighbor_port, + no_neighbor_port_val_cmd, + NO_NEIGHBOR_CMD "port <0-65535>", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Neighbor's BGP port\n" + "TCP port number\n"); + +/* neighbor weight. */ +int +peer_weight_set_vty (struct vty *vty, char *ip_str, char *weight_str, + afi_t afi, safi_t safi) +{ + int ret; + struct peer *peer; + u_int16_t weight; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + VTY_GET_INTEGER_RANGE("weight", weight, weight_str, 0, 65535); + + ret = peer_weight_set (peer, weight, afi, safi); + + return CMD_SUCCESS; +} + +int +peer_weight_unset_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi) +{ + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + peer_weight_unset (peer, afi, safi); + + return CMD_SUCCESS; +} + +DEFUN (neighbor_weight, + neighbor_weight_cmd, + NEIGHBOR_CMD2 "weight <0-65535>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Set default weight for routes from this neighbor\n" + "default weight\n") +{ + return peer_weight_set_vty (vty, argv[0], argv[1], bgp_node_afi (vty), + bgp_node_safi (vty)); +} + +DEFUN (no_neighbor_weight, + no_neighbor_weight_cmd, + NO_NEIGHBOR_CMD2 "weight", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Set default weight for routes from this neighbor\n") +{ + return peer_weight_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty)); +} + +ALIAS (no_neighbor_weight, + no_neighbor_weight_val_cmd, + NO_NEIGHBOR_CMD2 "weight <0-65535>", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Set default weight for routes from this neighbor\n" + "default weight\n"); + +/* Override capability negotiation. */ +DEFUN (neighbor_override_capability, + neighbor_override_capability_cmd, + NEIGHBOR_CMD2 "override-capability", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Override capability negotiation result\n") +{ + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_OVERRIDE_CAPABILITY); +} + +DEFUN (no_neighbor_override_capability, + no_neighbor_override_capability_cmd, + NO_NEIGHBOR_CMD2 "override-capability", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Override capability negotiation result\n") +{ + return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_OVERRIDE_CAPABILITY); +} + +DEFUN (neighbor_strict_capability, + neighbor_strict_capability_cmd, + NEIGHBOR_CMD "strict-capability-match", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Strict capability negotiation match\n") +{ + return peer_flag_set_vty (vty, argv[0], PEER_FLAG_STRICT_CAP_MATCH); +} + +DEFUN (no_neighbor_strict_capability, + no_neighbor_strict_capability_cmd, + NO_NEIGHBOR_CMD "strict-capability-match", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Strict capability negotiation match\n") +{ + return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_STRICT_CAP_MATCH); +} + +int +peer_timers_set_vty (struct vty *vty, char *ip_str, char *keep_str, + char *hold_str) +{ + int ret; + struct peer *peer; + u_int32_t keepalive; + u_int32_t holdtime; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + VTY_GET_INTEGER_RANGE ("Keepalive", keepalive, keep_str, 0, 65535); + VTY_GET_INTEGER_RANGE ("Holdtime", holdtime, hold_str, 0, 65535); + + ret = peer_timers_set (peer, keepalive, holdtime); + + return bgp_vty_return (vty, ret); +} + +int +peer_timers_unset_vty (struct vty *vty, char *ip_str) +{ + int ret; + struct peer *peer; + + peer = peer_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + ret = peer_timers_unset (peer); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_timers, + neighbor_timers_cmd, + NEIGHBOR_CMD2 "timers <0-65535> <0-65535>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP per neighbor timers\n" + "Keepalive interval\n" + "Holdtime\n") +{ + return peer_timers_set_vty (vty, argv[0], argv[1], argv[2]); +} + +DEFUN (no_neighbor_timers, + no_neighbor_timers_cmd, + NO_NEIGHBOR_CMD2 "timers", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BGP per neighbor timers\n") +{ + return peer_timers_unset_vty (vty, argv[0]); +} + +int +peer_advertise_interval_vty (struct vty *vty, char *ip_str, char *time_str, + int set) +{ + int ret; + struct peer *peer; + u_int32_t routeadv = 0; + + peer = peer_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + if (time_str) + VTY_GET_INTEGER_RANGE ("advertise interval", routeadv, time_str, 0, 600); + + if (set) + ret = peer_advertise_interval_set (peer, routeadv); + else + ret = peer_advertise_interval_unset (peer); + + return CMD_SUCCESS; +} + +DEFUN (neighbor_advertise_interval, + neighbor_advertise_interval_cmd, + NEIGHBOR_CMD "advertisement-interval <0-600>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Minimum interval between sending BGP routing updates\n" + "time in seconds\n") +{ + return peer_advertise_interval_vty (vty, argv[0], argv[1], 1); +} + +DEFUN (no_neighbor_advertise_interval, + no_neighbor_advertise_interval_cmd, + NO_NEIGHBOR_CMD "advertisement-interval", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Minimum interval between sending BGP routing updates\n") +{ + return peer_advertise_interval_vty (vty, argv[0], NULL, 0); +} + +ALIAS (no_neighbor_advertise_interval, + no_neighbor_advertise_interval_val_cmd, + NO_NEIGHBOR_CMD "advertisement-interval <0-600>", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Minimum interval between sending BGP routing updates\n" + "time in seconds\n"); + +/* neighbor interface */ +int +peer_interface_vty (struct vty *vty, char *ip_str, char *str) +{ + int ret; + struct peer *peer; + + peer = peer_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + if (str) + ret = peer_interface_set (peer, str); + else + ret = peer_interface_unset (peer); + + return CMD_SUCCESS; +} + +DEFUN (neighbor_interface, + neighbor_interface_cmd, + NEIGHBOR_CMD "interface WORD", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Interface\n" + "Interface name\n") +{ + return peer_interface_vty (vty, argv[0], argv[1]); +} + +DEFUN (no_neighbor_interface, + no_neighbor_interface_cmd, + NO_NEIGHBOR_CMD "interface WORD", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR + "Interface\n" + "Interface name\n") +{ + return peer_interface_vty (vty, argv[0], NULL); +} + +/* Set distribute list to the peer. */ +int +peer_distribute_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, + char *name_str, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_distribute_set (peer, afi, safi, direct, name_str); + + return bgp_vty_return (vty, ret); +} + +int +peer_distribute_unset_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_distribute_unset (peer, afi, safi, direct); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_distribute_list, + neighbor_distribute_list_cmd, + NEIGHBOR_CMD2 "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Filter updates to/from this neighbor\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n" + "Filter incoming updates\n" + "Filter outgoing updates\n") +{ + return peer_distribute_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], argv[2]); +} + +DEFUN (no_neighbor_distribute_list, + no_neighbor_distribute_list_cmd, + NO_NEIGHBOR_CMD2 "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Filter updates to/from this neighbor\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n" + "Filter incoming updates\n" + "Filter outgoing updates\n") +{ + return peer_distribute_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[2]); +} + +/* Set prefix list to the peer. */ +int +peer_prefix_list_set_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, char *name_str, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_prefix_list_set (peer, afi, safi, direct, name_str); + + return bgp_vty_return (vty, ret); +} + +int +peer_prefix_list_unset_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_prefix_list_unset (peer, afi, safi, direct); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_prefix_list, + neighbor_prefix_list_cmd, + NEIGHBOR_CMD2 "prefix-list WORD (in|out)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Filter updates to/from this neighbor\n" + "Name of a prefix list\n" + "Filter incoming updates\n" + "Filter outgoing updates\n") +{ + return peer_prefix_list_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], argv[2]); +} + +DEFUN (no_neighbor_prefix_list, + no_neighbor_prefix_list_cmd, + NO_NEIGHBOR_CMD2 "prefix-list WORD (in|out)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Filter updates to/from this neighbor\n" + "Name of a prefix list\n" + "Filter incoming updates\n" + "Filter outgoing updates\n") +{ + return peer_prefix_list_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[2]); +} + +int +peer_aslist_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, + char *name_str, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_aslist_set (peer, afi, safi, direct, name_str); + + return bgp_vty_return (vty, ret); +} + +int +peer_aslist_unset_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, + char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_aslist_unset (peer, afi, safi, direct); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_filter_list, + neighbor_filter_list_cmd, + NEIGHBOR_CMD2 "filter-list WORD (in|out)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Establish BGP filters\n" + "AS path access-list name\n" + "Filter incoming routes\n" + "Filter outgoing routes\n") +{ + return peer_aslist_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], argv[2]); +} + +DEFUN (no_neighbor_filter_list, + no_neighbor_filter_list_cmd, + NO_NEIGHBOR_CMD2 "filter-list WORD (in|out)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Establish BGP filters\n" + "AS path access-list name\n" + "Filter incoming routes\n" + "Filter outgoing routes\n") +{ + return peer_aslist_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[2]); +} + +/* Set route-map to the peer. */ +int +peer_route_map_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, + char *name_str, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = FILTER_OUT; + + ret = peer_route_map_set (peer, afi, safi, direct, name_str); + + return bgp_vty_return (vty, ret); +} + +int +peer_route_map_unset_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, char *direct_str) +{ + int ret; + struct peer *peer; + int direct = FILTER_IN; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + /* Check filter direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = FILTER_IN; + else if (strncmp (direct_str, "o", 1) == 0) + + direct = FILTER_OUT; + + ret = peer_route_map_unset (peer, afi, safi, direct); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_route_map, + neighbor_route_map_cmd, + NEIGHBOR_CMD2 "route-map WORD (in|out)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Apply route map to neighbor\n" + "Name of route map\n" + "Apply map to incoming routes\n" + "Apply map to outbound routes\n") +{ + return peer_route_map_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], argv[2]); +} + +DEFUN (no_neighbor_route_map, + no_neighbor_route_map_cmd, + NO_NEIGHBOR_CMD2 "route-map WORD (in|out)", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Apply route map to neighbor\n" + "Name of route map\n" + "Apply map to incoming routes\n" + "Apply map to outbound routes\n") +{ + return peer_route_map_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[2]); +} + +/* Set unsuppress-map to the peer. */ +int +peer_unsuppress_map_set_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, char *name_str) +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + ret = peer_unsuppress_map_set (peer, afi, safi, name_str); + + return bgp_vty_return (vty, ret); +} + +/* Unset route-map from the peer. */ +int +peer_unsuppress_map_unset_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi) +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + ret = peer_unsuppress_map_unset (peer, afi, safi); + + return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_unsuppress_map, + neighbor_unsuppress_map_cmd, + NEIGHBOR_CMD2 "unsuppress-map WORD", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Route-map to selectively unsuppress suppressed routes\n" + "Name of route map\n") +{ + return peer_unsuppress_map_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1]); +} + +DEFUN (no_neighbor_unsuppress_map, + no_neighbor_unsuppress_map_cmd, + NO_NEIGHBOR_CMD2 "unsuppress-map WORD", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Route-map to selectively unsuppress suppressed routes\n" + "Name of route map\n") +{ + return peer_unsuppress_map_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty)); +} + +int +peer_maximum_prefix_set_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi, char *num_str, char *threshold_str, + int warning, char *restart_str) +{ + int ret; + struct peer *peer; + u_int32_t max; + u_char threshold; + u_int16_t restart; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + VTY_GET_INTEGER ("maxmum number", max, num_str); + if (threshold_str) + threshold = atoi (threshold_str); + else + threshold = MAXIMUM_PREFIX_THRESHOLD_DEFAULT; + + if (restart_str) + restart = atoi (restart_str); + else + restart = 0; + + ret = peer_maximum_prefix_set (peer, afi, safi, max, threshold, warning, restart); + + return bgp_vty_return (vty, ret); +} + +int +peer_maximum_prefix_unset_vty (struct vty *vty, char *ip_str, afi_t afi, + safi_t safi) +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, ip_str); + if (! peer) + return CMD_WARNING; + + ret = peer_maximum_prefix_unset (peer, afi, safi); + + return bgp_vty_return (vty, ret); +} + +/* Maximum number of prefix configuration. prefix count is different + for each peer configuration. So this configuration can be set for + each peer configuration. */ +DEFUN (neighbor_maximum_prefix, + neighbor_maximum_prefix_cmd, + NEIGHBOR_CMD2 "maximum-prefix <1-4294967295>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n") +{ + return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], NULL, 0 ,NULL); +} + +DEFUN (neighbor_maximum_prefix_threshold, + neighbor_maximum_prefix_threshold_cmd, + NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> <1-100>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Threshold value (%) at which to generate a warning msg\n") +{ + return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], argv[2], 0, NULL); +} + +DEFUN (neighbor_maximum_prefix_warning, + neighbor_maximum_prefix_warning_cmd, + NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> warning-only", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Only give warning message when limit is exceeded\n") +{ + return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], NULL, 1, NULL); +} + +DEFUN (neighbor_maximum_prefix_threshold_warning, + neighbor_maximum_prefix_threshold_warning_cmd, + NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> <1-100> warning-only", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Threshold value (%) at which to generate a warning msg\n" + "Only give warning message when limit is exceeded\n") +{ + return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], argv[2], 1, NULL); +} + +DEFUN (neighbor_maximum_prefix_restart, + neighbor_maximum_prefix_restart_cmd, + NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> restart <1-65535>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Restart bgp connection after limit is exceeded\n" + "Restart interval in minutes") +{ + return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], NULL, 0, argv[2]); +} + +DEFUN (neighbor_maximum_prefix_threshold_restart, + neighbor_maximum_prefix_threshold_restart_cmd, + NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> <1-100> restart <1-65535>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Threshold value (%) at which to generate a warning msg\n" + "Restart bgp connection after limit is exceeded\n" + "Restart interval in minutes") +{ + return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), argv[1], argv[2], 0, argv[3]); +} + +DEFUN (no_neighbor_maximum_prefix, + no_neighbor_maximum_prefix_cmd, + NO_NEIGHBOR_CMD2 "maximum-prefix", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefix accept from this peer\n") +{ + return peer_maximum_prefix_unset_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty)); +} + +ALIAS (no_neighbor_maximum_prefix, + no_neighbor_maximum_prefix_val_cmd, + NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295>", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n"); + +ALIAS (no_neighbor_maximum_prefix, + no_neighbor_maximum_prefix_threshold_cmd, + NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> warning-only", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Threshold value (%) at which to generate a warning msg\n") + +ALIAS (no_neighbor_maximum_prefix, + no_neighbor_maximum_prefix_warning_cmd, + NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> warning-only", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Only give warning message when limit is exceeded\n"); + +ALIAS (no_neighbor_maximum_prefix, + no_neighbor_maximum_prefix_threshold_warning_cmd, + NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> <1-100> warning-only", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Threshold value (%) at which to generate a warning msg\n" + "Only give warning message when limit is exceeded\n"); + +ALIAS (no_neighbor_maximum_prefix, + no_neighbor_maximum_prefix_restart_cmd, + NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> restart <1-65535>", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Restart bgp connection after limit is exceeded\n" + "Restart interval in minutes") + +ALIAS (no_neighbor_maximum_prefix, + no_neighbor_maximum_prefix_threshold_restart_cmd, + NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> <1-100> restart <1-65535>", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Threshold value (%) at which to generate a warning msg\n" + "Restart bgp connection after limit is exceeded\n" + "Restart interval in minutes") + +/* "neighbor allowas-in" */ +DEFUN (neighbor_allowas_in, + neighbor_allowas_in_cmd, + NEIGHBOR_CMD2 "allowas-in", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Accept as-path with my AS present in it\n") +{ + int ret; + struct peer *peer; + int allow_num; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + if (argc == 1) + allow_num = 3; + else + VTY_GET_INTEGER_RANGE ("AS number", allow_num, argv[1], 1, 10); + + ret = peer_allowas_in_set (peer, bgp_node_afi (vty), bgp_node_safi (vty), + allow_num); + + return bgp_vty_return (vty, ret); +} + +ALIAS (neighbor_allowas_in, + neighbor_allowas_in_arg_cmd, + NEIGHBOR_CMD2 "allowas-in <1-10>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Accept as-path with my AS present in it\n" + "Number of occurances of AS number\n"); + +DEFUN (no_neighbor_allowas_in, + no_neighbor_allowas_in_cmd, + NO_NEIGHBOR_CMD2 "allowas-in", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "allow local ASN appears in aspath attribute\n") +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_allowas_in_unset (peer, bgp_node_afi (vty), bgp_node_safi (vty)); + + return bgp_vty_return (vty, ret); +} + +/* Address family configuration. */ +DEFUN (address_family_ipv4, + address_family_ipv4_cmd, + "address-family ipv4", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_IPV4_NODE; + return CMD_SUCCESS; +} + +DEFUN (address_family_ipv4_safi, + address_family_ipv4_safi_cmd, + "address-family ipv4 (unicast|multicast)", + "Enter Address Family command mode\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + vty->node = BGP_IPV4M_NODE; + else + vty->node = BGP_IPV4_NODE; + + return CMD_SUCCESS; +} + +DEFUN (address_family_ipv6_unicast, + address_family_ipv6_unicast_cmd, + "address-family ipv6 unicast", + "Enter Address Family command mode\n" + "Address family\n" + "unicast\n") +{ + vty->node = BGP_IPV6_NODE; + return CMD_SUCCESS; +} + +ALIAS (address_family_ipv6_unicast, + address_family_ipv6_cmd, + "address-family ipv6", + "Enter Address Family command mode\n" + "Address family\n"); + +DEFUN (address_family_vpnv4, + address_family_vpnv4_cmd, + "address-family vpnv4", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_VPNV4_NODE; + return CMD_SUCCESS; +} + +ALIAS (address_family_vpnv4, + address_family_vpnv4_unicast_cmd, + "address-family vpnv4 unicast", + "Enter Address Family command mode\n" + "Address family\n" + "Address Family Modifier\n"); + +DEFUN (exit_address_family, + exit_address_family_cmd, + "exit-address-family", + "Exit from Address Family configuration mode\n") +{ + if (vty->node == BGP_IPV4_NODE + || vty->node == BGP_IPV4M_NODE + || vty->node == BGP_VPNV4_NODE + || vty->node == BGP_IPV6_NODE) + vty->node = BGP_NODE; + return CMD_SUCCESS; +} + +/* BGP clear sort. */ +enum clear_sort + { + clear_all, + clear_peer, + clear_group, + clear_external, + clear_as + }; + +void +bgp_clear_vty_error (struct vty *vty, struct peer *peer, afi_t afi, + safi_t safi, int error) +{ + switch (error) + { + case BGP_ERR_AF_UNCONFIGURED: + vty_out (vty, + "%%BGP: Enable %s %s address family for the neighbor %s%s", + afi == AFI_IP6 ? "IPv6" : safi == SAFI_MPLS_VPN ? "VPNv4" : "IPv4", + safi == SAFI_MULTICAST ? "Multicast" : "Unicast", + peer->host, VTY_NEWLINE); + break; + case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED: + vty_out (vty, "%%BGP: Inbound soft reconfig for %s not possible as it%s has neither refresh capability, nor inbound soft reconfig%s", peer->host, VTY_NEWLINE, VTY_NEWLINE); + break; + default: + break; + } +} + +/* `clear ip bgp' functions. */ +int +bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, + enum clear_sort sort,enum bgp_clear_type stype, char *arg) +{ + int ret; + struct peer *peer; + struct listnode *nn; + + /* Clear all neighbors. */ + if (sort == clear_all) + { + LIST_LOOP (bgp->peer, peer, nn) + { + if (stype == BGP_CLEAR_SOFT_NONE) + ret = peer_clear (peer); + else + ret = peer_clear_soft (peer, afi, safi, stype); + + if (ret < 0) + bgp_clear_vty_error (vty, peer, afi, safi, ret); + } + return 0; + } + + /* Clear specified neighbors. */ + if (sort == clear_peer) + { + union sockunion su; + int ret; + + /* Make sockunion for lookup. */ + ret = str2sockunion (arg, &su); + if (ret < 0) + { + vty_out (vty, "Malformed address: %s%s", arg, VTY_NEWLINE); + return -1; + } + peer = peer_lookup (bgp, &su); + if (! peer) + { + vty_out (vty, "%%BGP: Unknown neighbor - \"%s\"%s", arg, VTY_NEWLINE); + return -1; + } + + if (stype == BGP_CLEAR_SOFT_NONE) + ret = peer_clear (peer); + else + ret = peer_clear_soft (peer, afi, safi, stype); + + if (ret < 0) + bgp_clear_vty_error (vty, peer, afi, safi, ret); + + return 0; + } + + /* Clear all peer-group members. */ + if (sort == clear_group) + { + struct peer_group *group; + + group = peer_group_lookup (bgp, arg); + if (! group) + { + vty_out (vty, "%%BGP: No such peer-group %s%s", arg, VTY_NEWLINE); + return -1; + } + + LIST_LOOP (group->peer, peer, nn) + { + if (stype == BGP_CLEAR_SOFT_NONE) + { + ret = peer_clear (peer); + continue; + } + + ret = peer_clear_soft (peer, afi, safi, stype); + + if (ret < 0) + bgp_clear_vty_error (vty, peer, afi, safi, ret); + } + return 0; + } + + if (sort == clear_external) + { + LIST_LOOP (bgp->peer, peer, nn) + { + if (peer_sort (peer) == BGP_PEER_IBGP) + continue; + + if (stype == BGP_CLEAR_SOFT_NONE) + ret = peer_clear (peer); + else + ret = peer_clear_soft (peer, afi, safi, stype); + + if (ret < 0) + bgp_clear_vty_error (vty, peer, afi, safi, ret); + } + return 0; + } + + if (sort == clear_as) + { + as_t as; + unsigned long as_ul; + char *endptr = NULL; + int find = 0; + + as_ul = strtoul(arg, &endptr, 10); + + if ((as_ul == ULONG_MAX) || (*endptr != '\0') || (as_ul > USHRT_MAX)) + { + vty_out (vty, "Invalid AS number%s", VTY_NEWLINE); + return -1; + } + as = (as_t) as_ul; + + LIST_LOOP (bgp->peer, peer, nn) + { + if (peer->as != as) + continue; + + find = 1; + if (stype == BGP_CLEAR_SOFT_NONE) + ret = peer_clear (peer); + else + ret = peer_clear_soft (peer, afi, safi, stype); + + if (ret < 0) + bgp_clear_vty_error (vty, peer, afi, safi, ret); + } + if (! find) + vty_out (vty, "%%BGP: No peer is configured with AS %s%s", arg, + VTY_NEWLINE); + return 0; + } + + return 0; +} + +int +bgp_clear_vty (struct vty *vty, char *name, afi_t afi, safi_t safi, + enum clear_sort sort, enum bgp_clear_type stype, char *arg) +{ + int ret; + struct bgp *bgp; + + /* BGP structure lookup. */ + if (name) + { + bgp = bgp_lookup_by_name (name); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", name, VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + ret = bgp_clear (vty, bgp, afi, safi, sort, stype, arg); + if (ret < 0) + return CMD_WARNING; + + return CMD_SUCCESS; +} + +DEFUN (clear_ip_bgp_all, + clear_ip_bgp_all_cmd, + "clear ip bgp *", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], 0, 0, clear_all, BGP_CLEAR_SOFT_NONE, NULL); + + return bgp_clear_vty (vty, NULL, 0, 0, clear_all, BGP_CLEAR_SOFT_NONE, NULL); +} + +ALIAS (clear_ip_bgp_all, + clear_bgp_all_cmd, + "clear bgp *", + CLEAR_STR + BGP_STR + "Clear all peers\n"); + +ALIAS (clear_ip_bgp_all, + clear_bgp_ipv6_all_cmd, + "clear bgp ipv6 *", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n"); + +ALIAS (clear_ip_bgp_all, + clear_ip_bgp_instance_all_cmd, + "clear ip bgp view WORD *", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n"); + +ALIAS (clear_ip_bgp_all, + clear_bgp_instance_all_cmd, + "clear bgp view WORD *", + CLEAR_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n"); + +DEFUN (clear_ip_bgp_peer, + clear_ip_bgp_peer_cmd, + "clear ip bgp (A.B.C.D|X:X::X:X)", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor IP address to clear\n" + "BGP IPv6 neighbor to clear\n") +{ + return bgp_clear_vty (vty, NULL, 0, 0, clear_peer, BGP_CLEAR_SOFT_NONE, argv[0]); +} + +ALIAS (clear_ip_bgp_peer, + clear_bgp_peer_cmd, + "clear bgp (A.B.C.D|X:X::X:X)", + CLEAR_STR + BGP_STR + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n"); + +ALIAS (clear_ip_bgp_peer, + clear_bgp_ipv6_peer_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X)", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n"); + +DEFUN (clear_ip_bgp_peer_group, + clear_ip_bgp_peer_group_cmd, + "clear ip bgp peer-group WORD", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n") +{ + return bgp_clear_vty (vty, NULL, 0, 0, clear_group, BGP_CLEAR_SOFT_NONE, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group, + clear_bgp_peer_group_cmd, + "clear bgp peer-group WORD", + CLEAR_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n"); + +ALIAS (clear_ip_bgp_peer_group, + clear_bgp_ipv6_peer_group_cmd, + "clear bgp ipv6 peer-group WORD", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n"); + +DEFUN (clear_ip_bgp_external, + clear_ip_bgp_external_cmd, + "clear ip bgp external", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n") +{ + return bgp_clear_vty (vty, NULL, 0, 0, clear_external, BGP_CLEAR_SOFT_NONE, NULL); +} + +ALIAS (clear_ip_bgp_external, + clear_bgp_external_cmd, + "clear bgp external", + CLEAR_STR + BGP_STR + "Clear all external peers\n"); + +ALIAS (clear_ip_bgp_external, + clear_bgp_ipv6_external_cmd, + "clear bgp ipv6 external", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all external peers\n"); + +DEFUN (clear_ip_bgp_as, + clear_ip_bgp_as_cmd, + "clear ip bgp <1-65535>", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n") +{ + return bgp_clear_vty (vty, NULL, 0, 0, clear_as, BGP_CLEAR_SOFT_NONE, argv[0]); +} + +ALIAS (clear_ip_bgp_as, + clear_bgp_as_cmd, + "clear bgp <1-65535>", + CLEAR_STR + BGP_STR + "Clear peers with the AS number\n"); + +ALIAS (clear_ip_bgp_as, + clear_bgp_ipv6_as_cmd, + "clear bgp ipv6 <1-65535>", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear peers with the AS number\n"); + +/* Outbound soft-reconfiguration */ +DEFUN (clear_ip_bgp_all_soft_out, + clear_ip_bgp_all_soft_out_cmd, + "clear ip bgp * soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_all_soft_out, + clear_ip_bgp_all_out_cmd, + "clear ip bgp * out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig outbound update\n"); + +ALIAS (clear_ip_bgp_all_soft_out, + clear_ip_bgp_instance_all_soft_out_cmd, + "clear ip bgp view WORD * soft out", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_ip_bgp_all_ipv4_soft_out, + clear_ip_bgp_all_ipv4_soft_out_cmd, + "clear ip bgp * ipv4 (unicast|multicast) soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_all_ipv4_soft_out, + clear_ip_bgp_all_ipv4_out_cmd, + "clear ip bgp * ipv4 (unicast|multicast) out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_ip_bgp_instance_all_ipv4_soft_out, + clear_ip_bgp_instance_all_ipv4_soft_out_cmd, + "clear ip bgp view WORD * ipv4 (unicast|multicast) soft out", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); + + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); +} + +DEFUN (clear_ip_bgp_all_vpnv4_soft_out, + clear_ip_bgp_all_vpnv4_soft_out_cmd, + "clear ip bgp * vpnv4 unicast soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_all_vpnv4_soft_out, + clear_ip_bgp_all_vpnv4_out_cmd, + "clear ip bgp * vpnv4 unicast out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_bgp_all_soft_out, + clear_bgp_all_soft_out_cmd, + "clear bgp * soft out", + CLEAR_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_bgp_all_soft_out, + clear_bgp_instance_all_soft_out_cmd, + "clear bgp view WORD * soft out", + CLEAR_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n"); + +ALIAS (clear_bgp_all_soft_out, + clear_bgp_all_out_cmd, + "clear bgp * out", + CLEAR_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig outbound update\n"); + +ALIAS (clear_bgp_all_soft_out, + clear_bgp_ipv6_all_soft_out_cmd, + "clear bgp ipv6 * soft out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n"); + +ALIAS (clear_bgp_all_soft_out, + clear_bgp_ipv6_all_out_cmd, + "clear bgp ipv6 * out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_ip_bgp_peer_soft_out, + clear_ip_bgp_peer_soft_out_cmd, + "clear ip bgp A.B.C.D soft out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_soft_out, + clear_ip_bgp_peer_out_cmd, + "clear ip bgp A.B.C.D out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_ip_bgp_peer_ipv4_soft_out, + clear_ip_bgp_peer_ipv4_soft_out_cmd, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, + BGP_CLEAR_SOFT_OUT, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_ipv4_soft_out, + clear_ip_bgp_peer_ipv4_out_cmd, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_ip_bgp_peer_vpnv4_soft_out, + clear_ip_bgp_peer_vpnv4_soft_out_cmd, + "clear ip bgp A.B.C.D vpnv4 unicast soft out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_vpnv4_soft_out, + clear_ip_bgp_peer_vpnv4_out_cmd, + "clear ip bgp A.B.C.D vpnv4 unicast out", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_bgp_peer_soft_out, + clear_bgp_peer_soft_out_cmd, + "clear bgp (A.B.C.D|X:X::X:X) soft out", + CLEAR_STR + BGP_STR + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_bgp_peer_soft_out, + clear_bgp_ipv6_peer_soft_out_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft out", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n"); + +ALIAS (clear_bgp_peer_soft_out, + clear_bgp_peer_out_cmd, + "clear bgp (A.B.C.D|X:X::X:X) out", + CLEAR_STR + BGP_STR + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig outbound update\n"); + +ALIAS (clear_bgp_peer_soft_out, + clear_bgp_ipv6_peer_out_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) out", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_ip_bgp_peer_group_soft_out, + clear_ip_bgp_peer_group_soft_out_cmd, + "clear ip bgp peer-group WORD soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group_soft_out, + clear_ip_bgp_peer_group_out_cmd, + "clear ip bgp peer-group WORD out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_ip_bgp_peer_group_ipv4_soft_out, + clear_ip_bgp_peer_group_ipv4_soft_out_cmd, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, + BGP_CLEAR_SOFT_OUT, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group_ipv4_soft_out, + clear_ip_bgp_peer_group_ipv4_out_cmd, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_bgp_peer_group_soft_out, + clear_bgp_peer_group_soft_out_cmd, + "clear bgp peer-group WORD soft out", + CLEAR_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_bgp_peer_group_soft_out, + clear_bgp_ipv6_peer_group_soft_out_cmd, + "clear bgp ipv6 peer-group WORD soft out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n"); + +ALIAS (clear_bgp_peer_group_soft_out, + clear_bgp_peer_group_out_cmd, + "clear bgp peer-group WORD out", + CLEAR_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig outbound update\n"); + +ALIAS (clear_bgp_peer_group_soft_out, + clear_bgp_ipv6_peer_group_out_cmd, + "clear bgp ipv6 peer-group WORD out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_ip_bgp_external_soft_out, + clear_ip_bgp_external_soft_out_cmd, + "clear ip bgp external soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_external_soft_out, + clear_ip_bgp_external_out_cmd, + "clear ip bgp external out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_ip_bgp_external_ipv4_soft_out, + clear_ip_bgp_external_ipv4_soft_out_cmd, + "clear ip bgp external ipv4 (unicast|multicast) soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, + BGP_CLEAR_SOFT_OUT, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_external_ipv4_soft_out, + clear_ip_bgp_external_ipv4_out_cmd, + "clear ip bgp external ipv4 (unicast|multicast) out", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_bgp_external_soft_out, + clear_bgp_external_soft_out_cmd, + "clear bgp external soft out", + CLEAR_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_bgp_external_soft_out, + clear_bgp_ipv6_external_soft_out_cmd, + "clear bgp ipv6 external soft out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n"); + +ALIAS (clear_bgp_external_soft_out, + clear_bgp_external_out_cmd, + "clear bgp external out", + CLEAR_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig outbound update\n"); + +ALIAS (clear_bgp_external_soft_out, + clear_bgp_ipv6_external_out_cmd, + "clear bgp ipv6 external WORD out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all external peers\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_ip_bgp_as_soft_out, + clear_ip_bgp_as_soft_out_cmd, + "clear ip bgp <1-65535> soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_as_soft_out, + clear_ip_bgp_as_out_cmd, + "clear ip bgp <1-65535> out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_ip_bgp_as_ipv4_soft_out, + clear_ip_bgp_as_ipv4_soft_out_cmd, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, + BGP_CLEAR_SOFT_OUT, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_as_ipv4_soft_out, + clear_ip_bgp_as_ipv4_out_cmd, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_ip_bgp_as_vpnv4_soft_out, + clear_ip_bgp_as_vpnv4_soft_out_cmd, + "clear ip bgp <1-65535> vpnv4 unicast soft out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_as_vpnv4_soft_out, + clear_ip_bgp_as_vpnv4_out_cmd, + "clear ip bgp <1-65535> vpnv4 unicast out", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n"); + +DEFUN (clear_bgp_as_soft_out, + clear_bgp_as_soft_out_cmd, + "clear bgp <1-65535> soft out", + CLEAR_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_bgp_as_soft_out, + clear_bgp_ipv6_as_soft_out_cmd, + "clear bgp ipv6 <1-65535> soft out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n"); + +ALIAS (clear_bgp_as_soft_out, + clear_bgp_as_out_cmd, + "clear bgp <1-65535> out", + CLEAR_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig outbound update\n"); + +ALIAS (clear_bgp_as_soft_out, + clear_bgp_ipv6_as_out_cmd, + "clear bgp ipv6 <1-65535> out", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig outbound update\n"); + +/* Inbound soft-reconfiguration */ +DEFUN (clear_ip_bgp_all_soft_in, + clear_ip_bgp_all_soft_in_cmd, + "clear ip bgp * soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_all_soft_in, + clear_ip_bgp_instance_all_soft_in_cmd, + "clear ip bgp view WORD * soft in", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n"); + +ALIAS (clear_ip_bgp_all_soft_in, + clear_ip_bgp_all_in_cmd, + "clear ip bgp * in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_ip_bgp_all_in_prefix_filter, + clear_ip_bgp_all_in_prefix_filter_cmd, + "clear ip bgp * in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + if (argc== 1) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +ALIAS (clear_ip_bgp_all_in_prefix_filter, + clear_ip_bgp_instance_all_in_prefix_filter_cmd, + "clear ip bgp view WORD * in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n"); + + +DEFUN (clear_ip_bgp_all_ipv4_soft_in, + clear_ip_bgp_all_ipv4_soft_in_cmd, + "clear ip bgp * ipv4 (unicast|multicast) soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_all_ipv4_soft_in, + clear_ip_bgp_all_ipv4_in_cmd, + "clear ip bgp * ipv4 (unicast|multicast) in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_ip_bgp_instance_all_ipv4_soft_in, + clear_ip_bgp_instance_all_ipv4_soft_in_cmd, + "clear ip bgp view WORD * ipv4 (unicast|multicast) soft in", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); + + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); +} + +DEFUN (clear_ip_bgp_all_ipv4_in_prefix_filter, + clear_ip_bgp_all_ipv4_in_prefix_filter_cmd, + "clear ip bgp * ipv4 (unicast|multicast) in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +DEFUN (clear_ip_bgp_instance_all_ipv4_in_prefix_filter, + clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd, + "clear ip bgp view WORD * ipv4 (unicast|multicast) in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); + + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +DEFUN (clear_ip_bgp_all_vpnv4_soft_in, + clear_ip_bgp_all_vpnv4_soft_in_cmd, + "clear ip bgp * vpnv4 unicast soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_all_vpnv4_soft_in, + clear_ip_bgp_all_vpnv4_in_cmd, + "clear ip bgp * vpnv4 unicast in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_bgp_all_soft_in, + clear_bgp_all_soft_in_cmd, + "clear bgp * soft in", + CLEAR_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_bgp_all_soft_in, + clear_bgp_instance_all_soft_in_cmd, + "clear bgp view WORD * soft in", + CLEAR_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n"); + +ALIAS (clear_bgp_all_soft_in, + clear_bgp_ipv6_all_soft_in_cmd, + "clear bgp ipv6 * soft in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n"); + +ALIAS (clear_bgp_all_soft_in, + clear_bgp_all_in_cmd, + "clear bgp * in", + CLEAR_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig inbound update\n"); + +ALIAS (clear_bgp_all_soft_in, + clear_bgp_ipv6_all_in_cmd, + "clear bgp ipv6 * in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_bgp_all_in_prefix_filter, + clear_bgp_all_in_prefix_filter_cmd, + "clear bgp * in prefix-filter", + CLEAR_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +ALIAS (clear_bgp_all_in_prefix_filter, + clear_bgp_ipv6_all_in_prefix_filter_cmd, + "clear bgp ipv6 * in prefix-filter", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n"); + +DEFUN (clear_ip_bgp_peer_soft_in, + clear_ip_bgp_peer_soft_in_cmd, + "clear ip bgp A.B.C.D soft in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_soft_in, + clear_ip_bgp_peer_in_cmd, + "clear ip bgp A.B.C.D in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_ip_bgp_peer_in_prefix_filter, + clear_ip_bgp_peer_in_prefix_filter_cmd, + "clear ip bgp A.B.C.D in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Soft reconfig inbound update\n" + "Push out the existing ORF prefix-list\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_ipv4_soft_in, + clear_ip_bgp_peer_ipv4_soft_in_cmd, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, + BGP_CLEAR_SOFT_IN, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_ipv4_soft_in, + clear_ip_bgp_peer_ipv4_in_cmd, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_ip_bgp_peer_ipv4_in_prefix_filter, + clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out the existing ORF prefix-list\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_vpnv4_soft_in, + clear_ip_bgp_peer_vpnv4_soft_in_cmd, + "clear ip bgp A.B.C.D vpnv4 unicast soft in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_vpnv4_soft_in, + clear_ip_bgp_peer_vpnv4_in_cmd, + "clear ip bgp A.B.C.D vpnv4 unicast in", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_bgp_peer_soft_in, + clear_bgp_peer_soft_in_cmd, + "clear bgp (A.B.C.D|X:X::X:X) soft in", + CLEAR_STR + BGP_STR + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_bgp_peer_soft_in, + clear_bgp_ipv6_peer_soft_in_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft in", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n"); + +ALIAS (clear_bgp_peer_soft_in, + clear_bgp_peer_in_cmd, + "clear bgp (A.B.C.D|X:X::X:X) in", + CLEAR_STR + BGP_STR + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig inbound update\n"); + +ALIAS (clear_bgp_peer_soft_in, + clear_bgp_ipv6_peer_in_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) in", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_bgp_peer_in_prefix_filter, + clear_bgp_peer_in_prefix_filter_cmd, + "clear bgp (A.B.C.D|X:X::X:X) in prefix-filter", + CLEAR_STR + BGP_STR + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig inbound update\n" + "Push out the existing ORF prefix-list\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +ALIAS (clear_bgp_peer_in_prefix_filter, + clear_bgp_ipv6_peer_in_prefix_filter_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) in prefix-filter", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig inbound update\n" + "Push out the existing ORF prefix-list\n"); + +DEFUN (clear_ip_bgp_peer_group_soft_in, + clear_ip_bgp_peer_group_soft_in_cmd, + "clear ip bgp peer-group WORD soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group_soft_in, + clear_ip_bgp_peer_group_in_cmd, + "clear ip bgp peer-group WORD in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_ip_bgp_peer_group_in_prefix_filter, + clear_ip_bgp_peer_group_in_prefix_filter_cmd, + "clear ip bgp peer-group WORD in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_group_ipv4_soft_in, + clear_ip_bgp_peer_group_ipv4_soft_in_cmd, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, + BGP_CLEAR_SOFT_IN, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group_ipv4_soft_in, + clear_ip_bgp_peer_group_ipv4_in_cmd, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_ip_bgp_peer_group_ipv4_in_prefix_filter, + clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_bgp_peer_group_soft_in, + clear_bgp_peer_group_soft_in_cmd, + "clear bgp peer-group WORD soft in", + CLEAR_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_bgp_peer_group_soft_in, + clear_bgp_ipv6_peer_group_soft_in_cmd, + "clear bgp ipv6 peer-group WORD soft in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n"); + +ALIAS (clear_bgp_peer_group_soft_in, + clear_bgp_peer_group_in_cmd, + "clear bgp peer-group WORD in", + CLEAR_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n"); + +ALIAS (clear_bgp_peer_group_soft_in, + clear_bgp_ipv6_peer_group_in_cmd, + "clear bgp ipv6 peer-group WORD in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_bgp_peer_group_in_prefix_filter, + clear_bgp_peer_group_in_prefix_filter_cmd, + "clear bgp peer-group WORD in prefix-filter", + CLEAR_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +ALIAS (clear_bgp_peer_group_in_prefix_filter, + clear_bgp_ipv6_peer_group_in_prefix_filter_cmd, + "clear bgp ipv6 peer-group WORD in prefix-filter", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n"); + +DEFUN (clear_ip_bgp_external_soft_in, + clear_ip_bgp_external_soft_in_cmd, + "clear ip bgp external soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_external_soft_in, + clear_ip_bgp_external_in_cmd, + "clear ip bgp external in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_ip_bgp_external_in_prefix_filter, + clear_ip_bgp_external_in_prefix_filter_cmd, + "clear ip bgp external in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +DEFUN (clear_ip_bgp_external_ipv4_soft_in, + clear_ip_bgp_external_ipv4_soft_in_cmd, + "clear ip bgp external ipv4 (unicast|multicast) soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, + BGP_CLEAR_SOFT_IN, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_external_ipv4_soft_in, + clear_ip_bgp_external_ipv4_in_cmd, + "clear ip bgp external ipv4 (unicast|multicast) in", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_ip_bgp_external_ipv4_in_prefix_filter, + clear_ip_bgp_external_ipv4_in_prefix_filter_cmd, + "clear ip bgp external ipv4 (unicast|multicast) in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +DEFUN (clear_bgp_external_soft_in, + clear_bgp_external_soft_in_cmd, + "clear bgp external soft in", + CLEAR_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_bgp_external_soft_in, + clear_bgp_ipv6_external_soft_in_cmd, + "clear bgp ipv6 external soft in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n"); + +ALIAS (clear_bgp_external_soft_in, + clear_bgp_external_in_cmd, + "clear bgp external in", + CLEAR_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig inbound update\n"); + +ALIAS (clear_bgp_external_soft_in, + clear_bgp_ipv6_external_in_cmd, + "clear bgp ipv6 external WORD in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all external peers\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_bgp_external_in_prefix_filter, + clear_bgp_external_in_prefix_filter_cmd, + "clear bgp external in prefix-filter", + CLEAR_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +ALIAS (clear_bgp_external_in_prefix_filter, + clear_bgp_ipv6_external_in_prefix_filter_cmd, + "clear bgp ipv6 external in prefix-filter", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all external peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n"); + +DEFUN (clear_ip_bgp_as_soft_in, + clear_ip_bgp_as_soft_in_cmd, + "clear ip bgp <1-65535> soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_as_soft_in, + clear_ip_bgp_as_in_cmd, + "clear ip bgp <1-65535> in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_ip_bgp_as_in_prefix_filter, + clear_ip_bgp_as_in_prefix_filter_cmd, + "clear ip bgp <1-65535> in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_as_ipv4_soft_in, + clear_ip_bgp_as_ipv4_soft_in_cmd, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, + BGP_CLEAR_SOFT_IN, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_as_ipv4_soft_in, + clear_ip_bgp_as_ipv4_in_cmd, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter, + clear_ip_bgp_as_ipv4_in_prefix_filter_cmd, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) in prefix-filter", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_as_vpnv4_soft_in, + clear_ip_bgp_as_vpnv4_soft_in_cmd, + "clear ip bgp <1-65535> vpnv4 unicast soft in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_as_vpnv4_soft_in, + clear_ip_bgp_as_vpnv4_in_cmd, + "clear ip bgp <1-65535> vpnv4 unicast in", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_bgp_as_soft_in, + clear_bgp_as_soft_in_cmd, + "clear bgp <1-65535> soft in", + CLEAR_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_bgp_as_soft_in, + clear_bgp_ipv6_as_soft_in_cmd, + "clear bgp ipv6 <1-65535> soft in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n"); + +ALIAS (clear_bgp_as_soft_in, + clear_bgp_as_in_cmd, + "clear bgp <1-65535> in", + CLEAR_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n"); + +ALIAS (clear_bgp_as_soft_in, + clear_bgp_ipv6_as_in_cmd, + "clear bgp ipv6 <1-65535> in", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n"); + +DEFUN (clear_bgp_as_in_prefix_filter, + clear_bgp_as_in_prefix_filter_cmd, + "clear bgp <1-65535> in prefix-filter", + CLEAR_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +ALIAS (clear_bgp_as_in_prefix_filter, + clear_bgp_ipv6_as_in_prefix_filter_cmd, + "clear bgp ipv6 <1-65535> in prefix-filter", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n"); + +/* Both soft-reconfiguration */ +DEFUN (clear_ip_bgp_all_soft, + clear_ip_bgp_all_soft_cmd, + "clear ip bgp * soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, NULL); +} + +ALIAS (clear_ip_bgp_all_soft, + clear_ip_bgp_instance_all_soft_cmd, + "clear ip bgp view WORD * soft", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n"); + + +DEFUN (clear_ip_bgp_all_ipv4_soft, + clear_ip_bgp_all_ipv4_soft_cmd, + "clear ip bgp * ipv4 (unicast|multicast) soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, NULL); +} + +DEFUN (clear_ip_bgp_instance_all_ipv4_soft, + clear_ip_bgp_instance_all_ipv4_soft_cmd, + "clear ip bgp view WORD * ipv4 (unicast|multicast) soft", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, NULL); +} + +DEFUN (clear_ip_bgp_all_vpnv4_soft, + clear_ip_bgp_all_vpnv4_soft_cmd, + "clear ip bgp * vpnv4 unicast soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_bgp_all_soft, + clear_bgp_all_soft_cmd, + "clear bgp * soft", + CLEAR_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +ALIAS (clear_bgp_all_soft, + clear_bgp_instance_all_soft_cmd, + "clear bgp view WORD * soft", + CLEAR_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n"); + +ALIAS (clear_bgp_all_soft, + clear_bgp_ipv6_all_soft_cmd, + "clear bgp ipv6 * soft", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n" + "Soft reconfig\n"); + +DEFUN (clear_ip_bgp_peer_soft, + clear_ip_bgp_peer_soft_cmd, + "clear ip bgp A.B.C.D soft", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_ipv4_soft, + clear_ip_bgp_peer_ipv4_soft_cmd, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, + BGP_CLEAR_SOFT_BOTH, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_vpnv4_soft, + clear_ip_bgp_peer_vpnv4_soft_cmd, + "clear ip bgp A.B.C.D vpnv4 unicast soft", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_bgp_peer_soft, + clear_bgp_peer_soft_cmd, + "clear bgp (A.B.C.D|X:X::X:X) soft", + CLEAR_STR + BGP_STR + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +ALIAS (clear_bgp_peer_soft, + clear_bgp_ipv6_peer_soft_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n"); + +DEFUN (clear_ip_bgp_peer_group_soft, + clear_ip_bgp_peer_group_soft_cmd, + "clear ip bgp peer-group WORD soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_group_ipv4_soft, + clear_ip_bgp_peer_group_ipv4_soft_cmd, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, + BGP_CLEAR_SOFT_BOTH, argv[0]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_bgp_peer_group_soft, + clear_bgp_peer_group_soft_cmd, + "clear bgp peer-group WORD soft", + CLEAR_STR + BGP_STR + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +ALIAS (clear_bgp_peer_group_soft, + clear_bgp_ipv6_peer_group_soft_cmd, + "clear bgp ipv6 peer-group WORD soft", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n"); + +DEFUN (clear_ip_bgp_external_soft, + clear_ip_bgp_external_soft_cmd, + "clear ip bgp external soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_BOTH, NULL); +} + +DEFUN (clear_ip_bgp_external_ipv4_soft, + clear_ip_bgp_external_ipv4_soft_cmd, + "clear ip bgp external ipv4 (unicast|multicast) soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, + BGP_CLEAR_SOFT_BOTH, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_BOTH, NULL); +} + +DEFUN (clear_bgp_external_soft, + clear_bgp_external_soft_cmd, + "clear bgp external soft", + CLEAR_STR + BGP_STR + "Clear all external peers\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, + BGP_CLEAR_SOFT_BOTH, NULL); +} + +ALIAS (clear_bgp_external_soft, + clear_bgp_ipv6_external_soft_cmd, + "clear bgp ipv6 external soft", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all external peers\n" + "Soft reconfig\n"); + +DEFUN (clear_ip_bgp_as_soft, + clear_ip_bgp_as_soft_cmd, + "clear ip bgp <1-65535> soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_as_ipv4_soft, + clear_ip_bgp_as_ipv4_soft_cmd, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, + BGP_CLEAR_SOFT_BOTH, argv[0]); + + return bgp_clear_vty (vty, NULL,AFI_IP, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_as_vpnv4_soft, + clear_ip_bgp_as_vpnv4_soft_cmd, + "clear ip bgp <1-65535> vpnv4 unicast soft", + CLEAR_STR + IP_STR + BGP_STR + "Clear peers with the AS number\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_bgp_as_soft, + clear_bgp_as_soft_cmd, + "clear bgp <1-65535> soft", + CLEAR_STR + BGP_STR + "Clear peers with the AS number\n" + "Soft reconfig\n") +{ + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, + BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +ALIAS (clear_bgp_as_soft, + clear_bgp_ipv6_as_soft_cmd, + "clear bgp ipv6 <1-65535> soft", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig\n"); + +/* Show BGP peer's summary information. */ +int +bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) +{ + struct peer *peer; + struct listnode *nn; + int count = 0; + char timebuf[BGP_UPTIME_LEN]; + int len; + + /* Header string for each address family. */ + static char header[] = "Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd"; + + LIST_LOOP (bgp->peer, peer, nn) + { + if (peer->afc[afi][safi]) + { + if (! count) + { + vty_out (vty, + "BGP router identifier %s, local AS number %d%s", + inet_ntoa (bgp->router_id), bgp->as, VTY_NEWLINE); + vty_out (vty, + "%ld BGP AS-PATH entries%s", aspath_count (), + VTY_NEWLINE); + vty_out (vty, + "%ld BGP community entries%s", community_count (), + VTY_NEWLINE); + + if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) + vty_out (vty, "Dampening enabled.%s", VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "%s%s", header, VTY_NEWLINE); + } + count++; + + len = vty_out (vty, "%s", peer->host); + len = 16 - len; + if (len < 1) + vty_out (vty, "%s%*s", VTY_NEWLINE, 16, " "); + else + vty_out (vty, "%*s", len, " "); + + vty_out (vty, "4 "); + + vty_out (vty, "%5d %7d %7d %8d %4d %4ld ", + peer->as, + peer->open_in + peer->update_in + peer->keepalive_in + + peer->notify_in + peer->refresh_in + peer->dynamic_cap_in, + peer->open_out + peer->update_out + peer->keepalive_out + + peer->notify_out + peer->refresh_out + + peer->dynamic_cap_out, + 0, 0, peer->obuf->count); + + vty_out (vty, "%8s", + peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN)); + + if (peer->status == Established) + { + vty_out (vty, " %8ld", peer->pcount[afi][safi]); + } + else + { + if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) + vty_out (vty, " Idle (Admin)"); + else if (CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) + vty_out (vty, " Idle (PfxCt)"); + else + vty_out (vty, " %-11s", LOOKUP(bgp_status_msg, peer->status)); + } + + vty_out (vty, "%s", VTY_NEWLINE); + } + } + + if (count) + vty_out (vty, "%sTotal number of neighbors %d%s", VTY_NEWLINE, + count, VTY_NEWLINE); + else + vty_out (vty, "No %s neighbor is configured%s", + afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE); + return CMD_SUCCESS; +} + +int +bgp_show_summary_vty (struct vty *vty, char *name, afi_t afi, safi_t safi) +{ + struct bgp *bgp; + + if (name) + { + bgp = bgp_lookup_by_name (name); + + if (! bgp) + { + vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_show_summary (vty, bgp, afi, safi); + return CMD_SUCCESS; + } + + bgp = bgp_get_default (); + + if (bgp) + bgp_show_summary (vty, bgp, afi, safi); + + return CMD_SUCCESS; +} + +/* `show ip bgp summary' commands. */ +DEFUN (show_ip_bgp_summary, + show_ip_bgp_summary_cmd, + "show ip bgp summary", + SHOW_STR + IP_STR + BGP_STR + "Summary of BGP neighbor status\n") +{ + return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_instance_summary, + show_ip_bgp_instance_summary_cmd, + "show ip bgp view WORD summary", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Summary of BGP neighbor status\n") +{ + return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_summary, + show_ip_bgp_ipv4_summary_cmd, + "show ip bgp ipv4 (unicast|multicast) summary", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Summary of BGP neighbor status\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); + + return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_instance_ipv4_summary, + show_ip_bgp_instance_ipv4_summary_cmd, + "show ip bgp view WORD ipv4 (unicast|multicast) summary", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Summary of BGP neighbor status\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); + else + return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_vpnv4_all_summary, + show_ip_bgp_vpnv4_all_summary_cmd, + "show ip bgp vpnv4 all summary", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Summary of BGP neighbor status\n") +{ + return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); +} + +DEFUN (show_ip_bgp_vpnv4_rd_summary, + show_ip_bgp_vpnv4_rd_summary_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn summary", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Summary of BGP neighbor status\n") +{ + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[0], &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_summary, + show_bgp_summary_cmd, + "show bgp summary", + SHOW_STR + BGP_STR + "Summary of BGP neighbor status\n") +{ + return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); +} + +DEFUN (show_bgp_instance_summary, + show_bgp_instance_summary_cmd, + "show bgp view WORD summary", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Summary of BGP neighbor status\n") +{ + return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_summary, + show_bgp_ipv6_summary_cmd, + "show bgp ipv6 summary", + SHOW_STR + BGP_STR + "Address family\n" + "Summary of BGP neighbor status\n"); + +ALIAS (show_bgp_instance_summary, + show_bgp_instance_ipv6_summary_cmd, + "show bgp view WORD ipv6 summary", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Summary of BGP neighbor status\n"); +#endif /* HAVE_IPV6 */ + +char * +afi_safi_print (afi_t afi, safi_t safi) +{ + if (afi == AFI_IP && safi == SAFI_UNICAST) + return "IPv4 Unicast"; + else if (afi == AFI_IP && safi == SAFI_MULTICAST) + return "IPv4 Multicast"; + else if (afi == AFI_IP && safi == SAFI_MPLS_VPN) + return "VPNv4 Unicast"; + else if (afi == AFI_IP6 && safi == SAFI_UNICAST) + return "IPv6 Unicast"; + else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) + return "IPv6 Multicast"; + else + return "Unknown"; +} + +/* Show BGP peer's information. */ +enum show_type + { + show_all, + show_peer + }; + +void +bgp_show_peer_afi_orf_cap (struct vty *vty, struct peer *p, + afi_t afi, safi_t safi, + u_int16_t adv_smcap, u_int16_t adv_rmcap, + u_int16_t rcv_smcap, u_int16_t rcv_rmcap) +{ + /* Send-Mode */ + if (CHECK_FLAG (p->af_cap[afi][safi], adv_smcap) + || CHECK_FLAG (p->af_cap[afi][safi], rcv_smcap)) + { + vty_out (vty, " Send-mode: "); + if (CHECK_FLAG (p->af_cap[afi][safi], adv_smcap)) + vty_out (vty, "advertised"); + if (CHECK_FLAG (p->af_cap[afi][safi], rcv_smcap)) + vty_out (vty, "%sreceived", + CHECK_FLAG (p->af_cap[afi][safi], adv_smcap) ? + ", " : ""); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Receive-Mode */ + if (CHECK_FLAG (p->af_cap[afi][safi], adv_rmcap) + || CHECK_FLAG (p->af_cap[afi][safi], rcv_rmcap)) + { + vty_out (vty, " Receive-mode: "); + if (CHECK_FLAG (p->af_cap[afi][safi], adv_rmcap)) + vty_out (vty, "advertised"); + if (CHECK_FLAG (p->af_cap[afi][safi], rcv_rmcap)) + vty_out (vty, "%sreceived", + CHECK_FLAG (p->af_cap[afi][safi], adv_rmcap) ? + ", " : ""); + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +void +bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi) +{ + struct bgp_filter *filter; + char orf_pfx_name[BUFSIZ]; + int orf_pfx_count; + + filter = &p->filter[afi][safi]; + + vty_out (vty, " For address family: %s%s", afi_safi_print (afi, safi), + VTY_NEWLINE); + + vty_out (vty, " Configuration flags 0x%x%s", p->af_config[afi][safi], + VTY_NEWLINE); + + if (peer_group_member (p)) + vty_out (vty, " %s peer-group member%s", p->group->name, VTY_NEWLINE); + + if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) + vty_out (vty, " Route-Reflector Client%s", VTY_NEWLINE); + if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + vty_out (vty, " Route-Server Client%s", VTY_NEWLINE); + if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) + vty_out (vty, " Inbound soft reconfiguration allowed%s", VTY_NEWLINE); + if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REMOVE_PRIVATE_AS)) + vty_out (vty, " Private AS number removed from updates to this neighbor%s", VTY_NEWLINE); + if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF)) + vty_out (vty, " NEXT_HOP is always this router%s", VTY_NEWLINE); + if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)) + vty_out (vty, " AS_PATH is propagated unchanged to this neighbor%s", VTY_NEWLINE); + if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)) + vty_out (vty, " NEXT_HOP is propagated unchanged to this neighbor%s", VTY_NEWLINE); + if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) + vty_out (vty, " MED is propagated unchanged to this neighbor%s", VTY_NEWLINE); + if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) + || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) + { + vty_out (vty, " Community attribute sent to this neighbor"); + if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) + && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) + vty_out (vty, "(both)%s", VTY_NEWLINE); + else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) + vty_out (vty, "(extended)%s", VTY_NEWLINE); + else + vty_out (vty, "(standard)%s", VTY_NEWLINE); + } + if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) + { + vty_out (vty, " Default information originate,"); + + if (p->default_rmap[afi][safi].name) + vty_out (vty, " default route-map %s%s,", + p->default_rmap[afi][safi].map ? "*" : "", + p->default_rmap[afi][safi].name); + if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) + vty_out (vty, " default sent%s", VTY_NEWLINE); + else + vty_out (vty, " default not sent%s", VTY_NEWLINE); + } + + if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) + || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) + || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV) + || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) + || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV) + || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) + vty_out (vty, " AF-dependant capabilities:%s", VTY_NEWLINE); + + if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) + || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) + || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) + || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)) + { + vty_out (vty, " Outbound Route Filter (ORF) type (%d) Prefix-list:%s", + ORF_TYPE_PREFIX, VTY_NEWLINE); + bgp_show_peer_afi_orf_cap (vty, p, afi, safi, + PEER_CAP_ORF_PREFIX_SM_ADV, + PEER_CAP_ORF_PREFIX_RM_ADV, + PEER_CAP_ORF_PREFIX_SM_RCV, + PEER_CAP_ORF_PREFIX_RM_RCV); + } + if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) + || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV) + || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) + || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) + { + vty_out (vty, " Outbound Route Filter (ORF) type (%d) Prefix-list:%s", + ORF_TYPE_PREFIX_OLD, VTY_NEWLINE); + bgp_show_peer_afi_orf_cap (vty, p, afi, safi, + PEER_CAP_ORF_PREFIX_SM_ADV, + PEER_CAP_ORF_PREFIX_RM_ADV, + PEER_CAP_ORF_PREFIX_SM_OLD_RCV, + PEER_CAP_ORF_PREFIX_RM_OLD_RCV); + } + + sprintf (orf_pfx_name, "%s.%d.%d", p->host, afi, safi); + orf_pfx_count = prefix_bgp_show_prefix_list (NULL, afi, orf_pfx_name); + + if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND) + || orf_pfx_count) + { + vty_out (vty, " Outbound Route Filter (ORF):"); + if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND)) + vty_out (vty, " sent;"); + if (orf_pfx_count) + vty_out (vty, " received (%d entries)", orf_pfx_count); + vty_out (vty, "%s", VTY_NEWLINE); + } + if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) + vty_out (vty, " First update is deferred until ORF or ROUTE-REFRESH is received%s", VTY_NEWLINE); + + if (filter->plist[FILTER_IN].name + || filter->dlist[FILTER_IN].name + || filter->aslist[FILTER_IN].name + || filter->map[FILTER_IN].name) + vty_out (vty, " Inbound path policy configured%s", VTY_NEWLINE); + if (filter->plist[FILTER_OUT].name + || filter->dlist[FILTER_OUT].name + || filter->aslist[FILTER_OUT].name + || filter->map[FILTER_OUT].name + || filter->usmap.name) + vty_out (vty, " Outbound path policy configured%s", VTY_NEWLINE); + + /* prefix-list */ + if (filter->plist[FILTER_IN].name) + vty_out (vty, " Incoming update prefix filter list is %s%s%s", + filter->plist[FILTER_IN].plist ? "*" : "", + filter->plist[FILTER_IN].name, + VTY_NEWLINE); + if (filter->plist[FILTER_OUT].name) + vty_out (vty, " Outgoing update prefix filter list is %s%s%s", + filter->plist[FILTER_OUT].plist ? "*" : "", + filter->plist[FILTER_OUT].name, + VTY_NEWLINE); + + /* distribute-list */ + if (filter->dlist[FILTER_IN].name) + vty_out (vty, " Incoming update network filter list is %s%s%s", + filter->dlist[FILTER_IN].alist ? "*" : "", + filter->dlist[FILTER_IN].name, + VTY_NEWLINE); + if (filter->dlist[FILTER_OUT].name) + vty_out (vty, " Outgoing update network filter list is %s%s%s", + filter->dlist[FILTER_OUT].alist ? "*" : "", + filter->dlist[FILTER_OUT].name, + VTY_NEWLINE); + + /* filter-list. */ + if (filter->aslist[FILTER_IN].name) + vty_out (vty, " Incoming update AS path filter list is %s%s%s", + filter->aslist[FILTER_IN].aslist ? "*" : "", + filter->aslist[FILTER_IN].name, + VTY_NEWLINE); + if (filter->aslist[FILTER_OUT].name) + vty_out (vty, " Outgoing update AS path filter list is %s%s%s", + filter->aslist[FILTER_OUT].aslist ? "*" : "", + filter->aslist[FILTER_OUT].name, + VTY_NEWLINE); + + /* route-map. */ + if (filter->map[FILTER_IN].name) + vty_out (vty, " Route map for incoming advertisements is %s%s%s", + filter->map[FILTER_IN].map ? "*" : "", + filter->map[FILTER_IN].name, + VTY_NEWLINE); + if (filter->map[FILTER_OUT].name) + vty_out (vty, " Route map for outgoing advertisements is %s%s%s", + filter->map[FILTER_OUT].map ? "*" : "", + filter->map[FILTER_OUT].name, + VTY_NEWLINE); + + /* unsuppress-map */ + if (filter->usmap.name) + vty_out (vty, " Route map for selective unsuppress is %s%s%s", + filter->usmap.map ? "*" : "", + filter->usmap.name, VTY_NEWLINE); + + /* Default weight */ + if (CHECK_FLAG (p->af_config[afi][safi], PEER_AF_CONFIG_WEIGHT)) + vty_out (vty, " Default weight %d%s", p->weight[afi][safi], + VTY_NEWLINE); + + /* Receive prefix count */ + vty_out (vty, " %ld accepted prefixes%s", p->pcount[afi][safi], VTY_NEWLINE); + + /* Maximum prefix */ + if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) + { + vty_out (vty, " Maximum prefixes allowed %ld%s%s", p->pmax[afi][safi], + CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING) + ? " (warning-only)" : "", VTY_NEWLINE); + vty_out (vty, " Threshold for warning message %d%%", p->pmax_threshold[afi][safi]); + if (p->pmax_restart[afi][safi]) + vty_out (vty, ", restart interval %d min", p->pmax_restart[afi][safi]); + vty_out (vty, "%s", VTY_NEWLINE); + } + + vty_out (vty, "%s", VTY_NEWLINE); +} + +void +bgp_show_peer (struct vty *vty, struct peer *p) +{ + struct bgp *bgp; + char buf1[BUFSIZ]; + char timebuf[BGP_UPTIME_LEN]; + afi_t afi; + safi_t safi; + + bgp = p->bgp; + + /* Configured IP address. */ + vty_out (vty, "BGP neighbor is %s, ", p->host); + vty_out (vty, "remote AS %d, ", p->as); + vty_out (vty, "local AS %d%s, ", + p->change_local_as ? p->change_local_as : p->local_as, + CHECK_FLAG (p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ? + " no-prepend" : ""); + vty_out (vty, "%s link%s", + p->as == p->local_as ? "internal" : "external", + VTY_NEWLINE); + + /* Description. */ + if (p->desc) + vty_out (vty, " Description: %s%s", p->desc, VTY_NEWLINE); + + /* Peer-group */ + if (p->group) + vty_out (vty, " Member of peer-group %s for session parameters%s", + p->group->name, VTY_NEWLINE); + + /* Administrative shutdown. */ + if (CHECK_FLAG (p->flags, PEER_FLAG_SHUTDOWN)) + vty_out (vty, " Administratively shut down%s", VTY_NEWLINE); + + /* BGP Version. */ + vty_out (vty, " BGP version 4"); + vty_out (vty, ", remote router ID %s%s", + inet_ntop (AF_INET, &p->remote_id, buf1, BUFSIZ), + VTY_NEWLINE); + + /* Confederation */ + if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION) + && bgp_confederation_peers_check (bgp, p->as)) + vty_out (vty, " Neighbor under common administration%s", VTY_NEWLINE); + + /* Status. */ + vty_out (vty, " BGP state = %s", + LOOKUP (bgp_status_msg, p->status)); + if (p->status == Established) + vty_out (vty, ", up for %8s", + peer_uptime (p->uptime, timebuf, BGP_UPTIME_LEN)); + vty_out (vty, "%s", VTY_NEWLINE); + + /* read timer */ + vty_out (vty, " Last read %s", peer_uptime (p->readtime, timebuf, BGP_UPTIME_LEN)); + + /* Configured timer values. */ + vty_out (vty, ", hold time is %d, keepalive interval is %d seconds%s", + p->v_holdtime, p->v_keepalive, VTY_NEWLINE); + if (CHECK_FLAG (p->config, PEER_CONFIG_TIMER)) + { + vty_out (vty, " Configured hold time is %d", p->holdtime); + vty_out (vty, ", keepalive interval is %d seconds%s", + p->keepalive, VTY_NEWLINE); + } + + /* Capability. */ + if (p->status == Established) + { + if (p->cap + || p->afc_adv[AFI_IP][SAFI_UNICAST] + || p->afc_recv[AFI_IP][SAFI_UNICAST] + || p->afc_adv[AFI_IP][SAFI_MULTICAST] + || p->afc_recv[AFI_IP][SAFI_MULTICAST] +#ifdef HAVE_IPV6 + || p->afc_adv[AFI_IP6][SAFI_UNICAST] + || p->afc_recv[AFI_IP6][SAFI_UNICAST] + || p->afc_adv[AFI_IP6][SAFI_MULTICAST] + || p->afc_recv[AFI_IP6][SAFI_MULTICAST] +#endif /* HAVE_IPV6 */ + || p->afc_adv[AFI_IP][SAFI_MPLS_VPN] + || p->afc_recv[AFI_IP][SAFI_MPLS_VPN]) + { + vty_out (vty, " Neighbor capabilities:%s", VTY_NEWLINE); + + /* Dynamic */ + if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV) + || CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV)) + { + vty_out (vty, " Dynamic:"); + if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV)) + vty_out (vty, " advertised"); + if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV)) + vty_out (vty, " %sreceived", + CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV) ? "and " : ""); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Route Refresh */ + if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV) + || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV) + || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV)) + { + vty_out (vty, " Route refresh:"); + if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV)) + vty_out (vty, " advertised"); + if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV) + || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV)) + vty_out (vty, " %sreceived(%s)", + CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV) ? "and " : "", + (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV) + && CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV)) ? + "old & new" : CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV) ? "old" : "new"); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Multiprotocol Extensions */ + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + if (p->afc_adv[afi][safi] || p->afc_recv[afi][safi]) + { + vty_out (vty, " Address family %s:", afi_safi_print (afi, safi)); + if (p->afc_adv[afi][safi]) + vty_out (vty, " advertised"); + if (p->afc_recv[afi][safi]) + vty_out (vty, " %sreceived", p->afc_adv[afi][safi] ? "and " : ""); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Gracefull Restart */ + if (CHECK_FLAG (p->cap, PEER_CAP_RESTART_RCV) + || CHECK_FLAG (p->cap, PEER_CAP_RESTART_ADV)) + { + vty_out (vty, " Graceful Restart Capabilty:"); + if (CHECK_FLAG (p->cap, PEER_CAP_RESTART_ADV)) + vty_out (vty, " advertised"); + if (CHECK_FLAG (p->cap, PEER_CAP_RESTART_RCV)) + vty_out (vty, " %sreceived", + CHECK_FLAG (p->cap, PEER_CAP_RESTART_ADV) ? "and " : ""); + vty_out (vty, "%s", VTY_NEWLINE); + + if (CHECK_FLAG (p->cap, PEER_CAP_RESTART_RCV)) + { + int restart_af_count = 0; + + vty_out (vty, " Remote Restart timer is %d seconds%s", + p->v_gr_restart, VTY_NEWLINE); + + vty_out (vty, " Address families preserved by peer:%s", VTY_NEWLINE); + vty_out (vty, " "); + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV)) + { + vty_out (vty, "%s%s", restart_af_count ? ", " : "", + afi_safi_print (afi, safi)); + restart_af_count++; + } + if (! restart_af_count) + vty_out (vty, "none"); + + vty_out (vty, "%s", VTY_NEWLINE); + } + } + } + } + + /* graceful restart information */ + if (CHECK_FLAG (p->cap, PEER_CAP_RESTART_RCV) + || p->t_gr_restart + || p->t_gr_stale) + { + int eor_send_af_count = 0; + int eor_receive_af_count = 0; + + vty_out (vty, " Graceful restart informations:%s", VTY_NEWLINE); + if (p->status == Established) + { + vty_out (vty, " End-of-RIB send: "); + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_EOR_SEND)) + { + vty_out (vty, "%s%s", eor_send_af_count ? ", " : "", + afi_safi_print (afi, safi)); + eor_send_af_count++; + } + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, " End-of-RIB received: "); + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED)) + { + vty_out (vty, "%s%s", eor_receive_af_count ? ", " : "", + afi_safi_print (afi, safi)); + eor_receive_af_count++; + } + vty_out (vty, "%s", VTY_NEWLINE); + } + + if (p->t_gr_restart) + { + vty_out (vty, " The remaining time of restart timer is %s%s", + thread_timer_remain_second (p->t_gr_restart), VTY_NEWLINE); + } + if (p->t_gr_stale) + { + vty_out (vty, " The remaining time of stalepath timer is %s%s", + thread_timer_remain_second (p->t_gr_stale), VTY_NEWLINE); + } + } + + /* Packet counts. */ + vty_out (vty, " Message statistics:%s", VTY_NEWLINE); + vty_out (vty, " Inq depth is 0%s", VTY_NEWLINE); + vty_out (vty, " Outq depth is %ld%s", p->obuf->count, VTY_NEWLINE); + vty_out (vty, " Sent Rcvd%s", VTY_NEWLINE); + vty_out (vty, " Opens: %10d %10d%s", p->open_out, p->open_in, VTY_NEWLINE); + vty_out (vty, " Notifications: %10d %10d%s", p->notify_out, p->notify_in, VTY_NEWLINE); + vty_out (vty, " Updates: %10d %10d%s", p->update_out, p->update_in, VTY_NEWLINE); + vty_out (vty, " Keepalives: %10d %10d%s", p->keepalive_out, p->keepalive_in, VTY_NEWLINE); + vty_out (vty, " Route Refresh: %10d %10d%s", p->refresh_out, p->refresh_in, VTY_NEWLINE); + vty_out (vty, " Capability: %10d %10d%s", p->dynamic_cap_out, p->dynamic_cap_in, VTY_NEWLINE); + vty_out (vty, " Total: %10d %10d%s", p->open_out + p->notify_out + + p->update_out + p->keepalive_out + p->refresh_out + p->dynamic_cap_out, + p->open_in + p->notify_in + p->update_in + p->keepalive_in + p->refresh_in + + p->dynamic_cap_in, VTY_NEWLINE); + + /* advertisement-interval */ + vty_out (vty, " Minimum time between advertisement runs is %d seconds%s", + p->v_routeadv, VTY_NEWLINE); + + /* Update-source. */ + if (p->update_if || p->update_source) + { + vty_out (vty, " Update source is "); + if (p->update_if) + vty_out (vty, "%s", p->update_if); + else if (p->update_source) + vty_out (vty, "%s", + sockunion2str (p->update_source, buf1, SU_ADDRSTRLEN)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + vty_out (vty, "%s", VTY_NEWLINE); + + /* Address Family Information */ + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) + if (p->afc[afi][safi]) + bgp_show_peer_afi (vty, p, afi, safi); + + vty_out (vty, " Connections established %d; dropped %d%s", + p->established, p->dropped, + VTY_NEWLINE); + + if (! p->dropped) + vty_out (vty, " Last reset never%s", VTY_NEWLINE); + else + vty_out (vty, " Last reset %s, due to %s%s", + peer_uptime (p->resettime, timebuf, BGP_UPTIME_LEN), + peer_down_str[(int) p->last_reset], VTY_NEWLINE); + + if (CHECK_FLAG (p->sflags, PEER_STATUS_PREFIX_OVERFLOW)) + { + vty_out (vty, " Peer had exceeded the max. no. of prefixes configured.%s", VTY_NEWLINE); + + if (p->t_pmax_restart) + vty_out (vty, " Reduce the no. of prefix from %s, will restart in %s%s", + p->host, thread_timer_remain_second (p->t_pmax_restart), VTY_NEWLINE); + else + vty_out (vty, " Reduce the no. of prefix and clear ip bgp %s to restore peering%s", + p->host, VTY_NEWLINE); + } + + /* EBGP Multihop */ + if (peer_sort (p) != BGP_PEER_IBGP && p->ttl > 1) + vty_out (vty, " External BGP neighbor may be up to %d hops away.%s", + p->ttl, VTY_NEWLINE); + + /* connection-mode */ + if (CHECK_FLAG (p->flags, PEER_FLAG_CONNECT_MODE_PASSIVE)) + vty_out (vty, " TCP session must be opened passively%s", VTY_NEWLINE); + if (CHECK_FLAG (p->flags, PEER_FLAG_CONNECT_MODE_ACTIVE)) + vty_out (vty, " TCP session must be opened actively%s", VTY_NEWLINE); + + /* Local address. */ + if (p->su_local) + { + vty_out (vty, "Local host: %s, Local port: %d%s", + sockunion2str (p->su_local, buf1, SU_ADDRSTRLEN), + ntohs (p->su_local->sin.sin_port), + VTY_NEWLINE); + } + + /* Remote address. */ + if (p->su_remote) + { + vty_out (vty, "Foreign host: %s, Foreign port: %d%s", + sockunion2str (p->su_remote, buf1, SU_ADDRSTRLEN), + ntohs (p->su_remote->sin.sin_port), + VTY_NEWLINE); + } + + /* Nexthop display. */ + if (p->su_local) + { + vty_out (vty, "Nexthop: %s%s", + inet_ntop (AF_INET, &p->nexthop.v4, buf1, BUFSIZ), + VTY_NEWLINE); +#ifdef HAVE_IPV6 + vty_out (vty, "Nexthop global: %s%s", + inet_ntop (AF_INET6, &p->nexthop.v6_global, buf1, BUFSIZ), + VTY_NEWLINE); + vty_out (vty, "Nexthop local: %s%s", + inet_ntop (AF_INET6, &p->nexthop.v6_local, buf1, BUFSIZ), + VTY_NEWLINE); + vty_out (vty, "BGP connection: %s%s", + p->shared_network ? "shared network" : "non shared network", + VTY_NEWLINE); +#endif /* HAVE_IPV6 */ + } + + /* Timer information. */ + if (p->t_start) + vty_out (vty, "Next start timer due in %s%s", + thread_timer_remain_second (p->t_start), VTY_NEWLINE); + if (p->t_connect) + vty_out (vty, "Next connect timer due in %s%s", + thread_timer_remain_second (p->t_connect), VTY_NEWLINE); + + vty_out (vty, "Read thread: %s Write thread: %s%s", + p->t_read ? "on" : "off", + p->t_write ? "on" : "off", + VTY_NEWLINE); + + if (p->notify.code == BGP_NOTIFY_OPEN_ERR + && p->notify.subcode == BGP_NOTIFY_OPEN_UNSUP_CAPBL) + bgp_capability_vty_out (vty, p); + + vty_out (vty, "%s", VTY_NEWLINE); +} + +int +bgp_show_neighbor (struct vty *vty, struct bgp *bgp, + enum show_type type, union sockunion *su) +{ + struct listnode *nn; + struct peer *peer; + int find = 0; + + LIST_LOOP (bgp->peer, peer, nn) + { + switch (type) + { + case show_all: + bgp_show_peer (vty, peer); + break; + case show_peer: + if (sockunion_same (&peer->su, su)) + { + find = 1; + bgp_show_peer (vty, peer); + } + break; + } + } + + if (type == show_peer && ! find) + vty_out (vty, "%% No such neighbor%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +int +bgp_show_neighbor_vty (struct vty *vty, char *name, enum show_type type, + char *ip_str) +{ + int ret; + struct bgp *bgp; + union sockunion su; + + if (ip_str) + { + ret = str2sockunion (ip_str, &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed address: %s%s", ip_str, VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (name) + { + bgp = bgp_lookup_by_name (name); + + if (! bgp) + { + vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_show_neighbor (vty, bgp, type, &su); + + return CMD_SUCCESS; + } + + bgp = bgp_get_default (); + + if (bgp) + bgp_show_neighbor (vty, bgp, type, &su); + + return CMD_SUCCESS; +} + +/* "show ip bgp neighbors" commands. */ +DEFUN (show_ip_bgp_neighbors, + show_ip_bgp_neighbors_cmd, + "show ip bgp neighbors", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n") +{ + return bgp_show_neighbor_vty (vty, NULL, show_all, NULL); +} + +ALIAS (show_ip_bgp_neighbors, + show_ip_bgp_ipv4_neighbors_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n"); + +ALIAS (show_ip_bgp_neighbors, + show_ip_bgp_vpnv4_all_neighbors_cmd, + "show ip bgp vpnv4 all neighbors", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n"); + +ALIAS (show_ip_bgp_neighbors, + show_ip_bgp_vpnv4_rd_neighbors_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n"); + +ALIAS (show_ip_bgp_neighbors, + show_bgp_neighbors_cmd, + "show bgp neighbors", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n"); + +ALIAS (show_ip_bgp_neighbors, + show_bgp_ipv6_neighbors_cmd, + "show bgp ipv6 neighbors", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n"); + +DEFUN (show_ip_bgp_neighbors_peer, + show_ip_bgp_neighbors_peer_cmd, + "show ip bgp neighbors (A.B.C.D|X:X::X:X)", + SHOW_STR + IP_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n") +{ + return bgp_show_neighbor_vty (vty, NULL, show_peer, argv[argc - 1]); +} + +ALIAS (show_ip_bgp_neighbors_peer, + show_ip_bgp_ipv4_neighbors_peer_cmd, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X)", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n"); + +ALIAS (show_ip_bgp_neighbors_peer, + show_ip_bgp_vpnv4_all_neighbors_peer_cmd, + "show ip bgp vpnv4 all neighbors A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n"); + +ALIAS (show_ip_bgp_neighbors_peer, + show_ip_bgp_vpnv4_rd_neighbors_peer_cmd, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n"); + +ALIAS (show_ip_bgp_neighbors_peer, + show_bgp_neighbors_peer_cmd, + "show bgp neighbors (A.B.C.D|X:X::X:X)", + SHOW_STR + BGP_STR + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n"); + +ALIAS (show_ip_bgp_neighbors_peer, + show_bgp_ipv6_neighbors_peer_cmd, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X)", + SHOW_STR + BGP_STR + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n"); + +DEFUN (show_ip_bgp_instance_neighbors, + show_ip_bgp_instance_neighbors_cmd, + "show ip bgp view WORD neighbors", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Detailed information on TCP and BGP neighbor connections\n") +{ + return bgp_show_neighbor_vty (vty, argv[0], show_all, NULL); +} + +DEFUN (show_ip_bgp_instance_neighbors_peer, + show_ip_bgp_instance_neighbors_peer_cmd, + "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X)", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n") +{ + return bgp_show_neighbor_vty (vty, argv[0], show_peer, argv[1]); +} + +/* Show BGP's AS paths internal data. There are both `show ip bgp + paths' and `show ip mbgp paths'. Those functions results are the + same.*/ +DEFUN (show_ip_bgp_paths, + show_ip_bgp_paths_cmd, + "show ip bgp paths", + SHOW_STR + IP_STR + BGP_STR + "Path information\n") +{ + vty_out (vty, "Address Refcnt Path%s", VTY_NEWLINE); + aspath_print_all_vty (vty); + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_ipv4_paths, + show_ip_bgp_ipv4_paths_cmd, + "show ip bgp ipv4 (unicast|multicast) paths", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Path information\n") +{ + vty_out (vty, "Address Refcnt Path\r\n"); + aspath_print_all_vty (vty); + + return CMD_SUCCESS; +} + +#include "hash.h" + +void +community_show_all_iterator (struct hash_backet *backet, struct vty *vty) +{ + struct community *com; + + com = (struct community *) backet->data; + vty_out (vty, "[%p] (%ld) %s%s", backet, com->refcnt, + community_str (com), VTY_NEWLINE); +} + +/* Show BGP's community internal data. */ +DEFUN (show_ip_bgp_community_info, + show_ip_bgp_community_info_cmd, + "show ip bgp community-info", + SHOW_STR + IP_STR + BGP_STR + "List all bgp community information\n") +{ + vty_out (vty, "Address Refcnt Community%s", VTY_NEWLINE); + + hash_iterate (community_hash (), + (void (*) (struct hash_backet *, void *)) + community_show_all_iterator, + vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_attr_info, + show_ip_bgp_attr_info_cmd, + "show ip bgp attribute-info", + SHOW_STR + IP_STR + BGP_STR + "List all bgp attribute information\n") +{ + attr_show_all (vty); + return CMD_SUCCESS; +} + +/* Redistribute VTY commands. */ + +/* Utility function to convert user input route type string to route + type. */ +static int +bgp_str2route_type (int afi, char *str) +{ + if (! str) + return 0; + + if (afi == AFI_IP) + { + if (strncmp (str, "k", 1) == 0) + return ZEBRA_ROUTE_KERNEL; + else if (strncmp (str, "c", 1) == 0) + return ZEBRA_ROUTE_CONNECT; + else if (strncmp (str, "s", 1) == 0) + return ZEBRA_ROUTE_STATIC; + else if (strncmp (str, "r", 1) == 0) + return ZEBRA_ROUTE_RIP; + else if (strncmp (str, "o", 1) == 0) + return ZEBRA_ROUTE_OSPF; + } + if (afi == AFI_IP6) + { + if (strncmp (str, "k", 1) == 0) + return ZEBRA_ROUTE_KERNEL; + else if (strncmp (str, "c", 1) == 0) + return ZEBRA_ROUTE_CONNECT; + else if (strncmp (str, "s", 1) == 0) + return ZEBRA_ROUTE_STATIC; + else if (strncmp (str, "r", 1) == 0) + return ZEBRA_ROUTE_RIPNG; + else if (strncmp (str, "o", 1) == 0) + return ZEBRA_ROUTE_OSPF6; + } + return 0; +} + +DEFUN (bgp_redistribute_ipv4, + bgp_redistribute_ipv4_cmd, + "redistribute (connected|kernel|ospf|rip|static)", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (bgp_redistribute_ipv4_rmap, + bgp_redistribute_ipv4_rmap_cmd, + "redistribute (connected|kernel|ospf|rip|static) route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[1]); + return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (bgp_redistribute_ipv4_metric, + bgp_redistribute_ipv4_metric_cmd, + "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + u_int32_t metric; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + VTY_GET_INTEGER ("metric", metric, argv[1]); + + bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric); + return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (bgp_redistribute_ipv4_rmap_metric, + bgp_redistribute_ipv4_rmap_metric_cmd, + "redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + u_int32_t metric; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + VTY_GET_INTEGER ("metric", metric, argv[2]); + + bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[1]); + bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric); + return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (bgp_redistribute_ipv4_metric_rmap, + bgp_redistribute_ipv4_metric_rmap_cmd, + "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type; + u_int32_t metric; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + VTY_GET_INTEGER ("metric", metric, argv[1]); + + bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric); + bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[2]); + return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (no_bgp_redistribute_ipv4, + no_bgp_redistribute_ipv4_cmd, + "no redistribute (connected|kernel|ospf|rip|static)", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_redistribute_unset (vty->index, AFI_IP, type); +} + +DEFUN (no_bgp_redistribute_ipv4_rmap, + no_bgp_redistribute_ipv4_rmap_cmd, + "no redistribute (connected|kernel|ospf|rip|static) route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_routemap_unset (vty->index, AFI_IP, type); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_redistribute_ipv4_metric, + no_bgp_redistribute_ipv4_metric_cmd, + "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_metric_unset (vty->index, AFI_IP, type); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_redistribute_ipv4_rmap_metric, + no_bgp_redistribute_ipv4_rmap_metric_cmd, + "no redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_metric_unset (vty->index, AFI_IP, type); + bgp_redistribute_routemap_unset (vty->index, AFI_IP, type); + return CMD_SUCCESS; +} + +ALIAS (no_bgp_redistribute_ipv4_rmap_metric, + no_bgp_redistribute_ipv4_metric_rmap_cmd, + "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n"); + +#ifdef HAVE_IPV6 +DEFUN (bgp_redistribute_ipv6, + bgp_redistribute_ipv6_cmd, + "redistribute (connected|kernel|ospf6|ripng|static)", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (bgp_redistribute_ipv6_rmap, + bgp_redistribute_ipv6_rmap_cmd, + "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[1]); + return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (bgp_redistribute_ipv6_metric, + bgp_redistribute_ipv6_metric_cmd, + "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + u_int32_t metric; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + VTY_GET_INTEGER ("metric", metric, argv[1]); + + bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric); + return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (bgp_redistribute_ipv6_rmap_metric, + bgp_redistribute_ipv6_rmap_metric_cmd, + "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + u_int32_t metric; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + VTY_GET_INTEGER ("metric", metric, argv[2]); + + bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[1]); + bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric); + return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (bgp_redistribute_ipv6_metric_rmap, + bgp_redistribute_ipv6_metric_rmap_cmd, + "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type; + u_int32_t metric; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + VTY_GET_INTEGER ("metric", metric, argv[1]); + + bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric); + bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[2]); + return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (no_bgp_redistribute_ipv6, + no_bgp_redistribute_ipv6_cmd, + "no redistribute (connected|kernel|ospf6|ripng|static)", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_redistribute_unset (vty->index, AFI_IP6, type); +} + +DEFUN (no_bgp_redistribute_ipv6_rmap, + no_bgp_redistribute_ipv6_rmap_cmd, + "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_redistribute_ipv6_metric, + no_bgp_redistribute_ipv6_metric_cmd, + "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_metric_unset (vty->index, AFI_IP6, type); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_redistribute_ipv6_rmap_metric, + no_bgp_redistribute_ipv6_rmap_metric_cmd, + "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n" + "Metric for redistributed routes\n" + "Default metric\n") +{ + int type; + + type = bgp_str2route_type (AFI_IP6, argv[0]); + if (! type) + { + vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_redistribute_metric_unset (vty->index, AFI_IP6, type); + bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type); + return CMD_SUCCESS; +} + +ALIAS (no_bgp_redistribute_ipv6_rmap_metric, + no_bgp_redistribute_ipv6_metric_rmap_cmd, + "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n"); +#endif /* HAVE_IPV6 */ + +/* Show version. */ +DEFUN (show_version_bgpd, + show_version_bgpd_cmd, + "show version bgpd", + SHOW_STR + "Displays zebra version\n" + "Displays bgpd version\n") +{ + vty_out (vty, "Zebra BGPd version %s%s", ZEBRA_BGPD_VERSION, VTY_NEWLINE); + vty_out (vty, "Copyright 1996-2004, Kunihiro Ishiguro.%s", VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +int +bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi, int *write) +{ + int i; + char *str[] = { "system", "kernel", "connected", "static", "rip", + "ripng", "ospf", "ospf6", "bgp"}; + + /* Unicast redistribution only. */ + if (safi != SAFI_UNICAST) + return 0; + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + /* Redistribute BGP does not make sense. */ + if (bgp->redist[afi][i] && i != ZEBRA_ROUTE_BGP) + { + /* Display "address-family" when it is not yet diplayed. */ + bgp_config_write_family_header (vty, afi, safi, write); + + /* "redistribute" configuration. */ + vty_out (vty, " redistribute %s", str[i]); + + if (bgp->redist_metric_flag[afi][i]) + vty_out (vty, " metric %d", bgp->redist_metric[afi][i]); + + if (bgp->rmap[afi][i].name) + vty_out (vty, " route-map %s", bgp->rmap[afi][i].name); + + vty_out (vty, "%s", VTY_NEWLINE); + } + } + return *write; +} + +/* BGP node structure. */ +struct cmd_node bgp_node = + { + BGP_NODE, + "%s(config-router)# ", + 1, + }; + +struct cmd_node bgp_ipv4_unicast_node = + { + BGP_IPV4_NODE, + "%s(config-router-af)# ", + 1, + }; + +struct cmd_node bgp_ipv4_multicast_node = + { + BGP_IPV4M_NODE, + "%s(config-router-af)# ", + 1, + }; + +struct cmd_node bgp_ipv6_unicast_node = + { + BGP_IPV6_NODE, + "%s(config-router-af)# ", + 1, + }; + +struct cmd_node bgp_vpnv4_node = + { + BGP_VPNV4_NODE, + "%s(config-router-af)# ", + 1 + }; + +void +bgp_vty_init () +{ + int bgp_config_write (struct vty *); + void community_list_vty (); + + /* Install bgp top node. */ + install_node (&bgp_node, bgp_config_write); + install_node (&bgp_ipv4_unicast_node, NULL); + install_node (&bgp_ipv4_multicast_node, NULL); + install_node (&bgp_ipv6_unicast_node, NULL); + install_node (&bgp_vpnv4_node, NULL); + + /* Install default VTY commands to new nodes. */ + install_default (BGP_NODE); + install_default (BGP_IPV4_NODE); + install_default (BGP_IPV4M_NODE); + install_default (BGP_IPV6_NODE); + install_default (BGP_VPNV4_NODE); + + /* "bgp multiple-instance" commands. */ + install_element (CONFIG_NODE, &bgp_multiple_instance_cmd); + install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd); + + /* "bgp config-type" commands. */ + install_element (CONFIG_NODE, &bgp_config_type_cmd); + install_element (CONFIG_NODE, &no_bgp_config_type_cmd); + + /* Dummy commands (Currently not supported) */ + install_element (BGP_NODE, &no_synchronization_cmd); + install_element (BGP_IPV4_NODE, &no_synchronization_cmd); + install_element (BGP_IPV6_NODE, &no_synchronization_cmd); + install_element (BGP_NODE, &no_auto_summary_cmd); + install_element (BGP_IPV4_NODE, &no_auto_summary_cmd); + install_element (BGP_IPV4M_NODE, &no_auto_summary_cmd); + + /* "router bgp" commands. */ + install_element (CONFIG_NODE, &router_bgp_cmd); + install_element (CONFIG_NODE, &router_bgp_view_cmd); + + /* "no router bgp" commands. */ + install_element (CONFIG_NODE, &no_router_bgp_cmd); + install_element (CONFIG_NODE, &no_router_bgp_view_cmd); + + /* "bgp router-id" commands. */ + install_element (BGP_NODE, &bgp_router_id_cmd); + install_element (BGP_NODE, &no_bgp_router_id_cmd); + install_element (BGP_NODE, &no_bgp_router_id_val_cmd); + + /* "bgp cluster-id" commands. */ + install_element (BGP_NODE, &bgp_cluster_id_cmd); + install_element (BGP_NODE, &bgp_cluster_id32_cmd); + install_element (BGP_NODE, &no_bgp_cluster_id_cmd); + install_element (BGP_NODE, &no_bgp_cluster_id_arg_cmd); + + /* "bgp confederation" commands. */ + install_element (BGP_NODE, &bgp_confederation_identifier_cmd); + install_element (BGP_NODE, &no_bgp_confederation_identifier_cmd); + install_element (BGP_NODE, &no_bgp_confederation_identifier_arg_cmd); + + /* "bgp confederation peers" commands. */ + install_element (BGP_NODE, &bgp_confederation_peers_cmd); + install_element (BGP_NODE, &no_bgp_confederation_peers_cmd); + + /* "timers bgp" commands. */ + install_element (BGP_NODE, &bgp_timers_cmd); + install_element (BGP_NODE, &no_bgp_timers_cmd); + install_element (BGP_NODE, &no_bgp_timers_arg_cmd); + + /* "bgp client-to-client reflection" commands */ + install_element (BGP_NODE, &no_bgp_client_to_client_reflection_cmd); + install_element (BGP_NODE, &bgp_client_to_client_reflection_cmd); + + /* "bgp always-compare-med" commands */ + install_element (BGP_NODE, &bgp_always_compare_med_cmd); + install_element (BGP_NODE, &no_bgp_always_compare_med_cmd); + + /* "bgp deterministic-med" commands */ + install_element (BGP_NODE, &bgp_deterministic_med_cmd); + install_element (BGP_NODE, &no_bgp_deterministic_med_cmd); + + /* "bgp graceful-restart" commands */ + install_element (BGP_NODE, &bgp_graceful_restart_cmd); + install_element (BGP_NODE, &no_bgp_graceful_restart_cmd); + install_element (BGP_NODE, &bgp_graceful_restart_stalepath_time_cmd); + install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_cmd); + install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_val_cmd); + + /* "bgp fast-external-failover" commands */ + install_element (BGP_NODE, &bgp_fast_external_failover_cmd); + install_element (BGP_NODE, &no_bgp_fast_external_failover_cmd); + + /* "bgp enforce-first-as" commands */ + install_element (BGP_NODE, &bgp_enforce_first_as_cmd); + install_element (BGP_NODE, &no_bgp_enforce_first_as_cmd); + + /* "bgp bestpath compare-routerid" commands */ + install_element (BGP_NODE, &bgp_bestpath_compare_router_id_cmd); + install_element (BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd); + + /* "bgp bestpath cost-community ignore" commands */ + install_element (BGP_NODE, &bgp_bestpath_cost_community_ignore_cmd); + install_element (BGP_NODE, &no_bgp_bestpath_cost_community_ignore_cmd); + + /* "bgp bestpath as-path ignore" commands */ + install_element (BGP_NODE, &bgp_bestpath_aspath_ignore_cmd); + install_element (BGP_NODE, &no_bgp_bestpath_aspath_ignore_cmd); + + /* "bgp log-neighbor-changes" commands */ + install_element (BGP_NODE, &bgp_log_neighbor_changes_cmd); + install_element (BGP_NODE, &no_bgp_log_neighbor_changes_cmd); + + /* "bgp bestpath med" commands */ + install_element (BGP_NODE, &bgp_bestpath_med_cmd); + install_element (BGP_NODE, &bgp_bestpath_med2_cmd); + install_element (BGP_NODE, &bgp_bestpath_med3_cmd); + install_element (BGP_NODE, &no_bgp_bestpath_med_cmd); + install_element (BGP_NODE, &no_bgp_bestpath_med2_cmd); + install_element (BGP_NODE, &no_bgp_bestpath_med3_cmd); + + /* "no bgp default ipv4-unicast" commands. */ + install_element (BGP_NODE, &no_bgp_default_ipv4_unicast_cmd); + install_element (BGP_NODE, &bgp_default_ipv4_unicast_cmd); + + /* "bgp network import-check" commands. */ + install_element (BGP_NODE, &bgp_network_import_check_cmd); + install_element (BGP_NODE, &no_bgp_network_import_check_cmd); + + /* "bgp default local-preference" commands. */ + install_element (BGP_NODE, &bgp_default_local_preference_cmd); + install_element (BGP_NODE, &no_bgp_default_local_preference_cmd); + install_element (BGP_NODE, &no_bgp_default_local_preference_val_cmd); + + /* "neighbor remote-as" commands. */ + install_element (BGP_NODE, &neighbor_remote_as_cmd); + install_element (BGP_NODE, &no_neighbor_cmd); + install_element (BGP_NODE, &no_neighbor_remote_as_cmd); + + /* "neighbor peer-group" commands. */ + install_element (BGP_NODE, &neighbor_peer_group_cmd); + install_element (BGP_NODE, &no_neighbor_peer_group_cmd); + install_element (BGP_NODE, &no_neighbor_peer_group_remote_as_cmd); + + /* "neighbor local-as" commands. */ + install_element (BGP_NODE, &neighbor_local_as_cmd); + install_element (BGP_NODE, &neighbor_local_as_no_prepend_cmd); + install_element (BGP_NODE, &no_neighbor_local_as_cmd); + install_element (BGP_NODE, &no_neighbor_local_as_val_cmd); + install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd); + +#ifdef HAVE_TCP_SIGNATURE + /* "neighbor password" commands. */ + install_element (BGP_NODE, &neighbor_password_cmd); + install_element (BGP_NODE, &no_neighbor_password_cmd); +#endif /* HAVE_TCP_SIGNATURE */ + + /* "neighbor activate" commands. */ + install_element (BGP_NODE, &neighbor_activate_cmd); + install_element (BGP_IPV4_NODE, &neighbor_activate_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_activate_cmd); + install_element (BGP_IPV6_NODE, &neighbor_activate_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd); + + /* "no neighbor activate" commands. */ + install_element (BGP_NODE, &no_neighbor_activate_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_activate_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_activate_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd); + + /* "neighbor peer-group set" commands. */ + install_element (BGP_NODE, &neighbor_set_peer_group_cmd); + install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_cmd); + install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd); + + /* "no neighbor peer-group unset" commands. */ + install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd); + + /* "neighbor softreconfiguration inbound" commands.*/ + install_element (BGP_NODE, &neighbor_soft_reconfiguration_cmd); + install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd); + install_element (BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd); + install_element (BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd); + + /* "neighbor attribute-unchanged" commands. */ + install_element (BGP_NODE, &neighbor_attr_unchanged_cmd); + install_element (BGP_NODE, &neighbor_attr_unchanged1_cmd); + install_element (BGP_NODE, &neighbor_attr_unchanged2_cmd); + install_element (BGP_NODE, &neighbor_attr_unchanged3_cmd); + install_element (BGP_NODE, &neighbor_attr_unchanged4_cmd); + install_element (BGP_NODE, &neighbor_attr_unchanged5_cmd); + install_element (BGP_NODE, &neighbor_attr_unchanged6_cmd); + install_element (BGP_NODE, &neighbor_attr_unchanged7_cmd); + install_element (BGP_NODE, &neighbor_attr_unchanged8_cmd); + install_element (BGP_NODE, &neighbor_attr_unchanged9_cmd); + install_element (BGP_NODE, &neighbor_attr_unchanged10_cmd); + install_element (BGP_NODE, &no_neighbor_attr_unchanged_cmd); + install_element (BGP_NODE, &no_neighbor_attr_unchanged1_cmd); + install_element (BGP_NODE, &no_neighbor_attr_unchanged2_cmd); + install_element (BGP_NODE, &no_neighbor_attr_unchanged3_cmd); + install_element (BGP_NODE, &no_neighbor_attr_unchanged4_cmd); + install_element (BGP_NODE, &no_neighbor_attr_unchanged5_cmd); + install_element (BGP_NODE, &no_neighbor_attr_unchanged6_cmd); + install_element (BGP_NODE, &no_neighbor_attr_unchanged7_cmd); + install_element (BGP_NODE, &no_neighbor_attr_unchanged8_cmd); + install_element (BGP_NODE, &no_neighbor_attr_unchanged9_cmd); + install_element (BGP_NODE, &no_neighbor_attr_unchanged10_cmd); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged_cmd); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged1_cmd); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged2_cmd); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged3_cmd); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged4_cmd); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged5_cmd); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged6_cmd); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged7_cmd); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged8_cmd); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged9_cmd); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged10_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged1_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged2_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged3_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged4_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged5_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged6_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged7_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged8_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged9_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged10_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged1_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged2_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged3_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged4_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged5_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged6_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged7_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged8_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged9_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged10_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged1_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged2_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged3_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged4_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged5_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged6_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged7_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged8_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged9_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged10_cmd); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged1_cmd); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged2_cmd); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged3_cmd); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged4_cmd); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged5_cmd); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged6_cmd); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged7_cmd); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged8_cmd); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged9_cmd); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged10_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged1_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged2_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged3_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged4_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged5_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged6_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged7_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged8_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged9_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged10_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged1_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged2_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged3_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged4_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged5_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged6_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged7_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged8_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged9_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged10_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged1_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged2_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged3_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged4_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged5_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged6_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged7_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged8_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged9_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged10_cmd); + + /* "neighbor next-hop-self" commands. */ + install_element (BGP_NODE, &neighbor_nexthop_self_cmd); + install_element (BGP_NODE, &no_neighbor_nexthop_self_cmd); + install_element (BGP_IPV4_NODE, &neighbor_nexthop_self_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd); + install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd); + + /* "neighbor remove-private-AS" commands. */ + install_element (BGP_NODE, &neighbor_remove_private_as_cmd); + install_element (BGP_NODE, &no_neighbor_remove_private_as_cmd); + install_element (BGP_IPV4_NODE, &neighbor_remove_private_as_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_remove_private_as_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_cmd); + install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd); + + /* "neighbor send-community" commands.*/ + install_element (BGP_NODE, &neighbor_send_community_cmd); + install_element (BGP_NODE, &neighbor_send_community_type_cmd); + install_element (BGP_NODE, &no_neighbor_send_community_cmd); + install_element (BGP_NODE, &no_neighbor_send_community_type_cmd); + install_element (BGP_IPV4_NODE, &neighbor_send_community_cmd); + install_element (BGP_IPV4_NODE, &neighbor_send_community_type_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_send_community_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_send_community_type_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_send_community_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_send_community_type_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd); + install_element (BGP_IPV6_NODE, &neighbor_send_community_cmd); + install_element (BGP_IPV6_NODE, &neighbor_send_community_type_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_send_community_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_send_community_type_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_send_community_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_type_cmd); + + /* "neighbor route-reflector" commands.*/ + install_element (BGP_NODE, &neighbor_route_reflector_client_cmd); + install_element (BGP_NODE, &no_neighbor_route_reflector_client_cmd); + install_element (BGP_IPV4_NODE, &neighbor_route_reflector_client_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_route_reflector_client_cmd); + install_element (BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd); + + /* "neighbor route-server" commands.*/ + install_element (BGP_NODE, &neighbor_route_server_client_cmd); + install_element (BGP_NODE, &no_neighbor_route_server_client_cmd); + install_element (BGP_IPV4_NODE, &neighbor_route_server_client_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_route_server_client_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd); + install_element (BGP_IPV6_NODE, &neighbor_route_server_client_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd); + + /* "neighbor transport connection-mode" commands. */ + install_element (BGP_NODE, &neighbor_transport_connection_mode_cmd); + install_element (BGP_NODE, &no_neighbor_transport_connection_mode_cmd); + install_element (BGP_NODE, &no_neighbor_transport_connection_mode_val_cmd); + install_element (BGP_NODE, &neighbor_passive_cmd); + + /* "neighbor shutdown" commands. */ + install_element (BGP_NODE, &neighbor_shutdown_cmd); + install_element (BGP_NODE, &no_neighbor_shutdown_cmd); + + /* "neighbor capability orf prefix-list" commands.*/ + install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd); + install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd); + install_element (BGP_IPV4_NODE, &neighbor_capability_orf_prefix_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd); + install_element (BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd); + + /* "neighbor capability dynamic" commands.*/ + install_element (BGP_NODE, &neighbor_capability_dynamic_cmd); + install_element (BGP_NODE, &no_neighbor_capability_dynamic_cmd); + + /* "neighbor dont-capability-negotiate" commands. */ + install_element (BGP_NODE, &neighbor_dont_capability_negotiate_cmd); + install_element (BGP_NODE, &no_neighbor_dont_capability_negotiate_cmd); + + /* "neighbor ebgp-multihop" commands. */ + install_element (BGP_NODE, &neighbor_ebgp_multihop_cmd); + install_element (BGP_NODE, &neighbor_ebgp_multihop_ttl_cmd); + install_element (BGP_NODE, &no_neighbor_ebgp_multihop_cmd); + install_element (BGP_NODE, &no_neighbor_ebgp_multihop_ttl_cmd); + + /* "neighbor disable-connected-check" commands. */ + install_element (BGP_NODE, &neighbor_disable_connected_check_cmd); + install_element (BGP_NODE, &no_neighbor_disable_connected_check_cmd); + install_element (BGP_NODE, &neighbor_enforce_multihop_cmd); + + /* "neighbor description" commands. */ + install_element (BGP_NODE, &neighbor_description_cmd); + install_element (BGP_NODE, &no_neighbor_description_cmd); + install_element (BGP_NODE, &no_neighbor_description_val_cmd); + + /* "neighbor update-source" commands. "*/ + install_element (BGP_NODE, &neighbor_update_source_cmd); + install_element (BGP_NODE, &no_neighbor_update_source_cmd); + + /* "neighbor default-originate" commands. */ + install_element (BGP_NODE, &neighbor_default_originate_cmd); + install_element (BGP_NODE, &neighbor_default_originate_rmap_cmd); + install_element (BGP_NODE, &no_neighbor_default_originate_cmd); + install_element (BGP_NODE, &no_neighbor_default_originate_rmap_cmd); + install_element (BGP_IPV4_NODE, &neighbor_default_originate_cmd); + install_element (BGP_IPV4_NODE, &neighbor_default_originate_rmap_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_rmap_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_default_originate_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_rmap_cmd); + install_element (BGP_IPV6_NODE, &neighbor_default_originate_cmd); + install_element (BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_rmap_cmd); + + /* "neighbor port" commands. */ + install_element (BGP_NODE, &neighbor_port_cmd); + install_element (BGP_NODE, &no_neighbor_port_cmd); + install_element (BGP_NODE, &no_neighbor_port_val_cmd); + + /* "neighbor weight" commands. */ + install_element (BGP_NODE, &neighbor_weight_cmd); + install_element (BGP_IPV4_NODE, &neighbor_weight_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_weight_cmd); + install_element (BGP_IPV6_NODE, &neighbor_weight_cmd); + install_element (BGP_NODE, &no_neighbor_weight_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_weight_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_weight_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_weight_cmd); + install_element (BGP_NODE, &no_neighbor_weight_val_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_weight_val_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_weight_val_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_weight_val_cmd); + + /* "neighbor override-capability" commands. */ + install_element (BGP_NODE, &neighbor_override_capability_cmd); + install_element (BGP_NODE, &no_neighbor_override_capability_cmd); + + /* "neighbor strict-capability-match" commands. */ + install_element (BGP_NODE, &neighbor_strict_capability_cmd); + install_element (BGP_NODE, &no_neighbor_strict_capability_cmd); + + /* "neighbor timers" commands. */ + install_element (BGP_NODE, &neighbor_timers_cmd); + install_element (BGP_NODE, &no_neighbor_timers_cmd); + + /* "neighbor advertisement-interval" commands. */ + install_element (BGP_NODE, &neighbor_advertise_interval_cmd); + install_element (BGP_NODE, &no_neighbor_advertise_interval_cmd); + install_element (BGP_NODE, &no_neighbor_advertise_interval_val_cmd); + + /* "neighbor version" commands. */ + install_element (BGP_NODE, &neighbor_version_cmd); + + /* "neighbor interface" commands. */ + install_element (BGP_NODE, &neighbor_interface_cmd); + install_element (BGP_NODE, &no_neighbor_interface_cmd); + + /* "neighbor distribute" commands. */ + install_element (BGP_NODE, &neighbor_distribute_list_cmd); + install_element (BGP_NODE, &no_neighbor_distribute_list_cmd); + install_element (BGP_IPV4_NODE, &neighbor_distribute_list_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_distribute_list_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd); + install_element (BGP_IPV6_NODE, &neighbor_distribute_list_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd); + + /* "neighbor prefix-list" commands. */ + install_element (BGP_NODE, &neighbor_prefix_list_cmd); + install_element (BGP_NODE, &no_neighbor_prefix_list_cmd); + install_element (BGP_IPV4_NODE, &neighbor_prefix_list_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_prefix_list_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd); + install_element (BGP_IPV6_NODE, &neighbor_prefix_list_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd); + + /* "neighbor filter-list" commands. */ + install_element (BGP_NODE, &neighbor_filter_list_cmd); + install_element (BGP_NODE, &no_neighbor_filter_list_cmd); + install_element (BGP_IPV4_NODE, &neighbor_filter_list_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_filter_list_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_filter_list_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd); + install_element (BGP_IPV6_NODE, &neighbor_filter_list_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_filter_list_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd); + + /* "neighbor route-map" commands. */ + install_element (BGP_NODE, &neighbor_route_map_cmd); + install_element (BGP_NODE, &no_neighbor_route_map_cmd); + install_element (BGP_IPV4_NODE, &neighbor_route_map_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_route_map_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_route_map_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_route_map_cmd); + install_element (BGP_IPV6_NODE, &neighbor_route_map_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_route_map_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd); + + /* "neighbor unsuppress-map" commands. */ + install_element (BGP_NODE, &neighbor_unsuppress_map_cmd); + install_element (BGP_NODE, &no_neighbor_unsuppress_map_cmd); + install_element (BGP_IPV4_NODE, &neighbor_unsuppress_map_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd); + install_element (BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd); + + /* "neighbor maximum-prefix" commands. */ + install_element (BGP_NODE, &neighbor_maximum_prefix_cmd); + install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_NODE, &no_neighbor_maximum_prefix_cmd); + install_element (BGP_NODE, &no_neighbor_maximum_prefix_val_cmd); + install_element (BGP_NODE, &no_neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_NODE, &no_neighbor_maximum_prefix_warning_cmd); + install_element (BGP_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_NODE, &no_neighbor_maximum_prefix_restart_cmd); + install_element (BGP_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_cmd); + install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_val_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_warning_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_restart_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_val_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_warning_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_restart_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd); + install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_val_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_warning_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_restart_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_val_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_threshold_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_warning_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_restart_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); + + /* "neighbor allowas-in" */ + install_element (BGP_NODE, &neighbor_allowas_in_cmd); + install_element (BGP_NODE, &neighbor_allowas_in_arg_cmd); + install_element (BGP_NODE, &no_neighbor_allowas_in_cmd); + install_element (BGP_IPV4_NODE, &neighbor_allowas_in_cmd); + install_element (BGP_IPV4_NODE, &neighbor_allowas_in_arg_cmd); + install_element (BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_cmd); + install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_arg_cmd); + install_element (BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd); + install_element (BGP_IPV6_NODE, &neighbor_allowas_in_cmd); + install_element (BGP_IPV6_NODE, &neighbor_allowas_in_arg_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd); + install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_arg_cmd); + install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd); + + /* address-family commands. */ + install_element (BGP_NODE, &address_family_ipv4_cmd); + install_element (BGP_NODE, &address_family_ipv4_safi_cmd); +#ifdef HAVE_IPV6 + install_element (BGP_NODE, &address_family_ipv6_cmd); + install_element (BGP_NODE, &address_family_ipv6_unicast_cmd); +#endif /* HAVE_IPV6 */ + install_element (BGP_NODE, &address_family_vpnv4_cmd); + install_element (BGP_NODE, &address_family_vpnv4_unicast_cmd); + + /* "exit-address-family" command. */ + install_element (BGP_IPV4_NODE, &exit_address_family_cmd); + install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); + install_element (BGP_IPV6_NODE, &exit_address_family_cmd); + install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); + + /* "clear ip bgp commands" */ + install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_external_cmd); +#ifdef HAVE_IPV6 + install_element (ENABLE_NODE, &clear_bgp_all_cmd); + install_element (ENABLE_NODE, &clear_bgp_instance_all_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_group_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_cmd); + install_element (ENABLE_NODE, &clear_bgp_external_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_cmd); + install_element (ENABLE_NODE, &clear_bgp_as_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_cmd); +#endif /* HAVE_IPV6 */ + + /* "clear ip bgp neighbor soft in" */ + install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_external_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_external_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_in_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_in_cmd); +#ifdef HAVE_IPV6 + install_element (ENABLE_NODE, &clear_bgp_all_soft_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_all_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_all_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_soft_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_group_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_group_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_bgp_external_soft_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_external_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_external_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_bgp_as_soft_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_as_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_as_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_prefix_filter_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd); +#endif /* HAVE_IPV6 */ + + /* "clear ip bgp neighbor soft out" */ + install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_external_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_out_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_out_cmd); +#ifdef HAVE_IPV6 + install_element (ENABLE_NODE, &clear_bgp_all_soft_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_all_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_soft_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_group_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_external_soft_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_external_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_as_soft_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_as_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_out_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_out_cmd); +#endif /* HAVE_IPV6 */ + + /* "clear ip bgp neighbor soft" */ + install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_cmd); +#ifdef HAVE_IPV6 + install_element (ENABLE_NODE, &clear_bgp_all_soft_cmd); + install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_soft_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_cmd); + install_element (ENABLE_NODE, &clear_bgp_external_soft_cmd); + install_element (ENABLE_NODE, &clear_bgp_as_soft_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_cmd); +#endif /* HAVE_IPV6 */ + + /* "show ip bgp summary" commands. */ + install_element (VIEW_NODE, &show_ip_bgp_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); +#ifdef HAVE_IPV6 + install_element (VIEW_NODE, &show_bgp_summary_cmd); + install_element (VIEW_NODE, &show_bgp_instance_summary_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd); + install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd); +#endif /* HAVE_IPV6 */ + install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); +#ifdef HAVE_IPV6 + install_element (ENABLE_NODE, &show_bgp_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd); +#endif /* HAVE_IPV6 */ + + /* "show ip bgp neighbors" commands. */ + install_element (VIEW_NODE, &show_ip_bgp_neighbors_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_cmd); + install_element (VIEW_NODE, &show_ip_bgp_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbors_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); + +#ifdef HAVE_IPV6 + install_element (VIEW_NODE, &show_bgp_neighbors_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd); + install_element (VIEW_NODE, &show_bgp_neighbors_peer_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbors_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_cmd); + install_element (ENABLE_NODE, &show_bgp_neighbors_peer_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_peer_cmd); +#endif /* HAVE_IPV6 */ + + /* "show ip bgp paths" commands. */ + install_element (VIEW_NODE, &show_ip_bgp_paths_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_paths_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_paths_cmd); + + /* "show ip bgp community" commands. */ + install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_community_info_cmd); + + /* "show ip bgp attribute-info" commands. */ + install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_attr_info_cmd); + + /* "redistribute" commands. */ + install_element (BGP_NODE, &bgp_redistribute_ipv4_cmd); + install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_cmd); + install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_cmd); + install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_metric_cmd); + install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd); + install_element (BGP_IPV4_NODE, &bgp_redistribute_ipv4_cmd); + install_element (BGP_IPV4_NODE, &bgp_redistribute_ipv4_rmap_cmd); + install_element (BGP_IPV4_NODE, &bgp_redistribute_ipv4_metric_cmd); + install_element (BGP_IPV4_NODE, &bgp_redistribute_ipv4_rmap_metric_cmd); + install_element (BGP_IPV4_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd); + install_element (BGP_NODE, &no_bgp_redistribute_ipv4_cmd); + install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_cmd); + install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_cmd); + install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_metric_cmd); + install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_rmap_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_redistribute_ipv4_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_redistribute_ipv4_rmap_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_redistribute_ipv4_metric_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_redistribute_ipv4_rmap_metric_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_redistribute_ipv4_metric_rmap_cmd); +#ifdef HAVE_IPV6 + install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_cmd); + install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_cmd); + install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_cmd); + install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_cmd); + install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd); + install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_cmd); + install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd); + install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd); + install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_metric_cmd); + install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd); +#endif /* HAVE_IPV6 */ + + /* Community-list. */ + community_list_vty (); +} + +#include "memory.h" +#include "bgp_regex.h" +#include "bgp_clist.h" +#include "bgp_ecommunity.h" + +/* VTY functions. */ + +/* Direction value to string conversion. */ +char * +community_direct_str (int direct) +{ + switch (direct) + { + case COMMUNITY_DENY: + return "deny"; + break; + case COMMUNITY_PERMIT: + return "permit"; + break; + default: + return "unknown"; + break; + } +} + +/* Display error string. */ +void +community_list_perror (struct vty *vty, int ret) +{ + switch (ret) + { + case COMMUNITY_LIST_ERR_CANT_FIND_LIST: + vty_out (vty, "%% Can't find communit-list%s", VTY_NEWLINE); + break; + case COMMUNITY_LIST_ERR_MALFORMED_VAL: + vty_out (vty, "%% Malformed community-list value%s", VTY_NEWLINE); + break; + case COMMUNITY_LIST_ERR_STANDARD_CONFLICT: + vty_out (vty, "%% Community name conflict, previously defined as standard community%s", VTY_NEWLINE); + break; + case COMMUNITY_LIST_ERR_EXPANDED_CONFLICT: + vty_out (vty, "%% Community name conflict, previously defined as expanded community%s", VTY_NEWLINE); + break; + } +} + +/* VTY interface for community_set() function. */ +int +community_list_set_vty (struct vty *vty, int argc, char **argv, int style, + int reject_all_digit_name) +{ + int ret; + int direct; + char *str; + + /* Check the list type. */ + if (strncmp (argv[1], "p", 1) == 0) + direct = COMMUNITY_PERMIT; + else if (strncmp (argv[1], "d", 1) == 0) + direct = COMMUNITY_DENY; + else + { + vty_out (vty, "%% Matching condition must be permit or deny%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* All digit name check. */ + if (reject_all_digit_name && all_digit (argv[0])) + { + vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Concat community string argument. */ + if (argc > 1) + str = argv_concat (argv, argc, 2); + else + str = NULL; + + /* When community_list_set() return nevetive value, it means + malformed community string. */ + ret = community_list_set (bgp_clist, argv[0], str, direct, style); + + /* Free temporary community list string allocated by + argv_concat(). */ + if (str) + XFREE (MTYPE_TMP, str); + + if (ret < 0) + { + /* Display error string. */ + community_list_perror (vty, ret); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* Communiyt-list entry delete. */ +int +community_list_unset_vty (struct vty *vty, int argc, char **argv, int style) +{ + int ret; + int direct = 0; + char *str = NULL; + + if (argc > 1) + { + /* Check the list direct. */ + if (strncmp (argv[1], "p", 1) == 0) + direct = COMMUNITY_PERMIT; + else if (strncmp (argv[1], "d", 1) == 0) + direct = COMMUNITY_DENY; + else + { + vty_out (vty, "%% Matching condition must be permit or deny%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Concat community string argument. */ + str = argv_concat (argv, argc, 2); + } + + /* Unset community list. */ + ret = community_list_unset (bgp_clist, argv[0], str, direct, style); + + /* Free temporary community list string allocated by + argv_concat(). */ + if (str) + XFREE (MTYPE_TMP, str); + + if (ret < 0) + { + community_list_perror (vty, ret); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* "community-list" keyword help string. */ +#define COMMUNITY_LIST_STR "Add a community list entry\n" +#define COMMUNITY_VAL_STR "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n" + +DEFUN (ip_community_list_standard, + ip_community_list_standard_cmd, + "ip community-list <1-99> (deny|permit) .AA:NN", + IP_STR + COMMUNITY_LIST_STR + "Community list number (standard)\n" + "Specify community to reject\n" + "Specify community to accept\n" + COMMUNITY_VAL_STR) +{ + return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD, 0); +} + +ALIAS (ip_community_list_standard, + ip_community_list_standard2_cmd, + "ip community-list <1-99> (deny|permit)", + IP_STR + COMMUNITY_LIST_STR + "Community list number (standard)\n" + "Specify community to reject\n" + "Specify community to accept\n"); + +DEFUN (ip_community_list_expanded, + ip_community_list_expanded_cmd, + "ip community-list <100-500> (deny|permit) .LINE", + IP_STR + COMMUNITY_LIST_STR + "Community list number (expanded)\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") +{ + return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED, 0); +} + +DEFUN (ip_community_list_name_standard, + ip_community_list_name_standard_cmd, + "ip community-list standard WORD (deny|permit) .AA:NN", + IP_STR + COMMUNITY_LIST_STR + "Add a standard community-list entry\n" + "Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + COMMUNITY_VAL_STR) +{ + return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD, 1); +} + +ALIAS (ip_community_list_name_standard, + ip_community_list_name_standard2_cmd, + "ip community-list standard WORD (deny|permit)", + IP_STR + COMMUNITY_LIST_STR + "Add a standard community-list entry\n" + "Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n"); + +DEFUN (ip_community_list_name_expanded, + ip_community_list_name_expanded_cmd, + "ip community-list expanded WORD (deny|permit) .LINE", + IP_STR + COMMUNITY_LIST_STR + "Add an expanded community-list entry\n" + "Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") +{ + return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED, 1); +} + +DEFUN (no_ip_community_list_standard_all, + no_ip_community_list_standard_all_cmd, + "no ip community-list <1-99>", + NO_STR + IP_STR + COMMUNITY_LIST_STR + "Community list number (standard)\n") +{ + return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_community_list_expanded_all, + no_ip_community_list_expanded_all_cmd, + "no ip community-list <100-500>", + NO_STR + IP_STR + COMMUNITY_LIST_STR + "Community list number (expanded)\n") +{ + return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED); +} + +DEFUN (no_ip_community_list_name_standard_all, + no_ip_community_list_name_standard_all_cmd, + "no ip community-list standard WORD", + NO_STR + IP_STR + COMMUNITY_LIST_STR + "Add a standard community-list entry\n" + "Community list name\n") +{ + return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_community_list_name_expanded_all, + no_ip_community_list_name_expanded_all_cmd, + "no ip community-list expanded WORD", + NO_STR + IP_STR + COMMUNITY_LIST_STR + "Add an expanded community-list entry\n" + "Community list name\n") +{ + return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED); +} + +DEFUN (no_ip_community_list_standard, + no_ip_community_list_standard_cmd, + "no ip community-list <1-99> (deny|permit) .AA:NN", + NO_STR + IP_STR + COMMUNITY_LIST_STR + "Community list number (standard)\n" + "Specify community to reject\n" + "Specify community to accept\n" + COMMUNITY_VAL_STR) +{ + return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_community_list_expanded, + no_ip_community_list_expanded_cmd, + "no ip community-list <100-500> (deny|permit) .LINE", + NO_STR + IP_STR + COMMUNITY_LIST_STR + "Community list number (expanded)\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") +{ + return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED); +} + +DEFUN (no_ip_community_list_name_standard, + no_ip_community_list_name_standard_cmd, + "no ip community-list standard WORD (deny|permit) .AA:NN", + NO_STR + IP_STR + COMMUNITY_LIST_STR + "Specify a standard community-list\n" + "Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + COMMUNITY_VAL_STR) +{ + return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_community_list_name_expanded, + no_ip_community_list_name_expanded_cmd, + "no ip community-list expanded WORD (deny|permit) .LINE", + NO_STR + IP_STR + COMMUNITY_LIST_STR + "Specify an expanded community-list\n" + "Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") +{ + return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED); +} + +void +community_list_show (struct vty *vty, struct community_list *list) +{ + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) + { + if (entry == list->head) + { + if (all_digit (list->name)) + vty_out (vty, "Community %s list %s%s", + entry->style == COMMUNITY_LIST_STANDARD ? + "standard" : "(expanded) access", + list->name, VTY_NEWLINE); + else + vty_out (vty, "Named Community %s list %s%s", + entry->style == COMMUNITY_LIST_STANDARD ? + "standard" : "expanded", + list->name, VTY_NEWLINE); + } + if (entry->any) + vty_out (vty, " %s%s", + community_direct_str (entry->direct), VTY_NEWLINE); + else + vty_out (vty, " %s %s%s", + community_direct_str (entry->direct), + entry->style == COMMUNITY_LIST_STANDARD + ? community_str (entry->u.com) : entry->config, + VTY_NEWLINE); + } +} + +DEFUN (show_ip_community_list, + show_ip_community_list_cmd, + "show ip community-list", + SHOW_STR + IP_STR + "List community-list\n") +{ + struct community_list *list; + struct community_list_master *cm; + + cm = community_list_master_lookup (bgp_clist, COMMUNITY_LIST_MASTER); + if (! cm) + return CMD_SUCCESS; + + for (list = cm->num.head; list; list = list->next) + community_list_show (vty, list); + + for (list = cm->str.head; list; list = list->next) + community_list_show (vty, list); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_community_list_arg, + show_ip_community_list_arg_cmd, + "show ip community-list (<1-500>|WORD)", + SHOW_STR + IP_STR + "List community-list\n" + "Community-list number\n" + "Community-list name\n") +{ + struct community_list *list; + + list = community_list_lookup (bgp_clist, argv[0], COMMUNITY_LIST_MASTER); + if (! list) + { + vty_out (vty, "%% Can't find communit-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + community_list_show (vty, list); + + return CMD_SUCCESS; +} + +int +extcommunity_list_set_vty (struct vty *vty, int argc, char **argv, int style, + int reject_all_digit_name) +{ + int ret; + int direct; + char *str; + + /* Check the list type. */ + if (strncmp (argv[1], "p", 1) == 0) + direct = COMMUNITY_PERMIT; + else if (strncmp (argv[1], "d", 1) == 0) + direct = COMMUNITY_DENY; + else + { + vty_out (vty, "%% Matching condition must be permit or deny%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* All digit name check. */ + if (reject_all_digit_name && all_digit (argv[0])) + { + vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Concat community string argument. */ + if (argc > 1) + str = argv_concat (argv, argc, 2); + else + str = NULL; + + ret = extcommunity_list_set (bgp_clist, argv[0], str, direct, style); + + /* Free temporary community list string allocated by + argv_concat(). */ + if (str) + XFREE (MTYPE_TMP, str); + + if (ret < 0) + { + community_list_perror (vty, ret); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +int +extcommunity_list_unset_vty (struct vty *vty, int argc, char **argv, int style) +{ + int ret; + int direct = 0; + char *str = NULL; + + if (argc > 1) + { + /* Check the list direct. */ + if (strncmp (argv[1], "p", 1) == 0) + direct = COMMUNITY_PERMIT; + else if (strncmp (argv[1], "d", 1) == 0) + direct = COMMUNITY_DENY; + else + { + vty_out (vty, "%% Matching condition must be permit or deny%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Concat community string argument. */ + str = argv_concat (argv, argc, 2); + } + + /* Unset community list. */ + ret = extcommunity_list_unset (bgp_clist, argv[0], str, direct, style); + + /* Free temporary community list string allocated by + argv_concat(). */ + if (str) + XFREE (MTYPE_TMP, str); + + if (ret < 0) + { + community_list_perror (vty, ret); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* "extcommunity-list" keyword help string. */ +#define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n" +#define EXTCOMMUNITY_VAL_STR "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n" + +DEFUN (ip_extcommunity_list_standard, + ip_extcommunity_list_standard_cmd, + "ip extcommunity-list <1-99> (deny|permit) .AA:NN", + IP_STR + EXTCOMMUNITY_LIST_STR + "Extended Community list number (standard)\n" + "Specify community to reject\n" + "Specify community to accept\n" + EXTCOMMUNITY_VAL_STR) +{ + return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD, 0); +} + +ALIAS (ip_extcommunity_list_standard, + ip_extcommunity_list_standard2_cmd, + "ip extcommunity-list <1-99> (deny|permit)", + IP_STR + EXTCOMMUNITY_LIST_STR + "Extended Community list number (standard)\n" + "Specify community to reject\n" + "Specify community to accept\n"); + +DEFUN (ip_extcommunity_list_expanded, + ip_extcommunity_list_expanded_cmd, + "ip extcommunity-list <100-500> (deny|permit) .LINE", + IP_STR + EXTCOMMUNITY_LIST_STR + "Extended Community list number (expanded)\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") +{ + return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED, 0); +} + +DEFUN (ip_extcommunity_list_name_standard, + ip_extcommunity_list_name_standard_cmd, + "ip extcommunity-list standard WORD (deny|permit) .AA:NN", + IP_STR + EXTCOMMUNITY_LIST_STR + "Specify standard extcommunity-list\n" + "Extended Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + EXTCOMMUNITY_VAL_STR) +{ + return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD, 1); +} + +ALIAS (ip_extcommunity_list_name_standard, + ip_extcommunity_list_name_standard2_cmd, + "ip extcommunity-list standard WORD (deny|permit)", + IP_STR + EXTCOMMUNITY_LIST_STR + "Specify standard extcommunity-list\n" + "Extended Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n"); + +DEFUN (ip_extcommunity_list_name_expanded, + ip_extcommunity_list_name_expanded_cmd, + "ip extcommunity-list expanded WORD (deny|permit) .LINE", + IP_STR + EXTCOMMUNITY_LIST_STR + "Specify expanded extcommunity-list\n" + "Extended Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") +{ + return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED, 1); +} + +DEFUN (no_ip_extcommunity_list_standard_all, + no_ip_extcommunity_list_standard_all_cmd, + "no ip extcommunity-list <1-99>", + NO_STR + IP_STR + EXTCOMMUNITY_LIST_STR + "Extended Community list number (standard)\n") +{ + return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_extcommunity_list_expanded_all, + no_ip_extcommunity_list_expanded_all_cmd, + "no ip extcommunity-list <100-500>", + NO_STR + IP_STR + EXTCOMMUNITY_LIST_STR + "Extended Community list number (expanded)\n") +{ + return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED); +} + +DEFUN (no_ip_extcommunity_list_name_standard_all, + no_ip_extcommunity_list_name_standard_all_cmd, + "no ip extcommunity-list standard WORD", + NO_STR + IP_STR + EXTCOMMUNITY_LIST_STR + "Specify standard extcommunity-list\n" + "Extended Community list name\n") +{ + return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_extcommunity_list_name_expanded_all, + no_ip_extcommunity_list_name_expanded_all_cmd, + "no ip extcommunity-list expanded WORD", + NO_STR + IP_STR + EXTCOMMUNITY_LIST_STR + "Specify expanded extcommunity-list\n" + "Extended Community list name\n") +{ + return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED); +} + +DEFUN (no_ip_extcommunity_list_standard, + no_ip_extcommunity_list_standard_cmd, + "no ip extcommunity-list <1-99> (deny|permit) .AA:NN", + NO_STR + IP_STR + EXTCOMMUNITY_LIST_STR + "Extended Community list number (standard)\n" + "Specify community to reject\n" + "Specify community to accept\n" + EXTCOMMUNITY_VAL_STR) +{ + return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_extcommunity_list_expanded, + no_ip_extcommunity_list_expanded_cmd, + "no ip extcommunity-list <100-500> (deny|permit) .LINE", + NO_STR + IP_STR + EXTCOMMUNITY_LIST_STR + "Extended Community list number (expanded)\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") +{ + return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED); +} + +DEFUN (no_ip_extcommunity_list_name_standard, + no_ip_extcommunity_list_name_standard_cmd, + "no ip extcommunity-list standard WORD (deny|permit) .AA:NN", + NO_STR + IP_STR + EXTCOMMUNITY_LIST_STR + "Specify standard extcommunity-list\n" + "Extended Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + EXTCOMMUNITY_VAL_STR) +{ + return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_extcommunity_list_name_expanded, + no_ip_extcommunity_list_name_expanded_cmd, + "no ip extcommunity-list expanded WORD (deny|permit) .LINE", + NO_STR + IP_STR + EXTCOMMUNITY_LIST_STR + "Specify expanded extcommunity-list\n" + "Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") +{ + return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED); +} + +void +extcommunity_list_show (struct vty *vty, struct community_list *list) +{ + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) + { + if (entry == list->head) + { + if (all_digit (list->name)) + vty_out (vty, "Extended community %s list %s%s", + entry->style == EXTCOMMUNITY_LIST_STANDARD ? + "standard" : "(expanded) access", + list->name, VTY_NEWLINE); + else + vty_out (vty, "Named extended community %s list %s%s", + entry->style == EXTCOMMUNITY_LIST_STANDARD ? + "standard" : "expanded", + list->name, VTY_NEWLINE); + } + if (entry->any) + vty_out (vty, " %s%s", + community_direct_str (entry->direct), VTY_NEWLINE); + else + vty_out (vty, " %s %s%s", + community_direct_str (entry->direct), + entry->style == EXTCOMMUNITY_LIST_STANDARD ? + entry->u.ecom->str : entry->config, + VTY_NEWLINE); + } +} + +DEFUN (show_ip_extcommunity_list, + show_ip_extcommunity_list_cmd, + "show ip extcommunity-list", + SHOW_STR + IP_STR + "List extended-community list\n") +{ + struct community_list *list; + struct community_list_master *cm; + + cm = community_list_master_lookup (bgp_clist, EXTCOMMUNITY_LIST_MASTER); + if (! cm) + return CMD_SUCCESS; + + for (list = cm->num.head; list; list = list->next) + extcommunity_list_show (vty, list); + + for (list = cm->str.head; list; list = list->next) + extcommunity_list_show (vty, list); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_extcommunity_list_arg, + show_ip_extcommunity_list_arg_cmd, + "show ip extcommunity-list (<1-500>|WORD)", + SHOW_STR + IP_STR + "List extended-community list\n" + "Extcommunity-list number\n" + "Extcommunity-list name\n") +{ + struct community_list *list; + + list = community_list_lookup (bgp_clist, argv[0], EXTCOMMUNITY_LIST_MASTER); + if (! list) + { + vty_out (vty, "%% Can't find extcommunit-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + extcommunity_list_show (vty, list); + + return CMD_SUCCESS; +} + +/* Return configuration string of community-list entry. */ +static char * +community_list_config_str (struct community_entry *entry) +{ + char *str; + + if (entry->any) + str = ""; + else + { + if (entry->style == COMMUNITY_LIST_STANDARD) + str = community_str (entry->u.com); + else + str = entry->config; + } + return str; +} + +/* Display community-list and extcommunity-list configuration. */ +int +community_list_config_write (struct vty *vty) +{ + struct community_list *list; + struct community_entry *entry; + struct community_list_master *cm; + int write = 0; + + /* Community-list. */ + cm = community_list_master_lookup (bgp_clist, COMMUNITY_LIST_MASTER); + + for (list = cm->num.head; list; list = list->next) + for (entry = list->head; entry; entry = entry->next) + { + vty_out (vty, "ip community-list %s %s %s%s", + list->name, community_direct_str (entry->direct), + community_list_config_str (entry), + VTY_NEWLINE); + write++; + } + for (list = cm->str.head; list; list = list->next) + for (entry = list->head; entry; entry = entry->next) + { + vty_out (vty, "ip community-list %s %s %s %s%s", + entry->style == COMMUNITY_LIST_STANDARD + ? "standard" : "expanded", + list->name, community_direct_str (entry->direct), + community_list_config_str (entry), + VTY_NEWLINE); + write++; + } + + /* Extcommunity-list. */ + cm = community_list_master_lookup (bgp_clist, EXTCOMMUNITY_LIST_MASTER); + + for (list = cm->num.head; list; list = list->next) + for (entry = list->head; entry; entry = entry->next) + { + vty_out (vty, "ip extcommunity-list %s %s %s%s", + list->name, community_direct_str (entry->direct), + community_list_config_str (entry), VTY_NEWLINE); + write++; + } + for (list = cm->str.head; list; list = list->next) + for (entry = list->head; entry; entry = entry->next) + { + vty_out (vty, "ip extcommunity-list %s %s %s %s%s", + entry->style == EXTCOMMUNITY_LIST_STANDARD + ? "standard" : "expanded", + list->name, community_direct_str (entry->direct), + community_list_config_str (entry), VTY_NEWLINE); + write++; + } + return write; +} + +struct cmd_node community_list_node = + { + COMMUNITY_LIST_NODE, + "", + 1 /* Export to vtysh. */ + }; + +void +community_list_vty () +{ + install_node (&community_list_node, community_list_config_write); + + /* Community-list. */ + install_element (CONFIG_NODE, &ip_community_list_standard_cmd); + install_element (CONFIG_NODE, &ip_community_list_standard2_cmd); + install_element (CONFIG_NODE, &ip_community_list_expanded_cmd); + install_element (CONFIG_NODE, &ip_community_list_name_standard_cmd); + install_element (CONFIG_NODE, &ip_community_list_name_standard2_cmd); + install_element (CONFIG_NODE, &ip_community_list_name_expanded_cmd); + install_element (CONFIG_NODE, &no_ip_community_list_standard_all_cmd); + install_element (CONFIG_NODE, &no_ip_community_list_expanded_all_cmd); + install_element (CONFIG_NODE, &no_ip_community_list_name_standard_all_cmd); + install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_all_cmd); + install_element (CONFIG_NODE, &no_ip_community_list_standard_cmd); + install_element (CONFIG_NODE, &no_ip_community_list_expanded_cmd); + install_element (CONFIG_NODE, &no_ip_community_list_name_standard_cmd); + install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_cmd); + install_element (VIEW_NODE, &show_ip_community_list_cmd); + install_element (VIEW_NODE, &show_ip_community_list_arg_cmd); + install_element (ENABLE_NODE, &show_ip_community_list_cmd); + install_element (ENABLE_NODE, &show_ip_community_list_arg_cmd); + + /* Extcommunity-list. */ + install_element (CONFIG_NODE, &ip_extcommunity_list_standard_cmd); + install_element (CONFIG_NODE, &ip_extcommunity_list_standard2_cmd); + install_element (CONFIG_NODE, &ip_extcommunity_list_expanded_cmd); + install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard_cmd); + install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard2_cmd); + install_element (CONFIG_NODE, &ip_extcommunity_list_name_expanded_cmd); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_all_cmd); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_all_cmd); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_all_cmd); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_cmd); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_cmd); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_cmd); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_cmd); + install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd); + install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd); + install_element (ENABLE_NODE, &show_ip_extcommunity_list_cmd); + install_element (ENABLE_NODE, &show_ip_extcommunity_list_arg_cmd); + + /* bgpd version */ + install_element (VIEW_NODE, &show_version_bgpd_cmd); + install_element (ENABLE_NODE, &show_version_bgpd_cmd); +} diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h new file mode 100644 index 0000000..74bc185 --- /dev/null +++ b/bgpd/bgp_vty.h @@ -0,0 +1,22 @@ +/* BGP VTY interface. + Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +void bgp_vty_init (); +char *afi_safi_print (afi_t, safi_t); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c new file mode 100644 index 0000000..ec6e2d1 --- /dev/null +++ b/bgpd/bgp_zebra.c @@ -0,0 +1,1001 @@ +/* zebra client + Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include + +#include "command.h" +#include "stream.h" +#include "network.h" +#include "prefix.h" +#include "log.h" +#include "sockunion.h" +#include "zclient.h" +#include "routemap.h" +#include "thread.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_zebra.h" +#include "bgpd/bgp_fsm.h" + +/* All information about zebra. */ +static struct zclient *zclient = NULL; + +/* Update default router id. */ +int +bgp_if_update (struct interface *ifp) +{ + struct bgp *bgp; + listnode cn; + struct listnode *nn; + struct listnode *nm; + struct peer *peer; + + for (cn = listhead (ifp->connected); cn; nextnode (cn)) + { + struct connected *co; + struct in_addr addr; + + co = getdata (cn); + + if (co->address->family == AF_INET) + { + addr = co->address->u.prefix4; + + /* Ignore NET127. */ + if (IPV4_NET127 (ntohl (addr.s_addr))) + continue; + + LIST_LOOP (bm->bgp, bgp, nn) + { + /* Respect configured router id */ + if (! (bgp->config & BGP_CONFIG_ROUTER_ID)) + if (ntohl (bgp->router_id.s_addr) < ntohl (addr.s_addr)) + { + bgp->router_id = addr; + LIST_LOOP (bgp->peer, peer, nm) + { + peer->local_id = addr; + } + } + } + } + } + return 0; +} + +int +bgp_if_update_all () +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; node = nextnode (node)) + { + ifp = getdata (node); + bgp_if_update (ifp); + } + return 0; +} + +/* Inteface addition message from zebra. */ +int +bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read (zclient->ibuf); + bgp_if_update (ifp); + + return 0; +} + +int +bgp_interface_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct interface *ifp; + + s = zclient->ibuf; + ifp = zebra_interface_state_read (s); + + return 0; +} + +int +bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length) +{ + struct stream *s; + struct interface *ifp; + struct connected *c; + listnode node; + + s = zclient->ibuf; + ifp = zebra_interface_state_read (s); + + if (! ifp) + return 0; + + for (node = listhead (ifp->connected); node; nextnode (node)) + { + c = getdata (node); + bgp_connected_add (c); + } + + return 0; +} + +int +bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length) +{ + struct stream *s; + struct interface *ifp; + struct connected *c; + listnode node; + + s = zclient->ibuf; + ifp = zebra_interface_state_read (s); + if (! ifp) + return 0; + + for (node = listhead (ifp->connected); node; nextnode (node)) + { + c = getdata (node); + bgp_connected_delete (c); + } + + /* Fast external-failover (Currently IPv4 only) */ + { + struct listnode *nn, *nm; + struct bgp *bgp; + struct peer *peer; + struct interface *peer_if; + + LIST_LOOP (bm->bgp, bgp, nn) + { + if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) + continue; + + LIST_LOOP (bgp->peer, peer, nm) + { + if (peer->ttl != 1) + continue; + + if (peer->su.sa.sa_family == AF_INET) + peer_if = if_lookup_by_ipv4 (&peer->su.sin.sin_addr); + else + continue; + + if (ifp == peer_if) + BGP_EVENT_ADD (peer, BGP_Stop); + } + } + } + + return 0; +} + +int +bgp_interface_address_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *ifc; + + ifc = zebra_interface_address_add_read (zclient->ibuf); + + if (ifc == NULL) + return 0; + + bgp_if_update (ifc->ifp); + + if (if_is_up (ifc->ifp)) + bgp_connected_add (ifc); + + return 0; +} + +int +bgp_interface_address_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *ifc; + + ifc = zebra_interface_address_delete_read (zclient->ibuf); + + if (ifc == NULL) + return 0; + + bgp_if_update (ifc->ifp); + + if (if_is_up (ifc->ifp)) + bgp_connected_delete (ifc); + + connected_free (ifc); + + return 0; +} + +/* Zebra route add and delete treatment. */ +int +zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv4 api; + unsigned long ifindex; + struct in_addr nexthop; + struct prefix_ipv4 p; + + s = zclient->ibuf; + ifindex = 0; + nexthop.s_addr = 0; + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv4 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + nexthop.s_addr = stream_get_ipv4 (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + if (command == ZEBRA_IPV4_ROUTE_ADD) + bgp_redistribute_add ((struct prefix *)&p, &nexthop, api.metric, api.type); + else + bgp_redistribute_delete ((struct prefix *)&p, api.type); + + return 0; +} + +#ifdef HAVE_IPV6 +/* Zebra route add and delete treatment. */ +int +zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv6 api; + unsigned long ifindex; + struct in6_addr nexthop; + struct prefix_ipv6 p; + + s = zclient->ibuf; + ifindex = 0; + memset (&nexthop, 0, sizeof (struct in6_addr)); + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv6 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + stream_get (&nexthop, s, 16); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + else + api.distance = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + /* Simply ignore link-local address. */ + if (IN6_IS_ADDR_LINKLOCAL (&p.prefix)) + return 0; + + if (command == ZEBRA_IPV6_ROUTE_ADD) + bgp_redistribute_add ((struct prefix *)&p, NULL, api.metric, api.type); + else + bgp_redistribute_delete ((struct prefix *) &p, api.type); + + return 0; +} +#endif /* HAVE_IPV6 */ + +struct interface * +if_lookup_by_ipv4 (struct in_addr *addr) +{ + listnode ifnode; + listnode cnode; + struct interface *ifp; + struct connected *connected; + struct prefix_ipv4 p; + struct prefix *cp; + + p.family = AF_INET; + p.prefix = *addr; + p.prefixlen = IPV4_MAX_BITLEN; + + for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) + { + ifp = getdata (ifnode); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET) + if (prefix_match (cp, (struct prefix *)&p)) + return ifp; + } + } + return NULL; +} + +struct interface * +if_lookup_by_ipv4_exact (struct in_addr *addr) +{ + listnode ifnode; + listnode cnode; + struct interface *ifp; + struct connected *connected; + struct prefix *cp; + + for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) + { + ifp = getdata (ifnode); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET) + if (IPV4_ADDR_SAME (&cp->u.prefix4, addr)) + return ifp; + } + } + return NULL; +} + +#ifdef HAVE_IPV6 +struct interface * +if_lookup_by_ipv6 (struct in6_addr *addr) +{ + listnode ifnode; + listnode cnode; + struct interface *ifp; + struct connected *connected; + struct prefix_ipv6 p; + struct prefix *cp; + + p.family = AF_INET6; + p.prefix = *addr; + p.prefixlen = IPV6_MAX_BITLEN; + + for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) + { + ifp = getdata (ifnode); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET6) + if (prefix_match (cp, (struct prefix *)&p)) + return ifp; + } + } + return NULL; +} + +struct interface * +if_lookup_by_ipv6_exact (struct in6_addr *addr) +{ + listnode ifnode; + listnode cnode; + struct interface *ifp; + struct connected *connected; + struct prefix *cp; + + for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) + { + ifp = getdata (ifnode); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET6) + if (IPV6_ADDR_SAME (&cp->u.prefix6, addr)) + return ifp; + } + } + return NULL; +} + +int +if_get_ipv6_global (struct interface *ifp, struct in6_addr *addr) +{ + listnode cnode; + struct connected *connected; + struct prefix *cp; + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET6) + if (! IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6)) + { + memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN); + return 1; + } + } + return 0; +} + +int +if_get_ipv6_local (struct interface *ifp, struct in6_addr *addr) +{ + listnode cnode; + struct connected *connected; + struct prefix *cp; + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET6) + if (IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6)) + { + memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN); + return 1; + } + } + return 0; +} +#endif /* HAVE_IPV6 */ + +int +bgp_nexthop_set (union sockunion *local, union sockunion *remote, + struct bgp_nexthop *nexthop, struct peer *peer) +{ + int ret = 0; + struct interface *ifp = NULL; + + memset (nexthop, 0, sizeof (struct bgp_nexthop)); + + if (!local) + return -1; + if (!remote) + return -1; + + if (local->sa.sa_family == AF_INET) + { + nexthop->v4 = local->sin.sin_addr; + ifp = if_lookup_by_ipv4 (&local->sin.sin_addr); + } +#ifdef HAVE_IPV6 + if (local->sa.sa_family == AF_INET6) + { + if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr)) + { + if (peer->ifname) + ifp = if_lookup_by_index (if_nametoindex (peer->ifname)); + } + else + ifp = if_lookup_by_ipv6 (&local->sin6.sin6_addr); + } +#endif /* HAVE_IPV6 */ + + if (!ifp) + return -1; + + nexthop->ifp = ifp; + + /* IPv4 connection. */ + if (local->sa.sa_family == AF_INET) + { +#ifdef HAVE_IPV6 + /* IPv6 nexthop*/ + ret = if_get_ipv6_global (ifp, &nexthop->v6_global); + + /* There is no global nexthop. */ + if (!ret) + if_get_ipv6_local (ifp, &nexthop->v6_global); + else + if_get_ipv6_local (ifp, &nexthop->v6_local); +#endif /* HAVE_IPV6 */ + } + +#ifdef HAVE_IPV6 + /* IPv6 connection. */ + if (local->sa.sa_family == AF_INET6) + { + struct interface *direct = NULL; + + /* IPv4 nexthop. I don't care about it. */ + if (peer->local_id.s_addr) + nexthop->v4 = peer->local_id; + + /* Global address*/ + if (! IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr)) + { + memcpy (&nexthop->v6_global, &local->sin6.sin6_addr, + IPV6_MAX_BYTELEN); + + /* If directory connected set link-local address. */ + direct = if_lookup_by_ipv6 (&remote->sin6.sin6_addr); + if (direct) + if_get_ipv6_local (ifp, &nexthop->v6_local); + } + else + /* Link-local address. */ + { + ret = if_get_ipv6_global (ifp, &nexthop->v6_global); + + /* If there is no global address. Set link-local address as + global. I know this break RFC specification... */ + if (!ret) + memcpy (&nexthop->v6_global, &local->sin6.sin6_addr, + IPV6_MAX_BYTELEN); + else + memcpy (&nexthop->v6_local, &local->sin6.sin6_addr, + IPV6_MAX_BYTELEN); + } + } + + if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr) || + if_lookup_by_ipv6 (&remote->sin6.sin6_addr)) + peer->shared_network = 1; + else + peer->shared_network = 0; + + /* KAME stack specific treatment. */ +#ifdef KAME + if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_global) + && IN6_LINKLOCAL_IFINDEX (nexthop->v6_global)) + { + SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_global, 0); + } + if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_local) + && IN6_LINKLOCAL_IFINDEX (nexthop->v6_local)) + { + SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_local, 0); + } +#endif /* KAME */ +#endif /* HAVE_IPV6 */ + return ret; +} + +#ifdef HAVE_IPV6 +unsigned int +bgp_ifindex_by_nexthop (struct in6_addr *addr) +{ + listnode ifnode; + listnode cnode; + struct interface *ifp; + struct connected *connected; + struct prefix_ipv6 p; + + p.family = AF_INET6; + p.prefix = *addr; + p.prefixlen = IPV6_MAX_BITLEN; + + for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) + { + ifp = getdata (ifnode); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + struct prefix *cp; + + connected = getdata (cnode); + cp = connected->address; + + if (cp->family == AF_INET6) + { + if (prefix_match (cp, (struct prefix *)&p)) + return ifp->ifindex; + } + } + } + return 0; +} +#endif /* HAVE_IPV6 */ + +void +bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) +{ + int flags; + u_char distance; + struct peer *peer; + + if (zclient->sock < 0) + return; + + if (! zclient->redist[ZEBRA_ROUTE_BGP]) + return; + + flags = 0; + peer = info->peer; + + if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED) + { + SET_FLAG (flags, ZEBRA_FLAG_IBGP); + SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); + } + + if ((peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1) + || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) + SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); + + if (p->family == AF_INET) + { + struct zapi_ipv4 api; + struct in_addr *nexthop; + + api.flags = flags; + nexthop = &info->attr->nexthop; + + api.type = ZEBRA_ROUTE_BGP; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + api.ifindex_num = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); + api.metric = info->attr->med; + + distance = bgp_distance_apply (p, info, bgp); + + if (distance) + { + SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); + api.distance = distance; + } + zapi_ipv4_add (zclient, (struct prefix_ipv4 *) p, &api); + } +#ifdef HAVE_IPV6 + /* We have to think about a IPv6 link-local address curse. */ + if (p->family == AF_INET6) + { + unsigned int ifindex; + struct in6_addr *nexthop; + struct zapi_ipv6 api; + + ifindex = 0; + nexthop = NULL; + + /* Only global address nexthop exists. */ + if (info->attr->mp_nexthop_len == 16) + nexthop = &info->attr->mp_nexthop_global; + + /* If both global and link-local address present. */ + if (info->attr->mp_nexthop_len == 32) + { + /* Workaround for Cisco's nexthop bug. */ + if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->mp_nexthop_global) + && peer->su_remote->sa.sa_family == AF_INET6) + nexthop = &peer->su_remote->sin6.sin6_addr; + else + nexthop = &info->attr->mp_nexthop_local; + + if (info->peer->nexthop.ifp) + ifindex = info->peer->nexthop.ifp->ifindex; + } + + if (nexthop == NULL) + return; + + if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) + { + if (info->peer->ifname) + ifindex = if_nametoindex (info->peer->ifname); + else if (info->peer->nexthop.ifp) + ifindex = info->peer->nexthop.ifp->ifindex; + } + + /* Make Zebra API structure. */ + api.flags = flags; + api.type = ZEBRA_ROUTE_BGP; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &ifindex; + SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); + api.metric = info->attr->med; + + zapi_ipv6_add (zclient, (struct prefix_ipv6 *) p, &api); + } +#endif /* HAVE_IPV6 */ +} + +void +bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info) +{ + int flags; + struct peer *peer; + + if (zclient->sock < 0) + return; + + if (! zclient->redist[ZEBRA_ROUTE_BGP]) + return; + + peer = info->peer; + flags = 0; + + if (peer_sort (peer) == BGP_PEER_IBGP) + { + SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); + SET_FLAG (flags, ZEBRA_FLAG_IBGP); + } + + if ((peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1) + || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) + SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); + + if (p->family == AF_INET) + { + struct zapi_ipv4 api; + struct in_addr *nexthop; + + api.flags = flags; + nexthop = &info->attr->nexthop; + + api.type = ZEBRA_ROUTE_BGP; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + api.ifindex_num = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); + api.metric = info->attr->med; + + zapi_ipv4_delete (zclient, (struct prefix_ipv4 *) p, &api); + } +#ifdef HAVE_IPV6 + /* We have to think about a IPv6 link-local address curse. */ + if (p->family == AF_INET6) + { + struct zapi_ipv6 api; + unsigned int ifindex; + struct in6_addr *nexthop; + + ifindex = 0; + nexthop = NULL; + + /* Only global address nexthop exists. */ + if (info->attr->mp_nexthop_len == 16) + nexthop = &info->attr->mp_nexthop_global; + + /* If both global and link-local address present. */ + if (info->attr->mp_nexthop_len == 32) + { + nexthop = &info->attr->mp_nexthop_local; + if (info->peer->nexthop.ifp) + ifindex = info->peer->nexthop.ifp->ifindex; + } + + if (nexthop == NULL) + return; + + if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) + if (info->peer->ifname) + ifindex = if_nametoindex (info->peer->ifname); + + api.flags = flags; + api.type = ZEBRA_ROUTE_BGP; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &ifindex; + SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); + api.metric = info->attr->med; + + zapi_ipv6_delete (zclient, (struct prefix_ipv6 *) p, &api); + } +#endif /* HAVE_IPV6 */ +} + +/* Other routes redistribution into BGP. */ +int +bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type) +{ + /* Set flag to BGP instance. */ + bgp->redist[afi][type] = 1; + + /* Return if already redistribute flag is set. */ + if (zclient->redist[type]) + return CMD_WARNING; + + zclient->redist[type] = 1; + + /* Return if zebra connection is not established. */ + if (zclient->sock < 0) + return CMD_WARNING; + + /* Send distribute add message to zebra. */ + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type); + + return CMD_SUCCESS; +} + +/* Redistribute with route-map specification. */ +int +bgp_redistribute_rmap_set (struct bgp *bgp, afi_t afi, int type, char *name) +{ + if (bgp->rmap[afi][type].name + && (strcmp (bgp->rmap[afi][type].name, name) == 0)) + return 0; + + if (bgp->rmap[afi][type].name) + free (bgp->rmap[afi][type].name); + bgp->rmap[afi][type].name = strdup (name); + bgp->rmap[afi][type].map = route_map_lookup_by_name (name); + + return 1; +} + +/* Redistribute with metric specification. */ +int +bgp_redistribute_metric_set (struct bgp *bgp, afi_t afi, int type, + u_int32_t metric) +{ + if (bgp->redist_metric_flag[afi][type] + && bgp->redist_metric[afi][type] == metric) + return 0; + + bgp->redist_metric_flag[afi][type] = 1; + bgp->redist_metric[afi][type] = metric; + + return 1; +} + +/* Unset redistribution. */ +int +bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type) +{ + /* Unset flag from BGP instance. */ + bgp->redist[afi][type] = 0; + + /* Unset route-map. */ + if (bgp->rmap[afi][type].name) + free (bgp->rmap[afi][type].name); + bgp->rmap[afi][type].name = NULL; + bgp->rmap[afi][type].map = NULL; + + /* Unset metric. */ + bgp->redist_metric_flag[afi][type] = 0; + bgp->redist_metric[afi][type] = 0; + + /* Return if zebra connection is disabled. */ + if (! zclient->redist[type]) + return CMD_WARNING; + zclient->redist[type] = 0; + + if (bgp->redist[AFI_IP][type] == 0 + && bgp->redist[AFI_IP6][type] == 0 + && zclient->sock >= 0) + /* Send distribute delete message to zebra. */ + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type); + + /* Withdraw redistributed routes from current BGP's routing table. */ + bgp_redistribute_withdraw (bgp, afi, type); + + return CMD_SUCCESS; +} + +/* Unset redistribution route-map configuration. */ +int +bgp_redistribute_routemap_unset (struct bgp *bgp, afi_t afi, int type) +{ + if (! bgp->rmap[afi][type].name) + return 0; + + /* Unset route-map. */ + free (bgp->rmap[afi][type].name); + bgp->rmap[afi][type].name = NULL; + bgp->rmap[afi][type].map = NULL; + + return 1; +} + +/* Unset redistribution metric configuration. */ +int +bgp_redistribute_metric_unset (struct bgp *bgp, afi_t afi, int type) +{ + if (! bgp->redist_metric_flag[afi][type]) + return 0; + + /* Unset metric. */ + bgp->redist_metric_flag[afi][type] = 0; + bgp->redist_metric[afi][type] = 0; + + return 1; +} + +void +bgp_zclient_reset () +{ + zclient_reset (zclient); +} + +void +bgp_zebra_init (int enable) +{ + /* Set default values. */ + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_BGP); + zclient->interface_add = bgp_interface_add; + zclient->interface_delete = bgp_interface_delete; + zclient->interface_address_add = bgp_interface_address_add; + zclient->interface_address_delete = bgp_interface_address_delete; + zclient->ipv4_route_add = zebra_read_ipv4; + zclient->ipv4_route_delete = zebra_read_ipv4; + zclient->interface_up = bgp_interface_up; + zclient->interface_down = bgp_interface_down; +#ifdef HAVE_IPV6 + zclient->ipv6_route_add = zebra_read_ipv6; + zclient->ipv6_route_delete = zebra_read_ipv6; +#endif /* HAVE_IPV6 */ + + /* Interface related init. */ + if_init (); +} diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h new file mode 100644 index 0000000..1620c84 --- /dev/null +++ b/bgpd/bgp_zebra.h @@ -0,0 +1,39 @@ +/* zebra connection and redistribute fucntions. + Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +int bgp_if_update_all (); +int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t, + int *); +void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *); +void bgp_zebra_withdraw (struct prefix *, struct bgp_info *); + +int bgp_redistribute_set (struct bgp *, afi_t, int); +int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, char *); +int bgp_redistribute_metric_set (struct bgp *, afi_t, int, u_int32_t); +int bgp_redistribute_unset (struct bgp *, afi_t, int); +int bgp_redistribute_routemap_unset (struct bgp *, afi_t, int); +int bgp_redistribute_metric_unset (struct bgp *, afi_t, int); + +struct interface *if_lookup_by_ipv4 (struct in_addr *); +struct interface *if_lookup_by_ipv4_exact (struct in_addr *); +#ifdef HAVE_IPV6 +struct interface *if_lookup_by_ipv6 (struct in6_addr *); +struct interface *if_lookup_by_ipv6_exact (struct in6_addr *); +#endif /* HAVE_IPV6 */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c new file mode 100644 index 0000000..03e6476 --- /dev/null +++ b/bgpd/bgpd.c @@ -0,0 +1,4951 @@ +/* BGP-4, BGP-4+ daemon program + Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "prefix.h" +#include "thread.h" +#include "buffer.h" +#include "stream.h" +#include "command.h" +#include "sockunion.h" +#include "network.h" +#include "memory.h" +#include "filter.h" +#include "routemap.h" +#include "str.h" +#include "log.h" +#include "plist.h" +#include "linklist.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_dump.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_clist.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_zebra.h" +#include "bgpd/bgp_open.h" +#include "bgpd/bgp_filter.h" +#include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_damp.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_advertise.h" +#include "bgpd/bgp_network.h" +#include "bgpd/bgp_vty.h" +#ifdef HAVE_SNMP +#include "bgpd/bgp_snmp.h" +#endif /* HAVE_SNMP */ +#ifdef HAVE_TCP_SIGNATURE +#include "bgpd/bgp_tcpsig.h" +#endif /* HAVE_TCP_SIGNATURE */ + +/* BGP process wide configuration. */ +static struct bgp_master bgp_master; + +/* BGP process wide configuration pointer to export. */ +struct bgp_master *bm; + +/* BGP community-list. */ +struct community_list_handler *bgp_clist; + +/* BGP global flag manipulation. */ +int +bgp_option_set (int flag) +{ + switch (flag) + { + case BGP_OPT_NO_FIB: + case BGP_OPT_MULTIPLE_INSTANCE: + case BGP_OPT_CONFIG_CISCO: + SET_FLAG (bm->options, flag); + break; + default: + return BGP_ERR_INVALID_FLAG; + break; + } + return 0; +} + +int +bgp_option_unset (int flag) +{ + switch (flag) + { + case BGP_OPT_MULTIPLE_INSTANCE: + if (listcount (bm->bgp) > 1) + return BGP_ERR_MULTIPLE_INSTANCE_USED; + /* Fall through. */ + case BGP_OPT_NO_FIB: + case BGP_OPT_CONFIG_CISCO: + UNSET_FLAG (bm->options, flag); + break; + default: + return BGP_ERR_INVALID_FLAG; + break; + } + return 0; +} + +int +bgp_option_check (int flag) +{ + return CHECK_FLAG (bm->options, flag); +} + +/* BGP flag manipulation. */ +int +bgp_flag_set (struct bgp *bgp, int flag) +{ + SET_FLAG (bgp->flags, flag); + return 0; +} + +int +bgp_flag_unset (struct bgp *bgp, int flag) +{ + UNSET_FLAG (bgp->flags, flag); + return 0; +} + +int +bgp_flag_check (struct bgp *bgp, int flag) +{ + return CHECK_FLAG (bgp->flags, flag); +} + +/* Internal function to set BGP structure configureation flag. */ +static void +bgp_config_set (struct bgp *bgp, int config) +{ + SET_FLAG (bgp->config, config); +} + +static void +bgp_config_unset (struct bgp *bgp, int config) +{ + UNSET_FLAG (bgp->config, config); +} + +static int +bgp_config_check (struct bgp *bgp, int config) +{ + return CHECK_FLAG (bgp->config, config); +} + +/* Set BGP router identifier. */ +int +bgp_router_id_set (struct bgp *bgp, struct in_addr *id) +{ + struct peer *peer; + struct listnode *nn; + + if (bgp_config_check (bgp, BGP_CONFIG_ROUTER_ID) + && IPV4_ADDR_SAME (&bgp->router_id, id)) + return 0; + + IPV4_ADDR_COPY (&bgp->router_id, id); + bgp_config_set (bgp, BGP_CONFIG_ROUTER_ID); + + /* Set all peer's local identifier with this value. */ + LIST_LOOP (bgp->peer, peer, nn) + { + IPV4_ADDR_COPY (&peer->local_id, id); + + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_RID_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + } + return 0; +} + +/* Unset BGP router identifier. */ +int +bgp_router_id_unset (struct bgp *bgp) +{ + struct peer *peer; + struct listnode *nn; + + if (! bgp_config_check (bgp, BGP_CONFIG_ROUTER_ID)) + return 0; + + bgp->router_id.s_addr = 0; + bgp_config_unset (bgp, BGP_CONFIG_ROUTER_ID); + + /* Clear peer router id configuration. */ + LIST_LOOP (bgp->peer, peer, nn) + { + peer->local_id.s_addr = 0; + } + + /* Set router-id from interface's address. */ + bgp_if_update_all (); + + /* Reset all BGP sessions to use new router-id. */ + LIST_LOOP (bgp->peer, peer, nn) + { + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_RID_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + } + + return 0; +} + +/* BGP's cluster-id control. */ +int +bgp_cluster_id_set (struct bgp *bgp, struct in_addr *cluster_id) +{ + struct peer *peer; + struct listnode *nn; + + if (bgp_config_check (bgp, BGP_CONFIG_CLUSTER_ID) + && IPV4_ADDR_SAME (&bgp->cluster_id, cluster_id)) + return 0; + + IPV4_ADDR_COPY (&bgp->cluster_id, cluster_id); + bgp_config_set (bgp, BGP_CONFIG_CLUSTER_ID); + + /* Clear all IBGP peer. */ + LIST_LOOP (bgp->peer, peer, nn) + { + if (peer_sort (peer) != BGP_PEER_IBGP) + continue; + + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_CLID_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + } + return 0; +} + +int +bgp_cluster_id_unset (struct bgp *bgp) +{ + struct peer *peer; + struct listnode *nn; + + if (! bgp_config_check (bgp, BGP_CONFIG_CLUSTER_ID)) + return 0; + + bgp->cluster_id.s_addr = 0; + bgp_config_unset (bgp, BGP_CONFIG_CLUSTER_ID); + + /* Clear all IBGP peer. */ + LIST_LOOP (bgp->peer, peer, nn) + { + if (peer_sort (peer) != BGP_PEER_IBGP) + continue; + + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_CLID_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + } + return 0; +} + +/* BGP timer configuration. */ +int +bgp_timers_set (struct bgp *bgp, u_int32_t keepalive, u_int32_t holdtime) +{ + bgp->default_keepalive = (keepalive < holdtime / 3 + ? keepalive : holdtime / 3); + bgp->default_holdtime = holdtime; + + return 0; +} + +int +bgp_timers_unset (struct bgp *bgp) +{ + bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; + bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; + + return 0; +} + +/* BGP confederation configuration. */ +int +bgp_confederation_id_set (struct bgp *bgp, as_t as) +{ + struct peer *peer; + struct listnode *nn; + int already_confed; + + if (as == 0) + return BGP_ERR_INVALID_AS; + + /* Remember - were we doing confederation before? */ + already_confed = bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION); + bgp->confed_id = as; + bgp_config_set (bgp, BGP_CONFIG_CONFEDERATION); + + /* If we were doing confederation already, this is just an external + AS change. Just Reset EBGP sessions, not CONFED sessions. If we + were not doing confederation before, reset all EBGP sessions. */ + LIST_LOOP (bgp->peer, peer, nn) + { + /* We're looking for peers who's AS is not local or part of our + confederation. */ + if (already_confed) + { + if (peer_sort (peer) == BGP_PEER_EBGP) + { + peer->local_as = as; + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + } + else + { + /* Not doign confederation before, so reset every non-local + session */ + if (peer_sort (peer) != BGP_PEER_IBGP) + { + /* Reset the local_as to be our EBGP one */ + if (peer_sort (peer) == BGP_PEER_EBGP) + peer->local_as = as; + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + } + } + return 0; +} + +int +bgp_confederation_id_unset (struct bgp *bgp) +{ + struct peer *peer; + struct listnode *nn; + + bgp->confed_id = 0; + bgp_config_unset (bgp, BGP_CONFIG_CONFEDERATION); + + LIST_LOOP (bgp->peer, peer, nn) + { + /* We're looking for peers who's AS is not local */ + if (peer_sort (peer) != BGP_PEER_IBGP) + { + peer->local_as = bgp->as; + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + } + return 0; +} + +/* Is an AS part of the confed or not? */ +int +bgp_confederation_peers_check (struct bgp *bgp, as_t as) +{ + int i; + + if (! bgp) + return 0; + + for (i = 0; i < bgp->confed_peers_cnt; i++) + if (bgp->confed_peers[i] == as) + return 1; + + return 0; +} + +/* Add an AS to the confederation set. */ +int +bgp_confederation_peers_add (struct bgp *bgp, as_t as) +{ + struct peer *peer; + struct listnode *nn; + + if (! bgp) + return BGP_ERR_INVALID_BGP; + + if (bgp->as == as) + return BGP_ERR_INVALID_AS; + + if (bgp_confederation_peers_check (bgp, as)) + return -1; + + if (bgp->confed_peers) + bgp->confed_peers = XREALLOC (MTYPE_BGP_CONFED_LIST, + bgp->confed_peers, + (bgp->confed_peers_cnt + 1) * sizeof (as_t)); + else + bgp->confed_peers = XMALLOC (MTYPE_BGP_CONFED_LIST, + (bgp->confed_peers_cnt + 1) * sizeof (as_t)); + + bgp->confed_peers[bgp->confed_peers_cnt] = as; + bgp->confed_peers_cnt++; + + if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION)) + { + LIST_LOOP (bgp->peer, peer, nn) + { + if (peer->as == as) + { + peer->local_as = bgp->as; + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + } + } + return 0; +} + +/* Delete an AS from the confederation set. */ +int +bgp_confederation_peers_remove (struct bgp *bgp, as_t as) +{ + int i; + int j; + struct peer *peer; + struct listnode *nn; + + if (! bgp) + return -1; + + if (! bgp_confederation_peers_check (bgp, as)) + return -1; + + for (i = 0; i < bgp->confed_peers_cnt; i++) + if (bgp->confed_peers[i] == as) + for(j = i + 1; j < bgp->confed_peers_cnt; j++) + bgp->confed_peers[j - 1] = bgp->confed_peers[j]; + + bgp->confed_peers_cnt--; + + if (bgp->confed_peers_cnt == 0) + { + if (bgp->confed_peers) + XFREE (MTYPE_BGP_CONFED_LIST, bgp->confed_peers); + bgp->confed_peers = NULL; + } + else + bgp->confed_peers = XREALLOC (MTYPE_BGP_CONFED_LIST, + bgp->confed_peers, + bgp->confed_peers_cnt * sizeof (as_t)); + + /* Now reset any peer who's remote AS has just been removed from the + CONFED */ + if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION)) + { + LIST_LOOP (bgp->peer, peer, nn) + { + if (peer->as == as) + { + peer->local_as = bgp->confed_id; + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + } + } + + return 0; +} + +/* Local preference configuration. */ +int +bgp_default_local_preference_set (struct bgp *bgp, u_int32_t local_pref) +{ + if (! bgp) + return -1; + + bgp->default_local_pref = local_pref; + + return 0; +} + +int +bgp_default_local_preference_unset (struct bgp *bgp) +{ + if (! bgp) + return -1; + + bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; + + return 0; +} + +/* Peer comparison function for sorting. */ +static int +peer_cmp (struct peer *p1, struct peer *p2) +{ + return sockunion_cmp (&p1->su, &p2->su); +} + +int +peer_af_flag_check (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag) +{ + return CHECK_FLAG (peer->af_flags[afi][safi], flag); +} + +/* Reset all address family specific configuration. */ +static void +peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi) +{ + int i; + struct bgp_filter *filter; + char orf_name[BUFSIZ]; + + filter = &peer->filter[afi][safi]; + + /* Clear neighbor filter and route-map */ + for (i = FILTER_IN; i < FILTER_MAX; i++) + { + if (filter->dlist[i].name) + { + free (filter->dlist[i].name); + filter->dlist[i].name = NULL; + } + if (filter->plist[i].name) + { + free (filter->plist[i].name); + filter->plist[i].name = NULL; + } + if (filter->aslist[i].name) + { + free (filter->aslist[i].name); + filter->aslist[i].name = NULL; + } + if (filter->map[i].name) + { + free (filter->map[i].name); + filter->map[i].name = NULL; + } + } + + /* Clear unsuppress map. */ + if (filter->usmap.name) + free (filter->usmap.name); + filter->usmap.name = NULL; + filter->usmap.map = NULL; + + /* Clear neighbor's all address family flags. */ + peer->af_flags[afi][safi] = 0; + + /* Clear neighbor's all address family sflags. */ + peer->af_sflags[afi][safi] = 0; + + /* Clear neighbor's all address family capabilities. */ + peer->af_cap[afi][safi] = 0; + + /* Clear ORF info */ + peer->orf_plist[afi][safi] = NULL; + sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); + prefix_bgp_orf_remove_all (orf_name); + + /* Set default neighbor send-community. */ + if (! bgp_option_check (BGP_OPT_CONFIG_CISCO)) + { + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY); + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY); + } + + /* Clear neighbor default_originate_rmap */ + if (peer->default_rmap[afi][safi].name) + free (peer->default_rmap[afi][safi].name); + peer->default_rmap[afi][safi].name = NULL; + peer->default_rmap[afi][safi].map = NULL; + + /* Clear neighbor maximum-prefix */ + peer->pmax[afi][safi] = 0; + peer->pmax_threshold[afi][safi] = MAXIMUM_PREFIX_THRESHOLD_DEFAULT; + + /* Clear address family configuration */ + peer->af_config[afi][safi] = 0; +} + +void +peer_group_global_config_copy (struct peer *group, struct peer *peer) +{ + /* remote-as */ + if (group->as) + peer->as = group->as; + + /* remote-as */ + if (group->change_local_as) + peer->change_local_as = group->change_local_as; + + /* TTL */ + peer->ttl = group->ttl; + + peer->flags = group->flags; + peer->config = group->config; + + /* peer timers apply */ + peer->holdtime = group->holdtime; + peer->keepalive = group->keepalive; + + /* advertisement-interval reset */ + if (peer_sort (peer) == BGP_PEER_IBGP) + peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + +#ifdef HAVE_TCP_SIGNATURE + /* password apply */ + if (CHECK_FLAG (group->flags, PEER_FLAG_PASSWORD)) + { + if (peer->password) + free (peer->password); + peer->password = strdup (group->password); + + bgp_tcpsig_set (bm->sock, peer); + } + else if (peer->password) + { + bgp_tcpsig_unset (bm->sock, peer); + free (peer->password); + peer->password = NULL; + } +#endif /* HAVE_TCP_SIGNATURE */ + + /* update-source apply */ + if (group->update_source) + { + if (peer->update_source) + sockunion_free (peer->update_source); + if (peer->update_if) + { + XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + peer->update_if = NULL; + } + peer->update_source = sockunion_dup (group->update_source); + } + else if (group->update_if) + { + if (peer->update_if) + XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + if (peer->update_source) + { + sockunion_free (peer->update_source); + peer->update_source = NULL; + } + peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, group->update_if); + } +} + +void +peer_group_af_config_copy (struct peer *group, struct peer *peer, + afi_t afi, safi_t safi) +{ + int in = FILTER_IN; + int out = FILTER_OUT; + struct bgp_filter *pfilter; + struct bgp_filter *gfilter; + + pfilter = &peer->filter[afi][safi]; + gfilter = &group->filter[afi][safi]; + + peer->af_flags[afi][safi] = group->af_flags[afi][safi]; + peer->af_config[afi][safi] = group->af_config[afi][safi]; + peer->weight[afi][safi] = group->weight[afi][safi]; + + /* maximum-prefix */ + peer->pmax[afi][safi] = group->pmax[afi][safi]; + peer->pmax_threshold[afi][safi] = group->pmax_threshold[afi][safi]; + peer->pmax_restart[afi][safi] = group->pmax_restart[afi][safi]; + + /* allowas-in */ + peer->allowas_in[afi][safi] = group->allowas_in[afi][safi]; + + /* default-originate route-map */ + if (group->default_rmap[afi][safi].name) + { + if (peer->default_rmap[afi][safi].name) + free (peer->default_rmap[afi][safi].name); + peer->default_rmap[afi][safi].name = strdup (group->default_rmap[afi][safi].name); + peer->default_rmap[afi][safi].map = group->default_rmap[afi][safi].map; + } + + /* inbound filter apply */ + if (gfilter->dlist[in].name && ! pfilter->dlist[in].name) + { + if (pfilter->dlist[in].name) + free (pfilter->dlist[in].name); + pfilter->dlist[in].name = strdup (gfilter->dlist[in].name); + pfilter->dlist[in].alist = gfilter->dlist[in].alist; + } + if (gfilter->plist[in].name && ! pfilter->plist[in].name) + { + if (pfilter->plist[in].name) + free (pfilter->plist[in].name); + pfilter->plist[in].name = strdup (gfilter->plist[in].name); + pfilter->plist[in].plist = gfilter->plist[in].plist; + } + if (gfilter->aslist[in].name && ! pfilter->aslist[in].name) + { + if (pfilter->aslist[in].name) + free (pfilter->aslist[in].name); + pfilter->aslist[in].name = strdup (gfilter->aslist[in].name); + pfilter->aslist[in].aslist = gfilter->aslist[in].aslist; + } + if (gfilter->map[in].name && ! pfilter->map[in].name) + { + if (pfilter->map[in].name) + free (pfilter->map[in].name); + pfilter->map[in].name = strdup (gfilter->map[in].name); + pfilter->map[in].map = gfilter->map[in].map; + } + + /* outbound filter apply */ + if (gfilter->dlist[out].name) + { + if (pfilter->dlist[out].name) + free (pfilter->dlist[out].name); + pfilter->dlist[out].name = strdup (gfilter->dlist[out].name); + pfilter->dlist[out].alist = gfilter->dlist[out].alist; + } + else + { + if (pfilter->dlist[out].name) + free (pfilter->dlist[out].name); + pfilter->dlist[out].name = NULL; + pfilter->dlist[out].alist = NULL; + } + if (gfilter->plist[out].name) + { + if (pfilter->plist[out].name) + free (pfilter->plist[out].name); + pfilter->plist[out].name = strdup (gfilter->plist[out].name); + pfilter->plist[out].plist = gfilter->plist[out].plist; + } + else + { + if (pfilter->plist[out].name) + free (pfilter->plist[out].name); + pfilter->plist[out].name = NULL; + pfilter->plist[out].plist = NULL; + } + if (gfilter->aslist[out].name) + { + if (pfilter->aslist[out].name) + free (pfilter->aslist[out].name); + pfilter->aslist[out].name = strdup (gfilter->aslist[out].name); + pfilter->aslist[out].aslist = gfilter->aslist[out].aslist; + } + else + { + if (pfilter->aslist[out].name) + free (pfilter->aslist[out].name); + pfilter->aslist[out].name = NULL; + pfilter->aslist[out].aslist = NULL; + } + if (gfilter->map[out].name) + { + if (pfilter->map[out].name) + free (pfilter->map[out].name); + pfilter->map[out].name = strdup (gfilter->map[out].name); + pfilter->map[out].map = gfilter->map[out].map; + } + else + { + if (pfilter->map[out].name) + free (pfilter->map[out].name); + pfilter->map[out].name = NULL; + pfilter->map[out].map = NULL; + } + + if (gfilter->usmap.name) + { + if (pfilter->usmap.name) + free (pfilter->usmap.name); + pfilter->usmap.name = strdup (gfilter->usmap.name); + pfilter->usmap.map = gfilter->usmap.map; + } + else + { + if (pfilter->usmap.name) + free (pfilter->usmap.name); + pfilter->usmap.name = NULL; + pfilter->usmap.map = NULL; + } +} + +/* Check peer's AS number and determin is this peer IBGP or EBGP */ +int +peer_sort (struct peer *peer) +{ + struct bgp *bgp; + + bgp = peer->bgp; + + /* Peer-group */ + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->as) + return (bgp->as == peer->as ? BGP_PEER_IBGP : BGP_PEER_EBGP); + else + { + struct peer *peer1; + peer1 = listnode_head (peer->group->peer); + if (peer1) + return (peer1->local_as == peer1->as + ? BGP_PEER_IBGP : BGP_PEER_EBGP); + } + return BGP_PEER_INTERNAL; + } + + /* Normal peer */ + if (bgp && CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) + { + if (peer->local_as == 0) + return BGP_PEER_INTERNAL; + + if (peer->local_as == peer->as) + { + if (peer->local_as == bgp->confed_id) + return BGP_PEER_EBGP; + else + return BGP_PEER_IBGP; + } + + if (bgp_confederation_peers_check (bgp, peer->as)) + return BGP_PEER_CONFED; + + return BGP_PEER_EBGP; + } + else + { + return (peer->local_as == 0 + ? BGP_PEER_INTERNAL : peer->local_as == peer->as + ? BGP_PEER_IBGP : BGP_PEER_EBGP); + } +} + +/* Allocate new peer object. */ +static struct peer * +peer_new () +{ + afi_t afi; + safi_t safi; + struct peer *peer; + struct servent *sp; + + /* Allocate new peer. */ + peer = XMALLOC (MTYPE_BGP_PEER, sizeof (struct peer)); + memset (peer, 0, sizeof (struct peer)); + + /* Set default value. */ + peer->fd = -1; + peer->v_start = BGP_INIT_START_TIMER; + peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; + peer->v_asorig = BGP_DEFAULT_ASORIGINATE; + peer->v_active_delay = BGP_ACTIVE_DELAY_TIMER; + peer->status = Idle; + peer->ostatus = Idle; + peer->password = NULL; + + /* Set default flags. */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + if (! bgp_option_check (BGP_OPT_CONFIG_CISCO)) + { + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY); + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY); + } + peer->orf_plist[afi][safi] = NULL; + } + SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); + + /* Create buffers. */ + peer->ibuf = stream_new (BGP_MAX_PACKET_SIZE); + peer->obuf = stream_fifo_new (); + peer->work = stream_new (BGP_MAX_PACKET_SIZE); + + bgp_sync_init (peer); + + /* Get service port number. */ + sp = getservbyname ("bgp", "tcp"); + peer->port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port); + + return peer; +} + +/* Create new BGP peer. */ +struct peer * +peer_create (union sockunion *su, struct bgp *bgp, as_t local_as, + as_t remote_as, afi_t afi, safi_t safi) +{ + int active; + struct peer *peer; + char buf[SU_ADDRSTRLEN]; + + peer = peer_new (); + peer->bgp = bgp; + peer->su = *su; + peer->local_as = local_as; + peer->as = remote_as; + peer->local_id = bgp->router_id; + peer->v_holdtime = bgp->default_holdtime; + peer->v_keepalive = bgp->default_keepalive; + if (peer_sort (peer) == BGP_PEER_IBGP) + peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + listnode_add_sort (bgp->peer, peer); + + active = peer_active (peer); + + if (afi && safi) + peer->afc[afi][safi] = 1; + + /* Last read time set */ + peer->readtime = time (NULL); + + /* Last reset time set */ + peer->resettime = time (NULL); + + /* Default TTL set. */ + peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1); + + /* Make peer's address string. */ + sockunion2str (su, buf, SU_ADDRSTRLEN); + peer->host = strdup (buf); + + /* set peer first create flag */ + SET_FLAG (peer->sflags, PEER_STATUS_CREATE_INIT); + + /* Set up peer's events and timers. */ + if (! active && peer_active (peer)) + bgp_timer_set (peer); + + return peer; +} + +/* Make accept BGP peer. Called from bgp_accept (). */ +struct peer * +peer_create_accept (struct bgp *bgp) +{ + struct peer *peer; + + peer = peer_new (); + peer->bgp = bgp; + listnode_add_sort (bgp->peer, peer); + + return peer; +} + +/* Change peer's AS number. */ +void +peer_as_change (struct peer *peer, as_t as) +{ + int type; + + /* Stop peer. */ + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + type = peer_sort (peer); + peer->as = as; + + if (bgp_config_check (peer->bgp, BGP_CONFIG_CONFEDERATION) + && ! bgp_confederation_peers_check (peer->bgp, as) + && peer->bgp->as != as) + peer->local_as = peer->bgp->confed_id; + else + peer->local_as = peer->bgp->as; + + /* Advertisement-interval reset */ + if (peer_sort (peer) == BGP_PEER_IBGP) + peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + + /* TTL reset */ + if (peer_sort (peer) == BGP_PEER_IBGP) + peer->ttl = 255; + else if (type == BGP_PEER_IBGP) + peer->ttl = 1; + + /* reflector-client reset */ + if (peer_sort (peer) != BGP_PEER_IBGP) + { + UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], + PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST], + PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN], + PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], + PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST], + PEER_FLAG_REFLECTOR_CLIENT); + } + + /* local-as reset */ + if (peer_sort (peer) != BGP_PEER_EBGP) + { + peer->change_local_as = 0; + UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + } +} + +/* If peer does not exist, create new one. If peer already exists, + set AS number to the peer. */ +int +peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as, + afi_t afi, safi_t safi) +{ + struct peer *peer; + as_t local_as; + + peer = peer_lookup (bgp, su); + + if (peer) + { + /* When this peer is a member of peer-group. */ + if (peer->group) + { + if (peer->group->conf->as) + { + /* Return peer group's AS number. */ + *as = peer->group->conf->as; + return BGP_ERR_PEER_GROUP_MEMBER; + } + if (peer_sort (peer->group->conf) == BGP_PEER_IBGP) + { + if (bgp->as != *as) + { + *as = peer->as; + return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; + } + } + else + { + if (bgp->as == *as) + { + *as = peer->as; + return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; + } + } + } + + /* Existing peer's AS number change. */ + if (peer->as != *as) + peer_as_change (peer, *as); + } + else + { + + /* If the peer is not part of our confederation, and its not an + iBGP peer then spoof the source AS */ + if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION) + && ! bgp_confederation_peers_check (bgp, *as) + && bgp->as != *as) + local_as = bgp->confed_id; + else + local_as = bgp->as; + + /* If this is IPv4 unicast configuration and "no bgp default + ipv4-unicast" is specified. */ + + if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4) + && afi == AFI_IP && safi == SAFI_UNICAST) + peer = peer_create (su, bgp, local_as, *as, 0, 0); + else + peer = peer_create (su, bgp, local_as, *as, afi, safi); + } + + return 0; +} + +/* Activate the peer or peer group for specified AFI and SAFI. */ +int +peer_activate (struct peer *peer, afi_t afi, safi_t safi) +{ + int active; + + if (peer->afc[afi][safi]) + return 0; + + /* Activate the address family configuration. */ + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + peer->afc[afi][safi] = 1; + else + { + active = peer_active (peer); + + peer->afc[afi][safi] = 1; + + if (peer_group_member (peer)) + { + peer->group->conf->afc[afi][safi] = 1; + peer_group_af_config_copy (peer->group->conf, peer, afi, safi); + } + + if (! active && peer_active (peer)) + bgp_timer_set (peer); + else + { + if (peer->status == Established) + { + if (CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV) + && CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV)) + { + peer->afc_adv[afi][safi] = 1; + bgp_capability_send (peer, afi, safi, + CAPABILITY_CODE_MP, + CAPABILITY_ACTION_SET); + if (peer->afc_recv[afi][safi]) + { + peer->afc_nego[afi][safi] = 1; + bgp_announce_route (peer, afi, safi); + } + } + else + { + peer->last_reset = PEER_DOWN_AF_ACTIVATE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + } + } + } + return 0; +} + +int +peer_deactivate (struct peer *peer, afi_t afi, safi_t safi) +{ + struct peer_group *group; + struct peer *peer1; + struct listnode *nn; + + if (! peer->afc[afi][safi]) + return 0; + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + + LIST_LOOP (group->peer, peer1, nn) + { + if (peer1->afc[afi][safi]) + return BGP_ERR_PEER_GROUP_MEMBER_EXISTS; + } + } + + /* De-activate the address family configuration. */ + peer->afc[afi][safi] = 0; + peer_af_flag_reset (peer, afi, safi); + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->status == Established) + { + if (CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV) + && CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV)) + { + peer->afc_adv[afi][safi] = 0; + peer->afc_nego[afi][safi] = 0; + + if (peer_active_nego (peer)) + { + bgp_capability_send (peer, afi, safi, + CAPABILITY_CODE_MP, + CAPABILITY_ACTION_UNSET); + bgp_clear_route (peer, afi, safi); + peer->synctime[afi][safi] = 0; + BGP_TIMER_OFF (peer->t_routeadv[afi][safi]); + peer->af_sflags[afi][safi] = 0; + } + else + { + peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + } + else + { + peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + } + } + return 0; +} + +void +peer_nsf_stop (struct peer *peer) +{ + afi_t afi; + safi_t safi; + + UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); + UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); + + for (afi = AFI_IP ; afi < AFI_MAX ; afi++) + for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) + peer->nsf[afi][safi] = 0; + + if (peer->t_gr_restart) + { + BGP_TIMER_OFF (peer->t_gr_restart); + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s graceful restart timer stopped", peer->host); + } + if (peer->t_gr_stale) + { + BGP_TIMER_OFF (peer->t_gr_stale); + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s graceful restart stalepath timer stopped", peer->host); + } + bgp_clear_route_all (peer); +} + +/* Delete peer from confguration. */ +int +peer_delete (struct peer *peer) +{ + int i; + afi_t afi; + safi_t safi; + struct bgp *bgp; + struct bgp_filter *filter; + + bgp = peer->bgp; + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) + peer_nsf_stop (peer); + + /* Delete peer from peer-list of group when peer is member of peer-group. */ + if (peer_group_member (peer)) + { + listnode_delete (peer->group->peer, peer); + peer->group = NULL; + } + + /* Withdraw all information from routing table. We can not use + BGP_EVENT_ADD (peer, BGP_Stop) at here. Because the event is + executed after peer structure is deleted. */ + if (peer->status == Established) + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_PEER_UNCONFIG); + else + { + bgp_stop (peer); + bgp_fsm_change_status (peer, Idle); + } + + /* Stop all timers. */ + BGP_TIMER_OFF (peer->t_start); + BGP_TIMER_OFF (peer->t_connect); + BGP_TIMER_OFF (peer->t_holdtime); + BGP_TIMER_OFF (peer->t_keepalive); + BGP_TIMER_OFF (peer->t_asorig); + BGP_TIMER_OFF (peer->t_pmax_restart); + BGP_TIMER_OFF (peer->t_gr_restart); + BGP_TIMER_OFF (peer->t_gr_stale); + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + BGP_TIMER_OFF (peer->t_routeadv[afi][safi]); + +#ifdef HAVE_TCP_SIGNATURE + /* Password configuration */ + if (peer->password) + { + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + bgp_tcpsig_unset (bm->sock, peer); + free (peer->password); + } +#endif /* HAVE_TCP_SIGNATURE */ + + /* Delete peer from peer-list of bgp, except peer of peer_self and peer_group. */ + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) + && peer != bgp->peer_self) + listnode_delete (bgp->peer, peer); + + /* Buffer. */ + if (peer->ibuf) + stream_free (peer->ibuf); + + if (peer->obuf) + stream_fifo_free (peer->obuf); + + if (peer->work) + stream_free (peer->work); + + /* Free allocated host character. */ + if (peer->host) + free (peer->host); + + /* Local and remote addresses. */ + if (peer->su_local) + XFREE (MTYPE_TMP, peer->su_local); + if (peer->su_remote) + XFREE (MTYPE_TMP, peer->su_remote); + + /* Peer description string. */ + if (peer->desc) + XFREE (MTYPE_TMP, peer->desc); + + bgp_sync_delete (peer); + + /* Free filter related memory. */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + filter = &peer->filter[afi][safi]; + + for (i = FILTER_IN; i < FILTER_MAX; i++) + { + if (filter->dlist[i].name) + free (filter->dlist[i].name); + if (filter->plist[i].name) + free (filter->plist[i].name); + if (filter->aslist[i].name) + free (filter->aslist[i].name); + if (filter->map[i].name) + free (filter->map[i].name); + } + + if (filter->usmap.name) + free (filter->usmap.name); + + if (peer->default_rmap[afi][safi].name) + free (peer->default_rmap[afi][safi].name); + } + + /* Update source configuration. */ + if (peer->update_source) + { + sockunion_free (peer->update_source); + peer->update_source = NULL; + } + if (peer->update_if) + { + XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + peer->update_if = NULL; + } + + /* Free peer structure. */ + XFREE (MTYPE_BGP_PEER, peer); + + return 0; +} + +int +peer_group_cmp (struct peer_group *g1, struct peer_group *g2) +{ + return strcmp (g1->name, g2->name); +} + +/* If peer is member of peer-group return 1. */ +int +peer_group_member (struct peer *peer) +{ + if (peer->group && ! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 1; + return 0; +} + +/* Peer group cofiguration. */ +static struct peer_group * +peer_group_new () +{ + return (struct peer_group *) XCALLOC (MTYPE_PEER_GROUP, + sizeof (struct peer_group)); +} + +void +peer_group_free (struct peer_group *group) +{ + XFREE (MTYPE_PEER_GROUP, group); +} + +struct peer_group * +peer_group_lookup (struct bgp *bgp, char *name) +{ + struct peer_group *group; + struct listnode *nn; + + LIST_LOOP (bgp->group, group, nn) + { + if (strcmp (group->name, name) == 0) + return group; + } + return NULL; +} + +struct peer_group * +peer_group_get (struct bgp *bgp, char *name) +{ + struct peer_group *group; + + group = peer_group_lookup (bgp, name); + if (group) + return group; + + group = peer_group_new (); + group->bgp = bgp; + group->name = strdup (name); + group->peer = list_new (); + group->conf = peer_new (); + if (! bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) + group->conf->afc[AFI_IP][SAFI_UNICAST] = 1; + group->conf->host = strdup (name); + group->conf->bgp = bgp; + group->conf->group = group; + group->conf->as = 0; + group->conf->ttl = 1; + group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + UNSET_FLAG (group->conf->config, PEER_CONFIG_TIMER); + group->conf->keepalive = 0; + group->conf->holdtime = 0; + SET_FLAG (group->conf->sflags, PEER_STATUS_GROUP); + listnode_add_sort (bgp->group, group); + + return 0; +} + +/* Peer group's remote AS configuration. */ +int +peer_group_remote_as (struct bgp *bgp, char *group_name, as_t *as) +{ + struct peer_group *group; + struct peer *peer; + struct listnode *nn; + + group = peer_group_lookup (bgp, group_name); + if (! group) + return -1; + + if (group->conf->as == *as) + return 0; + + /* When we setup peer-group AS number all peer group member's AS + number must be updated to same number. */ + peer_as_change (group->conf, *as); + + LIST_LOOP (group->peer, peer, nn) + { + if (peer->as != *as) + peer_as_change (peer, *as); + } + + return 0; +} + +int +peer_group_delete (struct peer_group *group) +{ + struct bgp *bgp; + struct peer *peer; + struct listnode *nn; + struct listnode *next; + + bgp = group->bgp; + + for (nn = group->peer->head; nn; nn = next) + { + peer = nn->data; + next = nn->next; + peer_delete (peer); + } + + free (group->name); + group->name = NULL; + peer_delete (group->conf); + + /* Delete from all peer_group list. */ + listnode_delete (bgp->group, group); + + peer_group_free (group); + + return 0; +} + +int +peer_group_remote_as_delete (struct peer_group *group) +{ + struct peer *peer; + struct listnode *nn; + + if (! group->conf->as) + return 0; + + LIST_LOOP (group->peer, peer, nn) + { + peer->group = NULL; + peer_delete (peer); + } + list_delete_all_node (group->peer); + + group->conf->as = 0; + + return 0; +} + +/* Bind specified peer to peer group. */ +int +peer_group_bind (struct bgp *bgp, union sockunion *su, + struct peer_group *group, afi_t afi, safi_t safi, as_t *as) +{ + struct peer *peer; + int first_member = 0; + + /* Lookup the peer. */ + peer = peer_lookup (bgp, su); + + /* Create a new peer. */ + if (! peer) + { + if (! group->conf->as) + return BGP_ERR_PEER_GROUP_NO_REMOTE_AS; + + peer = peer_create (su, bgp, bgp->as, group->conf->as, 0, 0); + peer->group = group; + listnode_add (group->peer, peer); + peer_group_global_config_copy (group->conf, peer); + + if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4) + && afi == AFI_IP && safi == SAFI_UNICAST) + return 0; + + return peer_activate (peer, afi, safi); + } + + /* When the peer already belongs to peer group, check the consistency. */ + if (peer_group_member (peer)) + { + if (strcmp (peer->group->name, group->name) != 0) + return BGP_ERR_PEER_GROUP_CANT_CHANGE; + + return peer_activate (peer, afi, safi); + } + + if (! group->conf->as) + { + if (peer_sort (group->conf) == BGP_PEER_INTERNAL) + first_member = 1; + else if (peer_sort (group->conf) != peer_sort (peer)) + { + if (as) + *as = peer->as; + return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; + } + } + + peer->group = group; + listnode_add (group->peer, peer); + + if (first_member) + { + /* Advertisement-interval reset */ + if (peer_sort (group->conf) == BGP_PEER_IBGP) + group->conf->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + + /* ebgp-multihop reset */ + if (peer_sort (group->conf) == BGP_PEER_IBGP) + group->conf->ttl = 255; + + /* local-as reset */ + if (peer_sort (group->conf) != BGP_PEER_EBGP) + { + group->conf->change_local_as = 0; + UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + } + } + + peer_group_global_config_copy (group->conf, peer); + peer_deactivate (peer, afi, safi); + return peer_activate (peer, afi,safi); +} + +/* Bind specified peer to peer group. */ +int +peer_group_bind2 (struct bgp *bgp, union sockunion *su, + struct peer_group *group, afi_t afi, safi_t safi, as_t *as) +{ + struct peer *peer; + int first_member = 0; + + /* Lookup the peer. */ + peer = peer_lookup (bgp, su); + + /* Create a new peer. */ + if (! peer) + { + if (! group->conf->as) + return BGP_ERR_PEER_GROUP_NO_REMOTE_AS; + + if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4) + && afi == AFI_IP && safi == SAFI_UNICAST) + { + peer = peer_create (su, bgp, bgp->as, group->conf->as, 0, 0); + peer->group = group; + listnode_add (group->peer, peer); + peer_group_global_config_copy (group->conf, peer); + } + else + { + peer = peer_create (su, bgp, bgp->as, group->conf->as, afi, safi); + peer->group = group; + listnode_add (group->peer, peer); + peer_group_global_config_copy (group->conf, peer); + peer_group_af_config_copy (group->conf, peer, afi, safi); + peer_activate (group->conf, afi, safi); + } + return 0; + } + + /* When the peer already belongs to peer group, check the consistency. */ + if (peer_group_member (peer)) + { + if (strcmp (peer->group->name, group->name) != 0) + return BGP_ERR_PEER_GROUP_CANT_CHANGE; + + return peer_activate (peer, afi, safi); + } + + if (! group->conf->as) + { + if (peer_sort (group->conf) == BGP_PEER_INTERNAL) + first_member = 1; + else if (peer_sort (group->conf) != peer_sort (peer)) + { + if (as) + *as = peer->as; + return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; + } + } + + peer->group = group; + listnode_add (group->peer, peer); + + if (first_member) + { + /* Advertisement-interval reset */ + if (peer_sort (group->conf) == BGP_PEER_IBGP) + group->conf->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + + /* ebgp-multihop reset */ + if (peer_sort (group->conf) == BGP_PEER_IBGP) + group->conf->ttl = 255; + + /* local-as reset */ + if (peer_sort (group->conf) != BGP_PEER_EBGP) + { + group->conf->change_local_as = 0; + UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + } + } + + peer_group_global_config_copy (group->conf, peer); + return peer_activate (peer, afi,safi); +} + +int +peer_group_unbind (struct bgp *bgp, struct peer *peer, + struct peer_group *group, afi_t afi, safi_t safi) +{ + if (! peer->afc[afi][safi]) + return 0; + + if (group != peer->group) + return BGP_ERR_PEER_GROUP_MISMATCH; + + peer->afc[afi][safi] = 0; + peer_af_flag_reset (peer, afi, safi); + + if (! peer_active (peer)) + { + peer_delete (peer); + return 0; + } + + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_RMAP_UNBIND; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + + return 0; +} + +/* BGP instance creation by `router bgp' commands. */ +struct bgp * +bgp_create (as_t *as, char *name) +{ + struct bgp *bgp; + afi_t afi; + safi_t safi; + + bgp = XCALLOC (MTYPE_BGP, sizeof (struct bgp)); + + bgp->peer_self = peer_new (); + bgp->peer_self->bgp = bgp; + bgp->peer_self->host = strdup ("Static announcement"); + + bgp->peer = list_new (); + bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp; + + bgp->group = list_new (); + bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + bgp->route[afi][safi] = bgp_table_init (); + bgp->aggregate[afi][safi] = bgp_table_init (); + bgp->rib[afi][safi] = bgp_table_init (); + } + + bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; + bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; + bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; + bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + + bgp->as = *as; + + if (name) + bgp->name = strdup (name); + + return bgp; +} + +/* Return first entry of BGP. */ +struct bgp * +bgp_get_default () +{ + if (bm->bgp->head) + return bm->bgp->head->data; + return NULL; +} + +/* Lookup BGP entry. */ +struct bgp * +bgp_lookup (as_t as, char *name) +{ + struct bgp *bgp; + struct listnode *nn; + + LIST_LOOP (bm->bgp, bgp, nn) + if (bgp->as == as + && ((bgp->name == NULL && name == NULL) + || (bgp->name && name && strcmp (bgp->name, name) == 0))) + return bgp; + return NULL; +} + +/* Lookup BGP structure by view name. */ +struct bgp * +bgp_lookup_by_name (char *name) +{ + struct bgp *bgp; + struct listnode *nn; + + LIST_LOOP (bm->bgp, bgp, nn) + if ((bgp->name == NULL && name == NULL) + || (bgp->name && name && strcmp (bgp->name, name) == 0)) + return bgp; + return NULL; +} + +/* Called from VTY commands. */ +int +bgp_get (struct bgp **bgp_val, as_t *as, char *name) +{ + struct bgp *bgp; + + /* Multiple instance check. */ + if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE)) + { + if (name) + bgp = bgp_lookup_by_name (name); + else + bgp = bgp_get_default (); + + /* Already exists. */ + if (bgp) + { + if (bgp->as != *as) + { + *as = bgp->as; + return BGP_ERR_INSTANCE_MISMATCH; + } + *bgp_val = bgp; + return 0; + } + } + else + { + /* BGP instance name can not be specified for single instance. */ + if (name) + return BGP_ERR_MULTIPLE_INSTANCE_NOT_SET; + + /* Get default BGP structure if exists. */ + bgp = bgp_get_default (); + + if (bgp) + { + if (bgp->as != *as) + { + *as = bgp->as; + return BGP_ERR_AS_MISMATCH; + } + *bgp_val = bgp; + return 0; + } + } + + bgp = bgp_create (as, name); + listnode_add (bm->bgp, bgp); + bgp_if_update_all (); + *bgp_val = bgp; + + return 0; +} + +/* Delete BGP instance. */ +int +bgp_delete (struct bgp *bgp) +{ + struct peer *peer; + struct peer_group *group; + struct listnode *nn; + struct listnode *next; + afi_t afi; + safi_t safi; + int i; + + /* Delete static route. */ + bgp_static_delete (bgp); + + /* Unset redistribution. */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (i != ZEBRA_ROUTE_BGP) + bgp_redistribute_unset (bgp, afi, i); + + for (nn = bgp->group->head; nn; nn = next) + { + group = nn->data; + next = nn->next; + peer_group_delete (group); + } + + for (nn = bgp->peer->head; nn; nn = next) + { + peer = nn->data; + next = nn->next; + peer_delete (peer); + } + + listnode_delete (bm->bgp, bgp); + + if (bgp->name) + free (bgp->name); + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + if (bgp->route[afi][safi]) + bgp_table_finish (bgp->route[afi][safi]); + if (bgp->aggregate[afi][safi]) + bgp_table_finish (bgp->aggregate[afi][safi]); + if (bgp->rib[afi][safi]) + bgp_table_finish (bgp->rib[afi][safi]); + } + peer_delete (bgp->peer_self); + XFREE (MTYPE_BGP, bgp); + + return 0; +} + +struct peer * +peer_lookup (struct bgp *bgp, union sockunion *su) +{ + struct peer *peer; + struct listnode *nn; + + if (! bgp) + bgp = bgp_get_default (); + + if (! bgp) + return NULL; + + LIST_LOOP (bgp->peer, peer, nn) + { + if (sockunion_same (&peer->su, su) + && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + return peer; + } + return NULL; +} + +struct peer * +peer_lookup_with_open (union sockunion *su, as_t remote_as, + struct in_addr *remote_id, int *as) +{ + struct peer *peer; + struct listnode *nn; + struct bgp *bgp; + + bgp = bgp_get_default (); + if (! bgp) + return NULL; + + LIST_LOOP (bgp->peer, peer, nn) + { + if (sockunion_same (&peer->su, su) + && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + if (peer->as == remote_as + && peer->remote_id.s_addr == remote_id->s_addr) + return peer; + if (peer->as == remote_as) + *as = 1; + } + } + LIST_LOOP (bgp->peer, peer, nn) + { + if (sockunion_same (&peer->su, su) + && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + if (peer->as == remote_as + && peer->remote_id.s_addr == 0) + return peer; + if (peer->as == remote_as) + *as = 1; + } + } + return NULL; +} + +/* If peer is configured at least one address family return 1. */ +int +peer_active (struct peer *peer) +{ + if (peer->afc[AFI_IP][SAFI_UNICAST] + || peer->afc[AFI_IP][SAFI_MULTICAST] + || peer->afc[AFI_IP][SAFI_MPLS_VPN] + || peer->afc[AFI_IP6][SAFI_UNICAST] + || peer->afc[AFI_IP6][SAFI_MULTICAST]) + return 1; + return 0; +} + +/* If peer is negotiated at least one address family return 1. */ +int +peer_active_nego (struct peer *peer) +{ + if (peer->afc_nego[AFI_IP][SAFI_UNICAST] + || peer->afc_nego[AFI_IP][SAFI_MULTICAST] + || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] + || peer->afc_nego[AFI_IP6][SAFI_UNICAST] + || peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) + return 1; + return 0; +} + +/* peer_flag_change_type. */ +enum peer_change_type +{ + peer_change_none, + peer_change_reset, + peer_change_reset_in, + peer_change_reset_out, +}; + +void +peer_change_action (struct peer *peer, afi_t afi, safi_t safi, + enum peer_change_type type) +{ + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return; + + if (type == peer_change_reset) + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else if (type == peer_change_reset_in) + { + if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV) + || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV)) + bgp_route_refresh_send (peer, afi, safi, 0, 0, 0); + else + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else if (type == peer_change_reset_out) + bgp_announce_route (peer, afi, safi); +} + +struct peer_flag_action +{ + /* Peer's flag. */ + u_int32_t flag; + + /* This flag can be set for peer-group member. */ + u_char not_for_member; + + /* Action when the flag is changed. */ + enum peer_change_type type; + + /* Peer down cause */ + u_char peer_down; +}; + +struct peer_flag_action peer_flag_action_list[] = + { + { PEER_FLAG_CONNECT_MODE_PASSIVE, 0, peer_change_reset }, + { PEER_FLAG_CONNECT_MODE_ACTIVE, 0, peer_change_reset }, + { PEER_FLAG_SHUTDOWN, 0, peer_change_reset }, + { PEER_FLAG_DONT_CAPABILITY, 0, peer_change_none }, + { PEER_FLAG_OVERRIDE_CAPABILITY, 0, peer_change_none }, + { PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none }, + { PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_reset }, + { PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset }, + { 0, 0, 0 } + }; + +struct peer_flag_action peer_af_flag_action_list[] = + { + { PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out }, + { PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out }, + { PEER_FLAG_SEND_EXT_COMMUNITY, 1, peer_change_reset_out }, + { PEER_FLAG_SOFT_RECONFIG, 0, peer_change_reset_in }, + { PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset }, + { PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset }, + { PEER_FLAG_AS_PATH_UNCHANGED, 1, peer_change_reset_out }, + { PEER_FLAG_NEXTHOP_UNCHANGED, 1, peer_change_reset_out }, + { PEER_FLAG_MED_UNCHANGED, 1, peer_change_reset_out }, + { PEER_FLAG_REMOVE_PRIVATE_AS, 1, peer_change_reset_out }, + { PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in }, + { PEER_FLAG_ORF_PREFIX_SM, 1, peer_change_reset }, + { PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset }, + { 0, 0, 0 } + }; + +/* Proper action set. */ +int +peer_flag_action_set (struct peer_flag_action *action_list, int size, + struct peer_flag_action *action, u_int32_t flag) +{ + int i; + int found = 0; + int reset_in = 0; + int reset_out = 0; + struct peer_flag_action *match = NULL; + + /* Check peer's frag action. */ + for (i = 0; i < size; i++) + { + match = &action_list[i]; + + if (match->flag == 0) + break; + + if (match->flag & flag) + { + found = 1; + + if (match->type == peer_change_reset_in) + reset_in = 1; + if (match->type == peer_change_reset_out) + reset_out = 1; + if (match->type == peer_change_reset) + { + reset_in = 1; + reset_out = 1; + } + if (match->not_for_member) + action->not_for_member = 1; + } + } + + /* Set peer clear type. */ + if (reset_in && reset_out) + action->type = peer_change_reset; + else if (reset_in) + action->type = peer_change_reset_in; + else if (reset_out) + action->type = peer_change_reset_out; + else + action->type = peer_change_none; + + return found; +} + +void +peer_flag_modify_action (struct peer *peer, u_int32_t flag) +{ + if (flag == PEER_FLAG_SHUTDOWN) + { + if (CHECK_FLAG (peer->flags, flag)) + { + if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) + peer_nsf_stop (peer); + + UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); + if (peer->t_pmax_restart) + { + BGP_TIMER_OFF (peer->t_pmax_restart); + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s Maximum-prefix restart timer canceled", peer->host); + } + + if (peer->status == Established) + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + else + { + BGP_EVENT_ADD (peer, BGP_Start); + } + } + else if (peer->status == Established) + { + if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK) + peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE; + + if (flag != PEER_FLAG_CONNECT_MODE_ACTIVE + && flag != PEER_FLAG_CONNECT_MODE_PASSIVE) + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); +} + +/* Change specified peer flag. */ +int +peer_flag_modify (struct peer *peer, u_int32_t flag, int set) +{ + int found; + int size; + struct peer_group *group; + struct listnode *nn; + struct peer_flag_action action; + + memset (&action, 0, sizeof (struct peer_flag_action)); + size = sizeof peer_flag_action_list / sizeof (struct peer_flag_action); + + found = peer_flag_action_set (peer_flag_action_list, size, &action, flag); + + /* No flag action is found. */ + if (! found) + return BGP_ERR_INVALID_FLAG; + + /* Not for peer-group member. */ + if (action.not_for_member && peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + /* When unset the peer-group member's flag we have to check + peer-group configuration. */ + if (! set && peer_group_member (peer)) + if (CHECK_FLAG (peer->group->conf->flags, flag)) + { + if (flag == PEER_FLAG_SHUTDOWN) + return BGP_ERR_PEER_GROUP_SHUTDOWN; + else + return BGP_ERR_PEER_GROUP_HAS_THE_FLAG; + } + + /* Flag conflict check. */ + if (set + && CHECK_FLAG (peer->flags | flag, PEER_FLAG_STRICT_CAP_MATCH) + && CHECK_FLAG (peer->flags | flag, PEER_FLAG_OVERRIDE_CAPABILITY)) + return BGP_ERR_PEER_FLAG_CONFLICT; + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (set && CHECK_FLAG (peer->flags, flag) == flag) + return 0; + if (! set && ! CHECK_FLAG (peer->flags, flag)) + return 0; + } + + if (set) + SET_FLAG (peer->flags, flag); + else + UNSET_FLAG (peer->flags, flag); + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (action.type == peer_change_reset) + peer_flag_modify_action (peer, flag); + + return 0; + } + + /* peer-group member updates. */ + group = peer->group; + + LIST_LOOP (group->peer, peer, nn) + { + if (set && CHECK_FLAG (peer->flags, flag) == flag) + continue; + + if (! set && ! CHECK_FLAG (peer->flags, flag)) + continue; + + if (set) + SET_FLAG (peer->flags, flag); + else + UNSET_FLAG (peer->flags, flag); + + if (action.type == peer_change_reset) + peer_flag_modify_action (peer, flag); + } + return 0; +} + +int +peer_flag_set (struct peer *peer, u_int32_t flag) +{ + return peer_flag_modify (peer, flag, 1); +} + +int +peer_flag_unset (struct peer *peer, u_int32_t flag) +{ + return peer_flag_modify (peer, flag, 0); +} + +int +peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag, + int set) +{ + int found; + int size; + struct listnode *nn; + struct peer_group *group; + struct peer_flag_action action; + + memset (&action, 0, sizeof (struct peer_flag_action)); + size = sizeof peer_af_flag_action_list / sizeof (struct peer_flag_action); + + found = peer_flag_action_set (peer_af_flag_action_list, size, &action, flag); + + /* No flag action is found. */ + if (! found) + return BGP_ERR_INVALID_FLAG; + + /* Adress family must be activated. */ + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + /* Not for peer-group member. */ + if (action.not_for_member && peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + /* Spcecial check for reflector client. */ + if (flag & PEER_FLAG_REFLECTOR_CLIENT + && peer_sort (peer) != BGP_PEER_IBGP) + return BGP_ERR_NOT_INTERNAL_PEER; + + /* Spcecial check for remove-private-AS. */ + if (flag & PEER_FLAG_REMOVE_PRIVATE_AS + && peer_sort (peer) == BGP_PEER_IBGP) + return BGP_ERR_REMOVE_PRIVATE_AS; + + /* When unset the peer-group member's flag we have to check + peer-group configuration. */ + if (! set && peer_group_member(peer)) + if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi], flag)) + return BGP_ERR_PEER_GROUP_HAS_THE_FLAG; + + /* When current flag configuration is same as requested one. */ + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag) + return 0; + if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag)) + return 0; + } + + if (set) + SET_FLAG (peer->af_flags[afi][safi], flag); + else + UNSET_FLAG (peer->af_flags[afi][safi], flag); + + /* Execute action when peer is established. */ + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) + && peer->status == Established) + { + if (! set && flag == PEER_FLAG_SOFT_RECONFIG) + bgp_clear_adj_in (peer, afi, safi); + else + { + if (flag == PEER_FLAG_REFLECTOR_CLIENT) + peer->last_reset = PEER_DOWN_RR_CLIENT_CHANGE; + else if (flag == PEER_FLAG_RSERVER_CLIENT) + peer->last_reset = PEER_DOWN_RS_CLIENT_CHANGE; + else if (flag == PEER_FLAG_ORF_PREFIX_SM) + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + else if (flag == PEER_FLAG_ORF_PREFIX_RM) + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + + peer_change_action (peer, afi, safi, action.type); + } + } + + /* Peer group member updates. */ + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + + LIST_LOOP (group->peer, peer, nn) + { + if (! peer->afc[afi][safi]) + continue; + + if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag) + continue; + + if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag)) + continue; + + if (set) + SET_FLAG (peer->af_flags[afi][safi], flag); + else + UNSET_FLAG (peer->af_flags[afi][safi], flag); + + if (peer->status == Established) + { + if (! set && flag == PEER_FLAG_SOFT_RECONFIG) + bgp_clear_adj_in (peer, afi, safi); + else + { + if (flag == PEER_FLAG_REFLECTOR_CLIENT) + peer->last_reset = PEER_DOWN_RR_CLIENT_CHANGE; + else if (flag == PEER_FLAG_RSERVER_CLIENT) + peer->last_reset = PEER_DOWN_RS_CLIENT_CHANGE; + else if (flag == PEER_FLAG_ORF_PREFIX_SM) + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + else if (flag == PEER_FLAG_ORF_PREFIX_RM) + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + + peer_change_action (peer, afi, safi, action.type); + } + } + } + } + return 0; +} + +int +peer_af_flag_set (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag) +{ + return peer_af_flag_modify (peer, afi, safi, flag, 1); +} + +int +peer_af_flag_unset (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag) +{ + return peer_af_flag_modify (peer, afi, safi, flag, 0); +} + +/* EBGP multihop configuration. */ +int +peer_ebgp_multihop_set (struct peer *peer, int ttl) +{ + struct peer_group *group; + struct listnode *nn; + + if (peer_sort (peer) == BGP_PEER_IBGP) + return 0; + + peer->ttl = ttl; + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) + sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); + } + else + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + if (peer_sort (peer) == BGP_PEER_IBGP) + continue; + + peer->ttl = group->conf->ttl; + + if (peer->fd >= 0) + sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); + } + } + return 0; +} + +int +peer_ebgp_multihop_unset (struct peer *peer) +{ + struct peer_group *group; + struct listnode *nn; + + if (peer_sort (peer) == BGP_PEER_IBGP) + return 0; + + if (peer_group_member (peer)) + peer->ttl = peer->group->conf->ttl; + else + peer->ttl = 1; + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) + sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); + } + else + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + if (peer_sort (peer) == BGP_PEER_IBGP) + continue; + + peer->ttl = 1; + + if (peer->fd >= 0) + sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); + } + } + return 0; +} + +/* Neighbor description. */ +int +peer_description_set (struct peer *peer, char *desc) +{ + if (peer->desc) + XFREE (MTYPE_PEER_DESC, peer->desc); + + peer->desc = XSTRDUP (MTYPE_PEER_DESC, desc); + + return 0; +} + +int +peer_description_unset (struct peer *peer) +{ + if (peer->desc) + XFREE (MTYPE_PEER_DESC, peer->desc); + + peer->desc = NULL; + + return 0; +} + +/* Neighbor update-source. */ +int +peer_update_source_if_set (struct peer *peer, char *ifname) +{ + struct peer_group *group; + struct listnode *nn; + + if (peer->update_if) + { + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) + && strcmp (peer->update_if, ifname) == 0) + return 0; + + XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + peer->update_if = NULL; + } + + if (peer->update_source) + { + sockunion_free (peer->update_source); + peer->update_source = NULL; + } + + peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname); + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + return 0; + } + + /* peer-group member updates. */ + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + if (peer->update_if) + { + if (strcmp (peer->update_if, ifname) == 0) + continue; + + XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + peer->update_if = NULL; + } + + if (peer->update_source) + { + sockunion_free (peer->update_source); + peer->update_source = NULL; + } + + peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname); + + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + return 0; +} + +int +peer_update_source_addr_set (struct peer *peer, union sockunion *su) +{ + struct peer_group *group; + struct listnode *nn; + +#ifdef HAVE_OPENBSD_TCP_SIGNATURE + if (peer->password) + bgp_tcpsig_unset (bm->sock, peer); +#endif /* HAVE_OPENBSD_TCP_SIGNATURE */ + + if (peer->update_source) + { + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) + && sockunion_cmp (peer->update_source, su) == 0) + return 0; + sockunion_free (peer->update_source); + peer->update_source = NULL; + } + + if (peer->update_if) + { + XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + peer->update_if = NULL; + } + +#ifdef HAVE_OPENBSD_TCP_SIGNATURE + if (peer->password) + bgp_tcpsig_set (bm->sock, peer); +#endif /* HAVE_OPENBSD_TCP_SIGNATURE */ + + peer->update_source = sockunion_dup (su); + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + return 0; + } + + /* peer-group member updates. */ + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { +#ifdef HAVE_OPENBSD_TCP_SIGNATURE + if (peer->password) + bgp_tcpsig_unset (bm->sock, peer); +#endif /* HAVE_OPENBSD_TCP_SIGNATURE */ + + if (peer->update_source) + { + if (sockunion_cmp (peer->update_source, su) == 0) + continue; + sockunion_free (peer->update_source); + peer->update_source = NULL; + } + + if (peer->update_if) + { + XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + peer->update_if = NULL; + } + + peer->update_source = sockunion_dup (su); + +#ifdef HAVE_OPENBSD_TCP_SIGNATURE + if (peer->password) + bgp_tcpsig_set (bm->sock, peer); +#endif /* HAVE_OPENBSD_TCP_SIGNATURE */ + + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + return 0; +} + +int +peer_update_source_unset (struct peer *peer) +{ + union sockunion *su; + struct peer_group *group; + struct listnode *nn; + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) + && ! peer->update_source + && ! peer->update_if) + return 0; + +#ifdef HAVE_OPENBSD_TCP_SIGNATURE + if (peer->password) + bgp_tcpsig_unset (bm->sock, peer); +#endif /* HAVE_OPENBSD_TCP_SIGNATURE */ + + if (peer->update_source) + { + sockunion_free (peer->update_source); + peer->update_source = NULL; + } + if (peer->update_if) + { + XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + peer->update_if = NULL; + } + + if (peer_group_member (peer)) + { + group = peer->group; + + if (group->conf->update_source) + { + su = sockunion_dup (group->conf->update_source); + peer->update_source = su; + } + else if (group->conf->update_if) + peer->update_if = + XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, group->conf->update_if); + } + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + return 0; + } + + /* peer-group member updates. */ + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + if (! peer->update_source && ! peer->update_if) + continue; + +#ifdef HAVE_OPENBSD_TCP_SIGNATURE + if (peer->password) + bgp_tcpsig_set (bm->sock, peer); +#endif /* HAVE_OPENBSD_TCP_SIGNATURE */ + + if (peer->update_source) + { + sockunion_free (peer->update_source); + peer->update_source = NULL; + } + + if (peer->update_if) + { + XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + peer->update_if = NULL; + } + + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + return 0; +} + +int +peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi, + char *rmap) +{ + struct peer_group *group; + struct listnode *nn; + + /* Adress family must be activated. */ + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + /* Default originate can't be used for peer group memeber. */ + if (peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE) + || (rmap && ! peer->default_rmap[afi][safi].name) + || (rmap && strcmp (rmap, peer->default_rmap[afi][safi].name) != 0)) + { + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE); + + if (rmap) + { + if (peer->default_rmap[afi][safi].name) + free (peer->default_rmap[afi][safi].name); + peer->default_rmap[afi][safi].name = strdup (rmap); + peer->default_rmap[afi][safi].map = route_map_lookup_by_name (rmap); + } + } + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->status == Established && peer->afc_nego[afi][safi]) + bgp_default_originate (peer, afi, safi, 0); + return 0; + } + + /* peer-group member updates. */ + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE); + + if (rmap) + { + if (peer->default_rmap[afi][safi].name) + free (peer->default_rmap[afi][safi].name); + peer->default_rmap[afi][safi].name = strdup (rmap); + peer->default_rmap[afi][safi].map = route_map_lookup_by_name (rmap); + } + + if (peer->status == Established && peer->afc_nego[afi][safi]) + bgp_default_originate (peer, afi, safi, 0); + } + return 0; +} + +int +peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi) +{ + struct peer_group *group; + struct listnode *nn; + + /* Adress family must be activated. */ + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + /* Default originate can't be used for peer group memeber. */ + if (peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) + { + UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE); + + if (peer->default_rmap[afi][safi].name) + free (peer->default_rmap[afi][safi].name); + peer->default_rmap[afi][safi].name = NULL; + peer->default_rmap[afi][safi].map = NULL; + } + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->status == Established && peer->afc_nego[afi][safi]) + bgp_default_originate (peer, afi, safi, 1); + return 0; + } + + /* peer-group member updates. */ + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE); + + if (peer->default_rmap[afi][safi].name) + free (peer->default_rmap[afi][safi].name); + peer->default_rmap[afi][safi].name = NULL; + peer->default_rmap[afi][safi].map = NULL; + + if (peer->status == Established && peer->afc_nego[afi][safi]) + bgp_default_originate (peer, afi, safi, 1); + } + return 0; +} + +int +peer_port_set (struct peer *peer, u_int16_t port) +{ + peer->port = port; + return 0; +} + +int +peer_port_unset (struct peer *peer) +{ + peer->port = BGP_PORT_DEFAULT; + return 0; +} + +/* neighbor weight. */ +int +peer_weight_set (struct peer *peer, u_int16_t weight, afi_t afi, safi_t safi) +{ + struct peer_group *group; + struct listnode *nn; + + if (CHECK_FLAG (peer->af_config[afi][safi], PEER_AF_CONFIG_WEIGHT) + && peer->weight[afi][safi] == weight) + return 0; + + SET_FLAG (peer->af_config[afi][safi], PEER_AF_CONFIG_WEIGHT); + peer->weight[afi][safi] = weight; + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + SET_FLAG (peer->af_config[afi][safi], PEER_AF_CONFIG_WEIGHT); + peer->weight[afi][safi] = weight; + peer_clear_soft (peer, afi, safi, BGP_CLEAR_SOFT_IN); + } + } + else + peer_clear_soft (peer, afi, safi, BGP_CLEAR_SOFT_IN); + + return 0; +} + +int +peer_weight_unset (struct peer *peer, afi_t afi, safi_t safi) +{ + struct peer_group *group; + struct listnode *nn; + + if (! CHECK_FLAG (peer->af_config[afi][safi], PEER_AF_CONFIG_WEIGHT)) + return 0; + + if (peer_group_member (peer) + && CHECK_FLAG (peer->group->conf->af_config[afi][safi], PEER_AF_CONFIG_WEIGHT)) + { + peer->weight[afi][safi] = peer->group->conf->weight[afi][safi]; + } + else + { + UNSET_FLAG (peer->af_config[afi][safi], PEER_AF_CONFIG_WEIGHT); + peer->weight[afi][safi] = 0; + } + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + UNSET_FLAG (peer->af_config[afi][safi], PEER_AF_CONFIG_WEIGHT); + peer->weight[afi][safi] = 0; + peer_clear_soft (peer, afi, safi, BGP_CLEAR_SOFT_IN); + } + } + else + peer_clear_soft (peer, afi, safi, BGP_CLEAR_SOFT_IN); + + return 0; +} + +int +peer_timers_set (struct peer *peer, u_int32_t keepalive, u_int32_t holdtime) +{ + struct peer_group *group; + struct listnode *nn; + + /* Not for peer group memeber. */ + if (peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + /* keepalive value check. */ + if (keepalive > 65535) + return BGP_ERR_INVALID_VALUE; + + /* Holdtime value check. */ + if (holdtime > 65535) + return BGP_ERR_INVALID_VALUE; + + /* Holdtime value must be either 0 or greater than 3. */ + if (holdtime < 3 && holdtime != 0) + return BGP_ERR_INVALID_VALUE; + + /* Set value to the configuration. */ + SET_FLAG (peer->config, PEER_CONFIG_TIMER); + peer->holdtime = holdtime; + peer->keepalive = (keepalive < holdtime / 3 ? keepalive : holdtime / 3); + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + /* peer-group member updates. */ + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + SET_FLAG (peer->config, PEER_CONFIG_TIMER); + peer->holdtime = group->conf->holdtime; + peer->keepalive = group->conf->keepalive; + } + return 0; +} + +int +peer_timers_unset (struct peer *peer) +{ + struct peer_group *group; + struct listnode *nn; + + if (peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + /* Clear configuration. */ + UNSET_FLAG (peer->config, PEER_CONFIG_TIMER); + peer->keepalive = 0; + peer->holdtime = 0; + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + /* peer-group member updates. */ + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + UNSET_FLAG (peer->config, PEER_CONFIG_TIMER); + peer->holdtime = 0; + peer->keepalive = 0; + } + + return 0; +} + +int +peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv) +{ + if (peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + if (routeadv > 600) + return BGP_ERR_INVALID_VALUE; + + SET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); + peer->routeadv = routeadv; + peer->v_routeadv = routeadv; + + return 0; +} + +int +peer_advertise_interval_unset (struct peer *peer) +{ + if (peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + UNSET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); + peer->routeadv = 0; + + if (peer_sort (peer) == BGP_PEER_IBGP) + peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + + return 0; +} + +/* neighbor interface */ +int +peer_interface_set (struct peer *peer, char *str) +{ + if (peer->ifname) + free (peer->ifname); + peer->ifname = strdup (str); + + return 0; +} + +int +peer_interface_unset (struct peer *peer) +{ + if (peer->ifname) + free (peer->ifname); + peer->ifname = NULL; + + return 0; +} + +/* Allow-as in. */ +int +peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num) +{ + struct peer_group *group; + struct listnode *nn; + + if (allow_num < 1 || allow_num > 10) + return BGP_ERR_INVALID_VALUE; + + if (peer->allowas_in[afi][safi] != allow_num) + { + peer->allowas_in[afi][safi] = allow_num; + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN); + peer_change_action (peer, afi, safi, peer_change_reset_in); + } + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + if (peer->allowas_in[afi][safi] != allow_num) + { + peer->allowas_in[afi][safi] = allow_num; + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN); + peer_change_action (peer, afi, safi, peer_change_reset_in); + } + + } + return 0; +} + +int +peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi) +{ + struct peer_group *group; + struct listnode *nn; + + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)) + { + peer->allowas_in[afi][safi] = 0; + peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN); + } + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)) + { + peer->allowas_in[afi][safi] = 0; + peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN); + } + } + return 0; +} + +int +peer_local_as_set (struct peer *peer, as_t as, int no_prepend) +{ + struct bgp *bgp = peer->bgp; + struct peer_group *group; + struct listnode *nn; + + if (peer_sort (peer) != BGP_PEER_EBGP + && peer_sort (peer) != BGP_PEER_INTERNAL) + return BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP; + + if (bgp->as == as) + return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS; + + if (peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + if (peer->change_local_as == as && + ((CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && no_prepend) + || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && ! no_prepend))) + return 0; + + peer->change_local_as = as; + if (no_prepend) + SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + else + UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + + return 0; + } + + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + peer->change_local_as = as; + if (no_prepend) + SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + else + UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + + return 0; +} + +int +peer_local_as_unset (struct peer *peer) +{ + struct peer_group *group; + struct listnode *nn; + + if (peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + if (! peer->change_local_as) + return 0; + + peer->change_local_as = 0; + UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + + return 0; + } + + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + peer->change_local_as = 0; + UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + return 0; +} + +#ifdef HAVE_TCP_SIGNATURE +/* Set password for authenticating with the peer. */ +int +peer_password_set (struct peer *peer, char *password) +{ + struct peer_group *group; + struct listnode *nn; + + if (peer->password && strcmp (peer->password, password) == 0 + && ! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + SET_FLAG (peer->flags, PEER_FLAG_PASSWORD); + if (peer->password) + free (peer->password); + peer->password = strdup (password); + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_PASSWORD_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + + bgp_tcpsig_set (bm->sock, peer); + return 0; + } + + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + if (peer->password && strcmp (peer->password, password) == 0) + continue; + + SET_FLAG (peer->flags, PEER_FLAG_PASSWORD); + if (peer->password) + free (peer->password); + peer->password = strdup (password); + + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_PASSWORD_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + + bgp_tcpsig_set (bm->sock, peer); + } + + return 0; +} + +int +peer_password_unset (struct peer *peer) +{ + struct peer_group *group; + struct listnode *nn; + + if (! CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD) + && ! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer_group_member (peer) + && CHECK_FLAG (peer->group->conf->flags, PEER_FLAG_PASSWORD)) + return BGP_ERR_PEER_GROUP_HAS_THE_FLAG; + + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_PASSWORD_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + + bgp_tcpsig_unset (bm->sock, peer); + + UNSET_FLAG (peer->flags, PEER_FLAG_PASSWORD); + if (peer->password) + free (peer->password); + peer->password = NULL; + + return 0; + } + + UNSET_FLAG (peer->flags, PEER_FLAG_PASSWORD); + if (peer->password) + free (peer->password); + peer->password = NULL; + + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + if (! CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD)) + continue; + + if (peer->status == Established) + { + peer->last_reset = PEER_DOWN_PASSWORD_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + BGP_EVENT_ADD (peer, BGP_Stop); + + bgp_tcpsig_unset (bm->sock, peer); + + UNSET_FLAG (peer->flags, PEER_FLAG_PASSWORD); + if (peer->password) + free (peer->password); + peer->password = NULL; + } + + return 0; +} +#endif /* HAVE_TCP_SIGNATURE */ + +/* Set distribute list to the peer. */ +int +peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct, + char *name) +{ + struct bgp_filter *filter; + struct peer_group *group; + struct listnode *nn; + + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + if (direct != FILTER_IN && direct != FILTER_OUT) + return BGP_ERR_INVALID_VALUE; + + if (direct == FILTER_OUT && peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + filter = &peer->filter[afi][safi]; + + if (filter->plist[direct].name) + return BGP_ERR_PEER_FILTER_CONFLICT; + + if (filter->dlist[direct].name) + free (filter->dlist[direct].name); + filter->dlist[direct].name = strdup (name); + filter->dlist[direct].alist = access_list_lookup (afi, name); + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + filter = &peer->filter[afi][safi]; + + if (! peer->afc[afi][safi]) + continue; + + if (filter->dlist[direct].name) + free (filter->dlist[direct].name); + filter->dlist[direct].name = strdup (name); + filter->dlist[direct].alist = access_list_lookup (afi, name); + } + } + + return 0; +} + +int +peer_distribute_unset (struct peer *peer, afi_t afi, safi_t safi, int direct) +{ + struct bgp_filter *filter; + struct bgp_filter *gfilter; + struct peer_group *group; + struct listnode *nn; + + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + if (direct != FILTER_IN && direct != FILTER_OUT) + return BGP_ERR_INVALID_VALUE; + + if (direct == FILTER_OUT && peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + filter = &peer->filter[afi][safi]; + + if (filter->dlist[direct].name) + free (filter->dlist[direct].name); + filter->dlist[direct].name = NULL; + filter->dlist[direct].alist = NULL; + + if (peer_group_member (peer)) + { + gfilter = &peer->group->conf->filter[afi][safi]; + + if (gfilter->dlist[direct].name) + { + filter->dlist[direct].name = strdup (gfilter->dlist[direct].name); + filter->dlist[direct].alist = gfilter->dlist[direct].alist; + } + } + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + filter = &peer->filter[afi][safi]; + + if (! peer->afc[afi][safi]) + continue; + + if (filter->dlist[direct].name) + free (filter->dlist[direct].name); + filter->dlist[direct].name = NULL; + filter->dlist[direct].alist = NULL; + } + } + + return 0; +} + +/* Update distribute list. */ +void +peer_distribute_update (struct access_list *access) +{ + afi_t afi; + safi_t safi; + int direct; + struct listnode *nn, *nm; + struct bgp *bgp; + struct peer *peer; + struct peer_group *group; + struct bgp_filter *filter; + + LIST_LOOP (bm->bgp, bgp, nn) + { + LIST_LOOP (bgp->peer, peer, nm) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + filter = &peer->filter[afi][safi]; + + for (direct = FILTER_IN; direct < FILTER_MAX; direct++) + { + if (filter->dlist[direct].name) + filter->dlist[direct].alist = + access_list_lookup (afi, filter->dlist[direct].name); + else + filter->dlist[direct].alist = NULL; + } + } + } + LIST_LOOP (bgp->group, group, nm) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + filter = &group->conf->filter[afi][safi]; + + for (direct = FILTER_IN; direct < FILTER_MAX; direct++) + { + if (filter->dlist[direct].name) + filter->dlist[direct].alist = + access_list_lookup (afi, filter->dlist[direct].name); + else + filter->dlist[direct].alist = NULL; + } + } + } + } +} + +/* Set prefix list to the peer. */ +int +peer_prefix_list_set (struct peer *peer, afi_t afi, safi_t safi, int direct, + char *name) +{ + struct bgp_filter *filter; + struct peer_group *group; + struct listnode *nn; + + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + if (direct != FILTER_IN && direct != FILTER_OUT) + return BGP_ERR_INVALID_VALUE; + + if (direct == FILTER_OUT && peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + filter = &peer->filter[afi][safi]; + + if (filter->dlist[direct].name) + return BGP_ERR_PEER_FILTER_CONFLICT; + + if (filter->plist[direct].name) + free (filter->plist[direct].name); + filter->plist[direct].name = strdup (name); + filter->plist[direct].plist = prefix_list_lookup (afi, name); + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + filter = &peer->filter[afi][safi]; + + if (! peer->afc[afi][safi]) + continue; + + if (filter->plist[direct].name) + free (filter->plist[direct].name); + filter->plist[direct].name = strdup (name); + filter->plist[direct].plist = prefix_list_lookup (afi, name); + } + } + return 0; +} + +int +peer_prefix_list_unset (struct peer *peer, afi_t afi, safi_t safi, int direct) +{ + struct bgp_filter *filter; + struct bgp_filter *gfilter; + struct peer_group *group; + struct listnode *nn; + + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + if (direct != FILTER_IN && direct != FILTER_OUT) + return BGP_ERR_INVALID_VALUE; + + if (direct == FILTER_OUT && peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + filter = &peer->filter[afi][safi]; + + if (filter->plist[direct].name) + free (filter->plist[direct].name); + filter->plist[direct].name = NULL; + filter->plist[direct].plist = NULL; + + if (peer_group_member (peer)) + { + gfilter = &peer->group->conf->filter[afi][safi]; + + if (gfilter->plist[direct].name) + { + filter->plist[direct].name = strdup (gfilter->plist[direct].name); + filter->plist[direct].plist = gfilter->plist[direct].plist; + } + } + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + filter = &peer->filter[afi][safi]; + + if (! peer->afc[afi][safi]) + continue; + + if (filter->plist[direct].name) + free (filter->plist[direct].name); + filter->plist[direct].name = NULL; + filter->plist[direct].plist = NULL; + } + } + + return 0; +} + +/* Update prefix-list list. */ +void +peer_prefix_list_update (struct prefix_list *plist) +{ + struct listnode *nn, *nm; + struct bgp *bgp; + struct peer *peer; + struct peer_group *group; + struct bgp_filter *filter; + afi_t afi; + safi_t safi; + int direct; + + LIST_LOOP (bm->bgp, bgp, nn) + { + LIST_LOOP (bgp->peer, peer, nm) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + filter = &peer->filter[afi][safi]; + + for (direct = FILTER_IN; direct < FILTER_MAX; direct++) + { + if (filter->plist[direct].name) + filter->plist[direct].plist = + prefix_list_lookup (afi, filter->plist[direct].name); + else + filter->plist[direct].plist = NULL; + } + } + } + LIST_LOOP (bgp->group, group, nm) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + filter = &group->conf->filter[afi][safi]; + + for (direct = FILTER_IN; direct < FILTER_MAX; direct++) + { + if (filter->plist[direct].name) + filter->plist[direct].plist = + prefix_list_lookup (afi, filter->plist[direct].name); + else + filter->plist[direct].plist = NULL; + } + } + } + } +} + +int +peer_aslist_set (struct peer *peer, afi_t afi, safi_t safi, int direct, + char *name) +{ + struct bgp_filter *filter; + struct peer_group *group; + struct listnode *nn; + + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + if (direct != FILTER_IN && direct != FILTER_OUT) + return BGP_ERR_INVALID_VALUE; + + if (direct == FILTER_OUT && peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + filter = &peer->filter[afi][safi]; + + if (filter->aslist[direct].name) + free (filter->aslist[direct].name); + filter->aslist[direct].name = strdup (name); + filter->aslist[direct].aslist = as_list_lookup (name); + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + filter = &peer->filter[afi][safi]; + + if (! peer->afc[afi][safi]) + continue; + + if (filter->aslist[direct].name) + free (filter->aslist[direct].name); + filter->aslist[direct].name = strdup (name); + filter->aslist[direct].aslist = as_list_lookup (name); + } + } + return 0; +} + +int +peer_aslist_unset (struct peer *peer,afi_t afi, safi_t safi, int direct) +{ + struct bgp_filter *filter; + struct bgp_filter *gfilter; + struct peer_group *group; + struct listnode *nn; + + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + if (direct != FILTER_IN && direct != FILTER_OUT) + return BGP_ERR_INVALID_VALUE; + + if (direct == FILTER_OUT && peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + filter = &peer->filter[afi][safi]; + + if (filter->aslist[direct].name) + free (filter->aslist[direct].name); + filter->aslist[direct].name = NULL; + filter->aslist[direct].aslist = NULL; + + if (peer_group_member (peer)) + { + gfilter = &peer->group->conf->filter[afi][safi]; + + if (gfilter->aslist[direct].name) + { + filter->aslist[direct].name = strdup (gfilter->aslist[direct].name); + filter->aslist[direct].aslist = gfilter->aslist[direct].aslist; + } + } + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + filter = &peer->filter[afi][safi]; + + if (! peer->afc[afi][safi]) + continue; + + if (filter->aslist[direct].name) + free (filter->aslist[direct].name); + filter->aslist[direct].name = NULL; + filter->aslist[direct].aslist = NULL; + } + } + return 0; +} + +void +peer_aslist_update () +{ + afi_t afi; + safi_t safi; + int direct; + struct listnode *nn, *nm; + struct bgp *bgp; + struct peer *peer; + struct peer_group *group; + struct bgp_filter *filter; + + LIST_LOOP (bm->bgp, bgp, nn) + { + LIST_LOOP (bgp->peer, peer, nm) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + filter = &peer->filter[afi][safi]; + + for (direct = FILTER_IN; direct < FILTER_MAX; direct++) + { + if (filter->aslist[direct].name) + filter->aslist[direct].aslist = + as_list_lookup (filter->aslist[direct].name); + else + filter->aslist[direct].aslist = NULL; + } + } + } + LIST_LOOP (bgp->group, group, nm) + { + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + { + filter = &group->conf->filter[afi][safi]; + + for (direct = FILTER_IN; direct < FILTER_MAX; direct++) + { + if (filter->aslist[direct].name) + filter->aslist[direct].aslist = + as_list_lookup (filter->aslist[direct].name); + else + filter->aslist[direct].aslist = NULL; + } + } + } + } +} + +/* Set route-map to the peer. */ +int +peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct, + char *name) +{ + struct bgp_filter *filter; + struct peer_group *group; + struct listnode *nn; + + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + if (direct != FILTER_IN && direct != FILTER_OUT) + return BGP_ERR_INVALID_VALUE; + + if (direct == FILTER_OUT && peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + filter = &peer->filter[afi][safi]; + + if (filter->map[direct].name) + free (filter->map[direct].name); + filter->map[direct].name = strdup (name); + filter->map[direct].map = route_map_lookup_by_name (name); + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + filter = &peer->filter[afi][safi]; + + if (! peer->afc[afi][safi]) + continue; + + if (filter->map[direct].name) + free (filter->map[direct].name); + filter->map[direct].name = strdup (name); + filter->map[direct].map = route_map_lookup_by_name (name); + } + } + return 0; +} + +/* Unset route-map from the peer. */ +int +peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct) +{ + struct bgp_filter *filter; + struct bgp_filter *gfilter; + struct peer_group *group; + struct listnode *nn; + + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + if (direct != FILTER_IN && direct != FILTER_OUT) + return BGP_ERR_INVALID_VALUE; + + if (direct == FILTER_OUT && peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + filter = &peer->filter[afi][safi]; + + if (filter->map[direct].name) + free (filter->map[direct].name); + filter->map[direct].name = NULL; + filter->map[direct].map = NULL; + + if (peer_group_member (peer)) + { + gfilter = &peer->group->conf->filter[afi][safi]; + + if (gfilter->map[direct].name) + { + filter->map[direct].name = strdup (gfilter->map[direct].name); + filter->map[direct].map = gfilter->map[direct].map; + } + } + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + filter = &peer->filter[afi][safi]; + + if (! peer->afc[afi][safi]) + continue; + + if (filter->map[direct].name) + free (filter->map[direct].name); + filter->map[direct].name = NULL; + filter->map[direct].map = NULL; + } + } + return 0; +} + +/* Set unsuppress-map to the peer. */ +int +peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi, char *name) +{ + struct bgp_filter *filter; + struct peer_group *group; + struct listnode *nn; + + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + if (peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + filter = &peer->filter[afi][safi]; + + if (filter->usmap.name) + free (filter->usmap.name); + filter->usmap.name = strdup (name); + filter->usmap.map = route_map_lookup_by_name (name); + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + filter = &peer->filter[afi][safi]; + + if (! peer->afc[afi][safi]) + continue; + + if (filter->usmap.name) + free (filter->usmap.name); + filter->usmap.name = strdup (name); + filter->usmap.map = route_map_lookup_by_name (name); + } + } + return 0; +} + +/* Unset route-map from the peer. */ +int +peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp_filter *filter; + struct bgp_filter *gfilter; + struct peer_group *group; + struct listnode *nn; + + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + if (peer_group_member (peer)) + return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + filter = &peer->filter[afi][safi]; + + if (filter->usmap.name) + free (filter->usmap.name); + filter->usmap.name = NULL; + filter->usmap.map = NULL; + + if (peer_group_member (peer)) + { + gfilter = &peer->group->conf->filter[afi][safi]; + + if (gfilter->usmap.name) + { + filter->usmap.name = strdup (gfilter->usmap.name); + filter->usmap.map = gfilter->usmap.map; + } + } + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + filter = &peer->filter[afi][safi]; + + if (! peer->afc[afi][safi]) + continue; + + if (filter->usmap.name) + free (filter->usmap.name); + filter->usmap.name = NULL; + filter->usmap.map = NULL; + } + } + return 0; +} + +int +peer_maximum_prefix_set (struct peer *peer, afi_t afi, safi_t safi, + u_int32_t max, u_char threshold, + int warning, u_int16_t restart) +{ + struct peer_group *group; + struct listnode *nn; + + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); + peer->pmax[afi][safi] = max; + peer->pmax_threshold[afi][safi] = threshold; + peer->pmax_restart[afi][safi] = restart; + if (warning) + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + else + UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + if (! peer->afc[afi][safi]) + continue; + + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); + peer->pmax[afi][safi] = max; + peer->pmax_threshold[afi][safi] = threshold; + peer->pmax_restart[afi][safi] = restart; + if (warning) + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + else + UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + } + } + return 0; +} + +int +peer_maximum_prefix_unset (struct peer *peer, afi_t afi, safi_t safi) +{ + struct peer_group *group; + struct listnode *nn; + + if (! peer->afc[afi][safi]) + return BGP_ERR_PEER_INACTIVE; + + UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); + UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + peer->pmax[afi][safi] = 0; + peer->pmax_threshold[afi][safi] = 0; + peer->pmax_restart[afi][safi] = 0; + + if (peer_group_member (peer)) + { + if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi], + PEER_FLAG_MAX_PREFIX)) + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); + else + UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); + + if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi], + PEER_FLAG_MAX_PREFIX_WARNING)) + SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + else + UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + + peer->pmax[afi][safi] = peer->group->conf->pmax[afi][safi]; + peer->pmax_threshold[afi][safi] = peer->group->conf->pmax_threshold[afi][safi]; + peer->pmax_restart[afi][safi] = peer->group->conf->pmax_restart[afi][safi]; + } + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + if (! peer->afc[afi][safi]) + continue; + + UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); + UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + peer->pmax[afi][safi] = 0; + peer->pmax_threshold[afi][safi] = 0; + peer->pmax_restart[afi][safi] = 0; + } + } + return 0; +} + +int +peer_clear (struct peer *peer) +{ + if (! CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) + { + peer->v_active_delay = BGP_ACTIVE_DELAY_TIMER; + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) + { + UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); + if (peer->t_pmax_restart) + { + BGP_TIMER_OFF (peer->t_pmax_restart); + if (BGP_DEBUG (events, EVENTS)) + zlog_info ("%s Maximum-prefix restart timer canceled", peer->host); + } + BGP_EVENT_ADD (peer, BGP_Start); + return 0; + } + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) + peer_nsf_stop (peer); + + if (peer->status == Established) + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_ADMIN_RESET); + else + BGP_EVENT_ADD (peer, BGP_Stop); + } + return 0; +} + +int +peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi, + enum bgp_clear_type stype) +{ + if (peer->status != Established) + return 0; + + if (! peer->afc[afi][safi]) + return BGP_ERR_AF_UNCONFIGURED; + + if (stype == BGP_CLEAR_SOFT_OUT || stype == BGP_CLEAR_SOFT_BOTH) + bgp_announce_route (peer, afi, safi); + + if (stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX) + { + if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) + && (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV) + || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV))) + { + struct bgp_filter *filter = &peer->filter[afi][safi]; + u_char prefix_type; + + if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)) + prefix_type = ORF_TYPE_PREFIX; + else + prefix_type = ORF_TYPE_PREFIX_OLD; + + if (filter->plist[FILTER_IN].plist) + { + if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND)) + bgp_route_refresh_send (peer, afi, safi, + prefix_type, REFRESH_DEFER, 1); + bgp_route_refresh_send (peer, afi, safi, prefix_type, + REFRESH_IMMEDIATE, 0); + } + else + { + if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND)) + bgp_route_refresh_send (peer, afi, safi, + prefix_type, REFRESH_IMMEDIATE, 1); + else + bgp_route_refresh_send (peer, afi, safi, 0, 0, 0); + } + return 0; + } + } + + if (stype == BGP_CLEAR_SOFT_IN || stype == BGP_CLEAR_SOFT_BOTH + || stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX) + { + /* If neighbor has soft reconfiguration inbound flag. + Use Adj-RIB-In database. */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) + bgp_soft_reconfig_in (peer, afi, safi); + else + { + /* If neighbor has route refresh capability, send route refresh + message to the peer. */ + if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV) + || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV)) + bgp_route_refresh_send (peer, afi, safi, 0, 0, 0); + else + return BGP_ERR_SOFT_RECONFIG_UNCONFIGURED; + } + } + return 0; +} + +/* Display peer uptime. */ +char * +peer_uptime (time_t uptime2, char *buf, size_t len) +{ + time_t uptime1; + struct tm *tm; + + /* Check buffer length. */ + if (len < BGP_UPTIME_LEN) + { + zlog_warn ("peer_uptime (): buffer shortage %d", len); + return ""; + } + + /* If there is no connection has been done before print `never'. */ + if (uptime2 == 0) + { + snprintf (buf, len, "never "); + return buf; + } + + /* Get current time. */ + uptime1 = time (NULL); + uptime1 -= uptime2; + tm = gmtime (&uptime1); + + /* Making formatted timer strings. */ +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + + if (uptime1 < ONE_DAY_SECOND) + snprintf (buf, len, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (uptime1 < ONE_WEEK_SECOND) + snprintf (buf, len, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + snprintf (buf, len, "%02dw%dd%02dh", + tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + return buf; +} + +void +bgp_config_write_filter (struct vty *vty, struct peer *peer, + afi_t afi, safi_t safi) +{ + struct bgp_filter *filter; + struct bgp_filter *gfilter = NULL; + char *addr; + int in = FILTER_IN; + int out = FILTER_OUT; + + addr = peer->host; + filter = &peer->filter[afi][safi]; + if (peer_group_member (peer)) + gfilter = &peer->group->conf->filter[afi][safi]; + + /* distribute-list. */ + if (filter->dlist[in].name) + if (! gfilter || ! gfilter->dlist[in].name + || strcmp (filter->dlist[in].name, gfilter->dlist[in].name) != 0) + vty_out (vty, " neighbor %s distribute-list %s in%s", addr, + filter->dlist[in].name, VTY_NEWLINE); + if (filter->dlist[out].name && ! gfilter) + vty_out (vty, " neighbor %s distribute-list %s out%s", addr, + filter->dlist[out].name, VTY_NEWLINE); + + /* prefix-list. */ + if (filter->plist[in].name) + if (! gfilter || ! gfilter->plist[in].name + || strcmp (filter->plist[in].name, gfilter->plist[in].name) != 0) + vty_out (vty, " neighbor %s prefix-list %s in%s", addr, + filter->plist[in].name, VTY_NEWLINE); + if (filter->plist[out].name && ! gfilter) + vty_out (vty, " neighbor %s prefix-list %s out%s", addr, + filter->plist[out].name, VTY_NEWLINE); + + /* route-map. */ + if (filter->map[in].name) + if (! gfilter || ! gfilter->map[in].name + || strcmp (filter->map[in].name, gfilter->map[in].name) != 0) + vty_out (vty, " neighbor %s route-map %s in%s", addr, + filter->map[in].name, VTY_NEWLINE); + if (filter->map[out].name && ! gfilter) + vty_out (vty, " neighbor %s route-map %s out%s", addr, + filter->map[out].name, VTY_NEWLINE); + + /* unsuppress-map */ + if (filter->usmap.name && ! gfilter) + vty_out (vty, " neighbor %s unsuppress-map %s%s", addr, + filter->usmap.name, VTY_NEWLINE); + + /* filter-list. */ + if (filter->aslist[in].name) + if (! gfilter || ! gfilter->aslist[in].name + || strcmp (filter->aslist[in].name, gfilter->aslist[in].name) != 0) + vty_out (vty, " neighbor %s filter-list %s in%s", addr, + filter->aslist[in].name, VTY_NEWLINE); + if (filter->aslist[out].name && ! gfilter) + vty_out (vty, " neighbor %s filter-list %s out%s", addr, + filter->aslist[out].name, VTY_NEWLINE); +} + +/* BGP peer configuration display function. */ +void +bgp_config_write_peer_global (struct vty *vty, struct bgp *bgp, + struct peer *peer) +{ + struct peer *group = NULL; + char buf[SU_ADDRSTRLEN]; + char *addr; + + addr = peer->host; + if (peer_group_member (peer)) + group = peer->group->conf; + + /* remote-as. */ + if (peer_group_member (peer)) + { + if (! group->as) + vty_out (vty, " neighbor %s remote-as %d%s", addr, peer->as, VTY_NEWLINE); + + vty_out (vty, " neighbor %s peer-group %s%s", addr, peer->group->name, VTY_NEWLINE); + } + else + { + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + vty_out (vty, " neighbor %s peer-group%s", addr, VTY_NEWLINE); + if (peer->as) + vty_out (vty, " neighbor %s remote-as %d%s", addr, peer->as, VTY_NEWLINE); + } + + /* local-as. */ + if (peer->change_local_as) + if (! peer_group_member (peer)) + vty_out (vty, " neighbor %s local-as %d%s%s", addr, + peer->change_local_as, + CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ? + " no-prepend" : "", VTY_NEWLINE); + + /* Description. */ + if (peer->desc) + vty_out (vty, " neighbor %s description %s%s", addr, peer->desc, VTY_NEWLINE); + + /* Shutdown. */ + if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) + if (! peer_group_member (peer) || + ! CHECK_FLAG (group->flags, PEER_FLAG_SHUTDOWN)) + vty_out (vty, " neighbor %s shutdown%s", addr, VTY_NEWLINE); + +#ifdef HAVE_TCP_SIGNATURE + /* Password. */ + if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD)) + if (! peer_group_member (peer) + || ! CHECK_FLAG (group->flags, PEER_FLAG_PASSWORD) + || strcmp (peer->password, group->password) != 0) + vty_out (vty, " neighbor %s password %s%s", addr, peer->password, VTY_NEWLINE); +#endif /* HAVE_TCP_SIGNATURE */ + + /* BGP port. */ + if (peer->port != BGP_PORT_DEFAULT) + vty_out (vty, " neighbor %s port %d%s", addr, peer->port, VTY_NEWLINE); + + /* Local interface name. */ + if (peer->ifname) + vty_out (vty, " neighbor %s interface %s%s", addr, peer->ifname, VTY_NEWLINE); + + /* transport connection-mode. */ + if (CHECK_FLAG (peer->flags, PEER_FLAG_CONNECT_MODE_PASSIVE)) + if (! peer_group_member (peer) || + ! CHECK_FLAG (group->flags, PEER_FLAG_CONNECT_MODE_PASSIVE)) + vty_out (vty, " neighbor %s transport connection-mode passive%s", + addr, VTY_NEWLINE); + if (CHECK_FLAG (peer->flags, PEER_FLAG_CONNECT_MODE_ACTIVE)) + if (! peer_group_member (peer) || + ! CHECK_FLAG (group->flags, PEER_FLAG_CONNECT_MODE_ACTIVE)) + vty_out (vty, " neighbor %s transport connection-mode active%s", + addr, VTY_NEWLINE); + + /* EBGP multihop. */ + if (peer_sort (peer) != BGP_PEER_IBGP && peer->ttl != 1) + if (! peer_group_member (peer) || group->ttl != peer->ttl) + vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr, peer->ttl, + VTY_NEWLINE); + + /* disable-connected-check. */ + if (CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) + if (! peer_group_member (peer) || + ! CHECK_FLAG (group->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) + vty_out (vty, " neighbor %s disable-connected-check%s", addr, VTY_NEWLINE); + + /* Update-source. */ + if (peer->update_if) + if (! peer_group_member (peer) || ! group->update_if + || strcmp (group->update_if, peer->update_if) != 0) + vty_out (vty, " neighbor %s update-source %s%s", addr, + peer->update_if, VTY_NEWLINE); + if (peer->update_source) + if (! peer_group_member (peer) || ! group->update_source + || sockunion_cmp (group->update_source, peer->update_source) != 0) + vty_out (vty, " neighbor %s update-source %s%s", addr, + sockunion2str (peer->update_source, buf, SU_ADDRSTRLEN), + VTY_NEWLINE); + + /* advertisement-interval */ + if (CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV)) + vty_out (vty, " neighbor %s advertisement-interval %d%s", + addr, peer->v_routeadv, VTY_NEWLINE); + + /* timers. */ + if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER) + && ! peer_group_member (peer)) + vty_out (vty, " neighbor %s timers %d %d%s", addr, + peer->keepalive, peer->holdtime, VTY_NEWLINE); + + /* Dynamic capability. */ + if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) + if (! peer_group_member (peer) || + ! CHECK_FLAG (group->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) + vty_out (vty, " neighbor %s capability dynamic%s", addr, VTY_NEWLINE); + + /* dont capability negotiation. */ + if (CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY)) + if (! peer_group_member (peer) || + ! CHECK_FLAG (group->flags, PEER_FLAG_DONT_CAPABILITY)) + vty_out (vty, " neighbor %s dont-capability-negotiate%s", addr, VTY_NEWLINE); + + /* override capability negotiation. */ + if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) + if (! peer_group_member (peer) || + ! CHECK_FLAG (group->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) + vty_out (vty, " neighbor %s override-capability%s", addr, VTY_NEWLINE); + + /* strict capability negotiation. */ + if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) + if (! peer_group_member (peer) || + ! CHECK_FLAG (group->flags, PEER_FLAG_STRICT_CAP_MATCH)) + vty_out (vty, " neighbor %s strict-capability-match%s", addr, VTY_NEWLINE); +} + +void +bgp_config_write_peer (struct vty *vty, struct bgp *bgp, + struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp_filter *filter; + struct peer *g_peer = NULL; + char *addr; + + filter = &peer->filter[afi][safi]; + addr = peer->host; + if (peer_group_member (peer)) + g_peer = peer->group->conf; + + if (peer->afc[afi][safi]) + { + if (peer_group_member (peer)) + vty_out (vty, " neighbor %s peer-group %s%s", addr, + peer->group->name, VTY_NEWLINE); + else + vty_out (vty, " neighbor %s activate%s", addr, VTY_NEWLINE); + } + else + { + vty_out (vty, " no neighbor %s activate%s", addr, VTY_NEWLINE); + return; + } + + /* Route server client */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) + && ! peer_group_member (peer)) + vty_out (vty, " neighbor %s route-server-client%s", addr, VTY_NEWLINE); + + /* Route reflector client */ + if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT) + && ! peer_group_member (peer)) + vty_out (vty, " neighbor %s route-reflector-client%s", addr, + VTY_NEWLINE); + + /* Nexthop self */ + if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF) + && ! peer_group_member (peer)) + vty_out (vty, " neighbor %s next-hop-self%s", addr, VTY_NEWLINE); + + /* Attribute-unchanged. */ + if ((CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) + || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) + || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) + && ! peer_group_member (peer)) + { + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) + && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) + && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) + vty_out (vty, " neighbor %s attribute-unchanged%s", addr, VTY_NEWLINE); + else + vty_out (vty, " neighbor %s attribute-unchanged%s%s%s%s", addr, + (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)) ? + " as-path" : "", + (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)) ? + " next-hop" : "", + (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) ? + " med" : "", VTY_NEWLINE); + } + + /* Send-community */ + if (! peer_group_member (peer)) + { + if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) + { + if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) + && peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) + vty_out (vty, " neighbor %s send-community both%s", addr, VTY_NEWLINE); + else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) + vty_out (vty, " neighbor %s send-community extended%s", + addr, VTY_NEWLINE); + else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) + vty_out (vty, " neighbor %s send-community%s", addr, VTY_NEWLINE); + } + else + { + if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) + && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) + vty_out (vty, " no neighbor %s send-community both%s", + addr, VTY_NEWLINE); + else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) + vty_out (vty, " no neighbor %s send-community extended%s", + addr, VTY_NEWLINE); + else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) + vty_out (vty, " no neighbor %s send-community%s", + addr, VTY_NEWLINE); + } + } + + /* Default information */ + if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_DEFAULT_ORIGINATE) + && ! peer_group_member (peer)) + { + vty_out (vty, " neighbor %s default-originate", addr); + if (peer->default_rmap[afi][safi].name) + vty_out (vty, " route-map %s", peer->default_rmap[afi][safi].name); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Remove private AS */ + if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) + && ! peer_group_member (peer)) + vty_out (vty, " neighbor %s remove-private-AS%s", + addr, VTY_NEWLINE); + + /* Weight */ + if (CHECK_FLAG (peer->af_config[afi][safi], PEER_AF_CONFIG_WEIGHT)) + if (! peer_group_member (peer) || + g_peer->weight[afi][safi] != peer->weight[afi][safi]) + vty_out (vty, " neighbor %s weight %d%s", addr, peer->weight[afi][safi], + VTY_NEWLINE); + + /* ORF capability */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) + || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) + if (! peer_group_member (peer)) + { + vty_out (vty, " neighbor %s capability orf prefix-list", addr); + + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) + && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) + vty_out (vty, " both"); + else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)) + vty_out (vty, " send"); + else + vty_out (vty, " receive"); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Allow AS in. */ + if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) + if (! peer_group_member (peer) + || ! peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_ALLOWAS_IN) + || peer->allowas_in[afi][safi] != g_peer->allowas_in[afi][safi]) + { + if (peer->allowas_in[afi][safi] == 3) + vty_out (vty, " neighbor %s allowas-in%s", addr, VTY_NEWLINE); + else + vty_out (vty, " neighbor %s allowas-in %d%s", addr, + peer->allowas_in[afi][safi], VTY_NEWLINE); + } + + /* Soft reconfiguration inbound */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) + if (! peer_group_member (peer) || + ! CHECK_FLAG (g_peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) + vty_out (vty, " neighbor %s soft-reconfiguration inbound%s", addr, + VTY_NEWLINE); + + /* Filter. */ + bgp_config_write_filter (vty, peer, afi, safi); + + /* Maximum-prefix */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) + if (! peer_group_member (peer) + || g_peer->pmax[afi][safi] != peer->pmax[afi][safi] + || g_peer->pmax_threshold[afi][safi] != peer->pmax_threshold[afi][safi] + || g_peer->pmax_restart[afi][safi] != peer->pmax_restart[afi][safi] + || CHECK_FLAG (g_peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING) + != CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)) + { + vty_out (vty, " neighbor %s maximum-prefix %ld", addr, peer->pmax[afi][safi]); + if (peer->pmax_threshold[afi][safi] != MAXIMUM_PREFIX_THRESHOLD_DEFAULT) + vty_out (vty, " %d", peer->pmax_threshold[afi][safi]); + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)) + vty_out (vty, " warning-only"); + if (peer->pmax_restart[afi][safi]) + vty_out (vty, " restart %d", peer->pmax_restart[afi][safi]); + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +/* Display "address-family" configuration header. */ +void +bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi, + int *write) +{ + if (*write) + return; + + vty_out (vty, "!%s address-family ", VTY_NEWLINE); + + if (afi == AFI_IP) + { + if (safi == SAFI_UNICAST) + vty_out (vty, "ipv4"); + else if (safi == SAFI_MULTICAST) + vty_out (vty, "ipv4 multicast"); + else if (safi == SAFI_MPLS_VPN) + vty_out (vty, "vpnv4 unicast"); + } + else if (afi == AFI_IP6) + vty_out (vty, "ipv6"); + + vty_out (vty, "%s", VTY_NEWLINE); + + *write = 1; +} + +/* Address family based peer configuration display. */ +int +bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi) +{ + int write = 0; + struct peer *peer; + struct peer_group *group; + struct listnode *nn; + + bgp_config_write_redistribute (vty, bgp, afi, safi, &write); + + LIST_LOOP (bgp->group, group, nn) + { + if ((! bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4) + && afi == AFI_IP && safi == SAFI_UNICAST) + || group->conf->afc[afi][safi]) + { + bgp_config_write_family_header (vty, afi, safi, &write); + bgp_config_write_peer (vty, bgp, group->conf, afi, safi); + } + } + LIST_LOOP (bgp->peer, peer, nn) + { + if ((! bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4) + && afi == AFI_IP && safi == SAFI_UNICAST) + || peer->afc[afi][safi]) + { + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + { + bgp_config_write_family_header (vty, afi, safi, &write); + bgp_config_write_peer (vty, bgp, peer, afi, safi); + } + } + } + + bgp_config_write_network (vty, bgp, afi, safi, &write); + + /* BGP flag dampening. */ + if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) + { + bgp_config_write_family_header (vty, afi, safi, &write); + bgp_config_write_damp (vty); + } + + if (write) + { + /* No auto-summary */ + if (afi == AFI_IP && (safi == SAFI_UNICAST || safi == SAFI_MULTICAST) + && bgp_option_check (BGP_OPT_CONFIG_CISCO)) + vty_out (vty, " no auto-summary%s", VTY_NEWLINE); + + /* No Synchronization */ + if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST + && bgp_option_check (BGP_OPT_CONFIG_CISCO)) + vty_out (vty, " no synchronization%s", VTY_NEWLINE); + + vty_out (vty, " exit-address-family%s", VTY_NEWLINE); + } + return write; +} + +int +bgp_config_write (struct vty *vty) +{ + int write = 0; + struct bgp *bgp; + struct peer_group *group; + struct peer *peer; + struct listnode *nn, *nm, *no; + + /* BGP Multiple instance. */ + if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE)) + { + vty_out (vty, "bgp multiple-instance%s", VTY_NEWLINE); + write++; + } + + /* BGP Config type. */ + if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) + { + vty_out (vty, "bgp config-type cisco%s", VTY_NEWLINE); + write++; + } + + /* BGP configuration. */ + LIST_LOOP (bm->bgp, bgp, nn) + { + if (write) + vty_out (vty, "!%s", VTY_NEWLINE); + + /* Router bgp ASN */ + vty_out (vty, "router bgp %d", bgp->as); + + if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE)) + { + if (bgp->name) + vty_out (vty, " view %s", bgp->name); + } + vty_out (vty, "%s", VTY_NEWLINE); + + /* BGP fast-external-failover. */ + if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) + vty_out (vty, " no bgp fast-external-failover%s", VTY_NEWLINE); + + /* BGP router ID. */ + if (CHECK_FLAG (bgp->config, BGP_CONFIG_ROUTER_ID)) + vty_out (vty, " bgp router-id %s%s", inet_ntoa (bgp->router_id), + VTY_NEWLINE); + + /* BGP log-neighbor-changes. */ + if (bgp_flag_check (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) + vty_out (vty, " bgp log-neighbor-changes%s", VTY_NEWLINE); + + /* BGP configuration. */ + if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED)) + vty_out (vty, " bgp always-compare-med%s", VTY_NEWLINE); + + /* BGP default ipv4-unicast. */ + if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) + vty_out (vty, " no bgp default ipv4-unicast%s", VTY_NEWLINE); + + /* BGP default local-preference. */ + if (bgp->default_local_pref != BGP_DEFAULT_LOCAL_PREF) + vty_out (vty, " bgp default local-preference %d%s", + bgp->default_local_pref, VTY_NEWLINE); + + /* BGP client-to-client reflection. */ + if (bgp_flag_check (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT)) + vty_out (vty, " no bgp client-to-client reflection%s", VTY_NEWLINE); + + /* BGP cluster ID. */ + if (CHECK_FLAG (bgp->config, BGP_CONFIG_CLUSTER_ID)) + vty_out (vty, " bgp cluster-id %s%s", inet_ntoa (bgp->cluster_id), + VTY_NEWLINE); + + /* Confederation identifier */ + if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) + vty_out (vty, " bgp confederation identifier %i%s", bgp->confed_id, + VTY_NEWLINE); + + /* Confederation peer */ + if (bgp->confed_peers_cnt > 0) + { + int i; + + vty_out (vty, " bgp confederation peers"); + + for (i = 0; i < bgp->confed_peers_cnt; i++) + vty_out(vty, " %d", bgp->confed_peers[i]); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* BGP enforce-first-as. */ + if (bgp_flag_check (bgp, BGP_FLAG_NO_ENFORCE_FIRST_AS)) + vty_out (vty, " no bgp enforce-first-as%s", VTY_NEWLINE); + + /* BGP deterministic-med. */ + if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) + vty_out (vty, " bgp deterministic-med%s", VTY_NEWLINE); + + /* BGP graceful-restart. */ + if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + vty_out (vty, " bgp graceful-restart stalepath-time %d%s", + bgp->stalepath_time, VTY_NEWLINE); + if (bgp_flag_check (bgp, BGP_FLAG_GRACEFUL_RESTART)) + vty_out (vty, " bgp graceful-restart%s", VTY_NEWLINE); + + /* BGP bestpath method. */ + if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE)) + vty_out (vty, " bgp bestpath as-path ignore%s", VTY_NEWLINE); + if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED) + || bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST)) + { + vty_out (vty, " bgp bestpath med"); + if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED)) + vty_out (vty, " confed"); + if (bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST)) + vty_out (vty, " missing-as-worst"); + vty_out (vty, "%s", VTY_NEWLINE); + } + if (bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID)) + vty_out (vty, " bgp bestpath compare-routerid%s", VTY_NEWLINE); + if (bgp_flag_check (bgp, BGP_FLAG_COST_COMMUNITY_IGNORE)) + vty_out (vty, " bgp bestpath cost-community ignore%s", VTY_NEWLINE); + + /* BGP network import check. */ + if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) + vty_out (vty, " bgp network import-check%s", VTY_NEWLINE); + + /* BGP scan interval. */ + bgp_config_write_scan_time (vty); + + /* BGP timers configuration. */ + if (bgp->default_keepalive != BGP_DEFAULT_KEEPALIVE + && bgp->default_holdtime != BGP_DEFAULT_HOLDTIME) + vty_out (vty, " timers bgp %d %d%s", bgp->default_keepalive, + bgp->default_holdtime, VTY_NEWLINE); + + /* Distance configuration. */ + bgp_config_write_distance (vty, bgp); + + /* peer-group */ + LIST_LOOP (bgp->group, group, nm) + { + bgp_config_write_peer_global (vty, bgp, group->conf); + } + + /* Normal neighbor configuration. */ + LIST_LOOP (bgp->peer, peer, no) + { + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) + bgp_config_write_peer_global (vty, bgp, peer); + } + + /* IPv4 unicast configuration. */ + write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_UNICAST); + + /* IPv4 multicast configuration. */ + write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MULTICAST); + + /* IPv4 VPN configuration. */ + write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MPLS_VPN); + + /* IPv6 unicast configuration. */ + write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_UNICAST); + + write++; + } + return write; +} + +void +bgp_master_init () +{ + memset (&bgp_master, 0, sizeof (struct bgp_master)); + + bm = &bgp_master; + bm->bgp = list_new (); + bm->port = BGP_PORT_DEFAULT; + bm->master = thread_master_create (); + bm->start_time = time (NULL); +#ifdef HAVE_TCP_SIGNATURE + bm->sock = -1; +#endif /* HAVE_TCP_SIGNATURE */ +} + +void +bgp_init () +{ + void bgp_zebra_init (); + void bgp_route_map_init (); + void bgp_filter_init (); + + /* BGP VTY commands installation. */ + bgp_vty_init (); + + /* Create BGP server socket. */ + bgp_socket (NULL, bm->port); + + /* Init zebra. */ + bgp_zebra_init (); + + /* BGP inits. */ + bgp_attr_init (); + bgp_debug_init (); + bgp_dump_init (); + bgp_route_init (); + bgp_route_map_init (); + bgp_scan_init (); + bgp_mplsvpn_init (); + + /* Access list initialize. */ + access_list_init (); + access_list_add_hook (peer_distribute_update); + access_list_delete_hook (peer_distribute_update); + + /* Filter list initialize. */ + bgp_filter_init (); + as_list_add_hook (peer_aslist_update); + as_list_delete_hook (peer_aslist_update); + + /* Prefix list initialize.*/ + prefix_list_init (); + prefix_list_add_hook (peer_prefix_list_update); + prefix_list_delete_hook (peer_prefix_list_update); + + /* Community list initialize. */ + bgp_clist = community_list_init (); + +#ifdef HAVE_SNMP + bgp_snmp_init (); +#endif /* HAVE_SNMP */ +} diff --git a/bgpd/bgpd.conf.sample b/bgpd/bgpd.conf.sample new file mode 100644 index 0000000..8ef835d --- /dev/null +++ b/bgpd/bgpd.conf.sample @@ -0,0 +1,29 @@ +! -*- bgp -*- +! +! BGPd sample configuratin file +! +! $Id: bgpd.conf.sample,v 1.19 1999/02/19 17:17:27 developer Exp $ +! +hostname bgpd +password zebra +!enable password please-set-at-here +! +!bgp mulitple-instance +! +router bgp 7675 +! bgp router-id 10.0.0.1 +! network 10.0.0.0/8 +! neighbor 10.0.0.2 remote-as 7675 +! neighbor 10.0.0.2 route-map set-nexthop out +! neighbor 10.0.0.2 ebgp-multihop +! neighbor 10.0.0.2 next-hop-self +! +! access-list all permit any +! +!route-map set-nexthop permit 10 +! match ip address all +! set ip next-hop 10.0.0.1 +! +!log file bgpd.log +! +log stdout diff --git a/bgpd/bgpd.conf.sample2 b/bgpd/bgpd.conf.sample2 new file mode 100644 index 0000000..d376ad2 --- /dev/null +++ b/bgpd/bgpd.conf.sample2 @@ -0,0 +1,77 @@ +! +! Zebra configuration saved from vty +! 2002/07/01 03:16:33 +! +hostname bgpd +password zebra +log file bgpd.log +log stdout +! +router bgp 7675 + no bgp default ipv4-unicast + neighbor 3ffe:506:1000::2 remote-as 7675 + neighbor fe80::200:c0ff:fe30:9be3 remote-as 9377 + neighbor fe80::200:c0ff:fe30:9be3 interface sit3 + neighbor fe80::210:5aff:fe6b:3cee remote-as 7675 + neighbor fe80::210:5aff:fe6b:3cee interface eth0 + neighbor fe80::290:27ff:fe51:84c7 remote-as 4691 + neighbor fe80::290:27ff:fe51:84c7 description DTI + neighbor fe80::290:27ff:fe51:84c7 interface sit7 + neighbor fe80::2a0:c9ff:fec8:82ec remote-as 7530 + neighbor fe80::2a0:c9ff:fec8:82ec description IRI + neighbor fe80::2a0:c9ff:fec8:82ec interface sit8 + neighbor fe80::2e0:18ff:fe98:2725 remote-as 2500 + neighbor fe80::2e0:18ff:fe98:2725 description WIDE + neighbor fe80::2e0:18ff:fe98:2725 interface sit5 + neighbor fe80::2e0:18ff:fea8:bf5 remote-as 65000 + neighbor fe80::2e0:18ff:fea8:bf5 interface sit6 +! + address-family ipv6 + network 3ffe:506::/33 + network 3ffe:1800:e800::/40 + aggregate-address 3ffe:506::/32 + redistribute connected + neighbor 3ffe:506:1000::2 activate + neighbor fe80::200:c0ff:fe30:9be3 activate + neighbor fe80::200:c0ff:fe30:9be3 route-map set-nexthop out + neighbor fe80::210:5aff:fe6b:3cee activate + neighbor fe80::290:27ff:fe51:84c7 activate + neighbor fe80::290:27ff:fe51:84c7 route-map set-nexthop out + neighbor fe80::2a0:c9ff:fec8:82ec activate + neighbor fe80::2a0:c9ff:fec8:82ec route-map set-nexthop out + neighbor fe80::2e0:18ff:fe98:2725 activate + neighbor fe80::2e0:18ff:fe98:2725 distribute-list nla1 out + neighbor fe80::2e0:18ff:fe98:2725 route-map set-nexthop out + neighbor fe80::2e0:18ff:fea8:bf5 activate + neighbor fe80::2e0:18ff:fea8:bf5 route-map set-nexthop out + exit-address-family +! +ipv6 access-list all permit any +ipv6 access-list nla1 deny 3ffe:506::/33 +ipv6 access-list nla1 permit 3ffe:506::/32 +ipv6 access-list nla1 deny any +ipv6 access-list ntt-nla1 permit 3ffe:1800:0:ffff::c/127 +ipv6 access-list ntt-nla1 deny 3ffe:1800:e800::/41 +ipv6 access-list ntt-nla1 permit 3ffe:1800:e800::/40 +ipv6 access-list ntt-nla1 deny any +! +ipv6 prefix-list 6bone-filter seq 5 permit 3ffe::/17 ge 24 le 24 +ipv6 prefix-list 6bone-filter seq 10 permit 3ffe:8000::/17 ge 28 le 28 +ipv6 prefix-list 6bone-filter seq 12 deny 3ffe::/16 +ipv6 prefix-list 6bone-filter seq 15 permit 2000::/3 ge 16 le 16 +ipv6 prefix-list 6bone-filter seq 20 permit 2001::/16 ge 35 le 35 +! +route-map set-nexthop permit 10 + match ipv6 address all + set ipv6 next-hop global 3ffe:506::1 + set ipv6 next-hop local fe80::cbb5:591a + set ip next-hop 203.181.89.26 + set community 7675:0 +! +route-map set-link-local permit 10 + match ipv6 address all + set ipv6 next-hop local fe80::cbb5:591a + set ipv6 next-hop global 3ffe:1800:0:ffff::d +! +line vty +! diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h new file mode 100644 index 0000000..8d09bfb --- /dev/null +++ b/bgpd/bgpd.h @@ -0,0 +1,915 @@ +/* BGP message definition header. + Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* For union sockunion. */ +#include "sockunion.h" + +/* ZEBRA BGPd Version */ +#define ZEBRA_BGPD_VERSION "0.95 build 26" + +/* Typedef BGP specific types. */ +typedef u_int16_t as_t; +typedef u_int16_t bgp_size_t; + +/* BGP master for system wide configurations and variables. */ +struct bgp_master +{ + /* BGP instance list. */ + struct list *bgp; + + /* BGP thread master. */ + struct thread_master *master; + + /* BGP port number. */ + u_int16_t port; + + /* BGP start time. */ + time_t start_time; + + /* Various BGP global configuration. */ + u_char options; +#define BGP_OPT_NO_FIB (1 << 0) +#define BGP_OPT_MULTIPLE_INSTANCE (1 << 1) +#define BGP_OPT_CONFIG_CISCO (1 << 2) + +#ifdef HAVE_TCP_SIGNATURE + /* bgp receive socket */ + int sock; +#endif /* HAVE_TCP_SIGNATURE */ +}; + +/* BGP instance structure. */ +struct bgp +{ + /* AS number of this BGP instance. */ + as_t as; + + /* Name of this BGP instance. */ + char *name; + + /* Self peer. */ + struct peer *peer_self; + + /* BGP peer. */ + struct list *peer; + + /* BGP peer group. */ + struct list *group; + + /* BGP configuration. */ + u_int16_t config; +#define BGP_CONFIG_ROUTER_ID (1 << 0) +#define BGP_CONFIG_CLUSTER_ID (1 << 1) +#define BGP_CONFIG_CONFEDERATION (1 << 2) + + /* BGP router identifier. */ + struct in_addr router_id; + + /* BGP route reflector cluster ID. */ + struct in_addr cluster_id; + + /* BGP confederation information. */ + as_t confed_id; + as_t *confed_peers; + int confed_peers_cnt; + + /* BGP flags. */ + u_int16_t flags; +#define BGP_FLAG_ALWAYS_COMPARE_MED (1 << 0) +#define BGP_FLAG_DETERMINISTIC_MED (1 << 1) +#define BGP_FLAG_MED_MISSING_AS_WORST (1 << 2) +#define BGP_FLAG_MED_CONFED (1 << 3) +#define BGP_FLAG_NO_DEFAULT_IPV4 (1 << 4) +#define BGP_FLAG_NO_CLIENT_TO_CLIENT (1 << 5) +#define BGP_FLAG_NO_ENFORCE_FIRST_AS (1 << 6) +#define BGP_FLAG_COMPARE_ROUTER_ID (1 << 7) +#define BGP_FLAG_ASPATH_IGNORE (1 << 8) +#define BGP_FLAG_IMPORT_CHECK (1 << 9) +#define BGP_FLAG_NO_FAST_EXT_FAILOVER (1 << 10) +#define BGP_FLAG_LOG_NEIGHBOR_CHANGES (1 << 11) +#define BGP_FLAG_GRACEFUL_RESTART (1 << 12) +#define BGP_FLAG_COST_COMMUNITY_IGNORE (1 << 13) + + /* BGP Per AF flags */ + u_int16_t af_flags[AFI_MAX][SAFI_MAX]; +#define BGP_CONFIG_DAMPENING (1 << 0) + + /* Static route configuration. */ + struct bgp_table *route[AFI_MAX][SAFI_MAX]; + + /* Aggregate address configuration. */ + struct bgp_table *aggregate[AFI_MAX][SAFI_MAX]; + + /* BGP routing information base. */ + struct bgp_table *rib[AFI_MAX][SAFI_MAX]; + + /* BGP redistribute configuration. */ + u_char redist[AFI_MAX][ZEBRA_ROUTE_MAX]; + + /* BGP redistribute metric configuration. */ + u_char redist_metric_flag[AFI_MAX][ZEBRA_ROUTE_MAX]; + u_int32_t redist_metric[AFI_MAX][ZEBRA_ROUTE_MAX]; + + /* BGP redistribute route-map. */ + struct + { + char *name; + struct route_map *map; + } rmap[AFI_MAX][ZEBRA_ROUTE_MAX]; + + /* BGP distance configuration. */ + u_char distance_ebgp; + u_char distance_ibgp; + u_char distance_local; + + /* BGP default local-preference. */ + u_int32_t default_local_pref; + + /* BGP default timer. */ + u_int32_t default_holdtime; + u_int32_t default_keepalive; + + /* BGP graceful restart */ + u_int32_t restart_time; + u_int32_t stalepath_time; +}; + +/* BGP peer-group support. */ +struct peer_group +{ + /* Name of the peer-group. */ + char *name; + + /* Pointer to BGP. */ + struct bgp *bgp; + + /* Peer-group client list. */ + struct list *peer; + + /* Peer-group config */ + struct peer *conf; +}; + +/* BGP Notify message format. */ +struct bgp_notify +{ + u_char code; + u_char subcode; + char *data; + bgp_size_t length; +}; + +/* Next hop self address. */ +struct bgp_nexthop +{ + struct interface *ifp; + struct in_addr v4; +#ifdef HAVE_IPV6 + struct in6_addr v6_global; + struct in6_addr v6_local; +#endif /* HAVE_IPV6 */ +}; + +/* BGP router distinguisher value. */ +#define BGP_RD_SIZE 8 + +struct bgp_rd +{ + u_char val[BGP_RD_SIZE]; +}; + +/* BGP filter structure. */ +struct bgp_filter +{ + /* Distribute-list. */ + struct + { + char *name; + struct access_list *alist; + } dlist[FILTER_MAX]; + + /* Prefix-list. */ + struct + { + char *name; + struct prefix_list *plist; + } plist[FILTER_MAX]; + + /* Filter-list. */ + struct + { + char *name; + struct as_list *aslist; + } aslist[FILTER_MAX]; + + /* Route-map. */ + struct + { + char *name; + struct route_map *map; + } map[FILTER_MAX]; + + /* Unsuppress-map. */ + struct + { + char *name; + struct route_map *map; + } usmap; +}; + +/* BGP neighbor structure. */ +struct peer +{ + /* BGP structure. */ + struct bgp *bgp; + + /* BGP peer group. */ + struct peer_group *group; + + /* Peer's remote AS number. */ + as_t as; + + /* Peer's local AS number. */ + as_t local_as; + + /* Peer's Change local AS number. */ + as_t change_local_as; + + /* Remote router ID. */ + struct in_addr remote_id; + + /* Local router ID. */ + struct in_addr local_id; + + /* Packet receive and send buffer. */ + struct stream *ibuf; + struct stream_fifo *obuf; + struct stream *work; + + /* Status of the peer. */ + int status; + int ostatus; + + /* Peer information */ + int fd; /* File descriptor */ + int ttl; /* TTL of TCP connection to the peer. */ + char *desc; /* Description of the peer. */ + unsigned short port; /* Destination port for peer */ + char *host; /* Printable address of the peer. */ + union sockunion su; /* Sockunion address of the peer. */ + time_t uptime; /* Last Up/Down time */ + time_t readtime; /* Last read time */ + time_t resettime; /* Last reset time */ + + unsigned int ifindex; /* ifindex of the BGP connection. */ + char *ifname; /* bind interface name. */ + char *update_if; + union sockunion *update_source; + struct zlog *log; + + union sockunion *su_local; /* Sockunion of local address. */ + union sockunion *su_remote; /* Sockunion of remote address. */ + int shared_network; /* Is this peer shared same network. */ + struct bgp_nexthop nexthop; /* Nexthop */ + + /* Peer address family configuration. */ + u_char afc[AFI_MAX][SAFI_MAX]; + u_char afc_nego[AFI_MAX][SAFI_MAX]; + u_char afc_adv[AFI_MAX][SAFI_MAX]; + u_char afc_recv[AFI_MAX][SAFI_MAX]; + + /* Capability flags (reset in bgp_stop) */ + u_char cap; +#define PEER_CAP_REFRESH_ADV (1 << 0) /* refresh advertised */ +#define PEER_CAP_REFRESH_OLD_RCV (1 << 1) /* refresh old received */ +#define PEER_CAP_REFRESH_NEW_RCV (1 << 2) /* refresh rfc received */ +#define PEER_CAP_DYNAMIC_ADV (1 << 3) /* dynamic advertised */ +#define PEER_CAP_DYNAMIC_RCV (1 << 4) /* dynamic received */ +#define PEER_CAP_RESTART_ADV (1 << 5) /* restart advertised */ +#define PEER_CAP_RESTART_RCV (1 << 6) /* restart received */ + + /* Capability flags (reset in bgp_stop) */ + u_int16_t af_cap[AFI_MAX][SAFI_MAX]; +#define PEER_CAP_ORF_PREFIX_SM_ADV (1 << 0) /* send-mode advertised */ +#define PEER_CAP_ORF_PREFIX_RM_ADV (1 << 1) /* receive-mode advertised */ +#define PEER_CAP_ORF_PREFIX_SM_RCV (1 << 2) /* send-mode received */ +#define PEER_CAP_ORF_PREFIX_RM_RCV (1 << 3) /* receive-mode received */ +#define PEER_CAP_ORF_PREFIX_SM_OLD_RCV (1 << 4) /* send-mode received */ +#define PEER_CAP_ORF_PREFIX_RM_OLD_RCV (1 << 5) /* receive-mode received */ +#define PEER_CAP_RESTART_AF_RCV (1 << 6) /* graceful restart afi/safi received */ +#define PEER_CAP_RESTART_AF_PRESERVE_RCV (1 << 7) /* graceful restart afi/safi F-bit received */ + + /* Global configuration flags. */ + u_int32_t flags; +#define PEER_FLAG_CONNECT_MODE_PASSIVE (1 << 0) /* tranport connection-mode passive */ +#define PEER_FLAG_CONNECT_MODE_ACTIVE (1 << 1) /* tranport connection-mode active */ +#define PEER_FLAG_SHUTDOWN (1 << 2) /* shutdown */ +#define PEER_FLAG_DONT_CAPABILITY (1 << 3) /* dont-capability */ +#define PEER_FLAG_OVERRIDE_CAPABILITY (1 << 4) /* override-capability */ +#define PEER_FLAG_STRICT_CAP_MATCH (1 << 5) /* strict-match */ +#define PEER_FLAG_DYNAMIC_CAPABILITY (1 << 6) /* dynamic capability */ +#define PEER_FLAG_DISABLE_CONNECTED_CHECK (1 << 7) /* disable-connected-check */ +#define PEER_FLAG_LOCAL_AS_NO_PREPEND (1 << 8) /* local-as no-prepend */ +#define PEER_FLAG_PASSWORD (1 << 9) /* password */ + + /* NSF mode (graceful restart) */ + u_char nsf[AFI_MAX][SAFI_MAX]; + + /* Per AF configuration flags. */ + u_int32_t af_flags[AFI_MAX][SAFI_MAX]; +#define PEER_FLAG_SEND_COMMUNITY (1 << 0) /* send-community */ +#define PEER_FLAG_SEND_EXT_COMMUNITY (1 << 1) /* send-community ext. */ +#define PEER_FLAG_NEXTHOP_SELF (1 << 2) /* next-hop-self */ +#define PEER_FLAG_REFLECTOR_CLIENT (1 << 3) /* reflector-client */ +#define PEER_FLAG_RSERVER_CLIENT (1 << 4) /* route-server-client */ +#define PEER_FLAG_SOFT_RECONFIG (1 << 5) /* soft-reconfiguration */ +#define PEER_FLAG_AS_PATH_UNCHANGED (1 << 6) /* transparent-as */ +#define PEER_FLAG_NEXTHOP_UNCHANGED (1 << 7) /* transparent-next-hop */ +#define PEER_FLAG_MED_UNCHANGED (1 << 8) /* transparent-next-hop */ +#define PEER_FLAG_DEFAULT_ORIGINATE (1 << 9) /* default-originate */ +#define PEER_FLAG_REMOVE_PRIVATE_AS (1 << 10) /* remove-private-as */ +#define PEER_FLAG_ALLOWAS_IN (1 << 11) /* set allowas-in */ +#define PEER_FLAG_ORF_PREFIX_SM (1 << 12) /* orf capability send-mode */ +#define PEER_FLAG_ORF_PREFIX_RM (1 << 13) /* orf capability receive-mode */ +#define PEER_FLAG_MAX_PREFIX (1 << 14) /* maximum prefix */ +#define PEER_FLAG_MAX_PREFIX_WARNING (1 << 15) /* maximum prefix warning-only */ + + /* address family configuration */ + u_int32_t af_config[AFI_MAX][SAFI_MAX]; +#define PEER_AF_CONFIG_WEIGHT (1 << 0) /* Default weight. */ + u_int16_t weight[AFI_MAX][SAFI_MAX]; + + /* password for TCP signature */ + char *password; + + /* default-originate route-map. */ + struct + { + char *name; + struct route_map *map; + } default_rmap[AFI_MAX][SAFI_MAX]; + + /* Peer status flags. */ + u_int16_t sflags; +#define PEER_STATUS_ACCEPT_PEER (1 << 0) /* accept peer */ +#define PEER_STATUS_PREFIX_OVERFLOW (1 << 1) /* prefix-overflow */ +#define PEER_STATUS_CAPABILITY_OPEN (1 << 2) /* capability open send */ +#define PEER_STATUS_HAVE_ACCEPT (1 << 3) /* accept peer's parent */ +#define PEER_STATUS_GROUP (1 << 4) /* peer-group conf */ +#define PEER_STATUS_CREATE_INIT (1 << 5) /* peer create init */ +#define PEER_STATUS_NSF_MODE (1 << 6) /* NSF aware peer */ +#define PEER_STATUS_NSF_WAIT (1 << 7) /* wait comeback peer */ + + /* Peer status af flags (reset in bgp_stop) */ + u_int16_t af_sflags[AFI_MAX][SAFI_MAX]; +#define PEER_STATUS_ORF_PREFIX_SEND (1 << 0) /* prefix-list send peer */ +#define PEER_STATUS_ORF_WAIT_REFRESH (1 << 1) /* wait refresh received peer */ +#define PEER_STATUS_DEFAULT_ORIGINATE (1 << 2) /* default-originate peer */ +#define PEER_STATUS_PREFIX_THRESHOLD (1 << 3) /* exceed prefix-threshold */ +#define PEER_STATUS_PREFIX_LIMIT (1 << 4) /* exceed prefix-limit */ +#define PEER_STATUS_EOR_SEND (1 << 5) /* end-of-rib send to peer */ +#define PEER_STATUS_EOR_RECEIVED (1 << 6) /* end-of-rib received from peer */ + + /* Default attribute value for the peer. */ + u_int32_t config; +#define PEER_CONFIG_TIMER (1 << 1) /* keepalive & holdtime */ +#define PEER_CONFIG_ROUTEADV (1 << 2) /* route advertise */ + u_int32_t holdtime; + u_int32_t keepalive; + u_int32_t routeadv; + + /* Timer values. */ + u_int32_t v_start; + u_int32_t v_connect; + u_int32_t v_holdtime; + u_int32_t v_keepalive; + u_int32_t v_asorig; + u_int32_t v_routeadv; + u_int32_t v_pmax_restart; + u_int32_t v_active_delay; + u_int32_t v_gr_restart; + + /* Threads. */ + struct thread *t_read; + struct thread *t_write; + struct thread *t_start; + struct thread *t_connect; + struct thread *t_holdtime; + struct thread *t_keepalive; + struct thread *t_asorig; + struct thread *t_routeadv[AFI_MAX][SAFI_MAX]; + struct thread *t_pmax_restart; + struct thread *t_gr_restart; + struct thread *t_gr_stale; + + /* Statistics field */ + u_int32_t open_in; /* Open message input count */ + u_int32_t open_out; /* Open message output count */ + u_int32_t update_in; /* Update message input count */ + u_int32_t update_out; /* Update message ouput count */ + time_t update_time; /* Update message received time. */ + u_int32_t keepalive_in; /* Keepalive input count */ + u_int32_t keepalive_out; /* Keepalive output count */ + u_int32_t notify_in; /* Notify input count */ + u_int32_t notify_out; /* Notify output count */ + u_int32_t refresh_in; /* Route Refresh input count */ + u_int32_t refresh_out; /* Route Refresh output count */ + u_int32_t dynamic_cap_in; /* Dynamic Capability input count. */ + u_int32_t dynamic_cap_out; /* Dynamic Capability output count. */ + + /* BGP state count */ + u_int32_t established; /* Established */ + u_int32_t dropped; /* Dropped */ + + /* Syncronization list and time. */ + struct bgp_synchronize *sync[AFI_MAX][SAFI_MAX]; + time_t synctime[AFI_MAX][SAFI_MAX]; + + /* Send prefix count. */ + unsigned long scount[AFI_MAX][SAFI_MAX]; + + /* Announcement attribute hash. */ + struct hash *hash[AFI_MAX][SAFI_MAX]; + + /* Notify data. */ + struct bgp_notify notify; + + /* Whole packet size to be read. */ + unsigned long packet_size; + + /* Filter structure. */ + struct bgp_filter filter[AFI_MAX][SAFI_MAX]; + + /* ORF Prefix-list */ + struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX]; + + /* Prefix count. */ + unsigned long pcount[AFI_MAX][SAFI_MAX]; + + /* Max prefix count. */ + unsigned long pmax[AFI_MAX][SAFI_MAX]; + u_char pmax_threshold[AFI_MAX][SAFI_MAX]; + u_int16_t pmax_restart[AFI_MAX][SAFI_MAX]; +#define MAXIMUM_PREFIX_THRESHOLD_DEFAULT 75 + + /* allowas-in. */ + char allowas_in[AFI_MAX][SAFI_MAX]; + + /* peer reset cause */ + char last_reset; +#define PEER_DOWN_RID_CHANGE 1 /* bgp router-id command */ +#define PEER_DOWN_REMOTE_AS_CHANGE 2 /* neighbor remote-as command */ +#define PEER_DOWN_LOCAL_AS_CHANGE 3 /* neighbor local-as command */ +#define PEER_DOWN_CLID_CHANGE 4 /* bgp cluster-id command */ +#define PEER_DOWN_CONFED_ID_CHANGE 5 /* bgp confederation identifier command */ +#define PEER_DOWN_CONFED_PEER_CHANGE 6 /* bgp confederation peer command */ +#define PEER_DOWN_RR_CLIENT_CHANGE 7 /* neighbor route-reflector-client command */ +#define PEER_DOWN_RS_CLIENT_CHANGE 8 /* neighbor route-server-client command */ +#define PEER_DOWN_UPDATE_SOURCE_CHANGE 9 /* neighbor update-source command */ +#define PEER_DOWN_AF_ACTIVATE 10 /* neighbor activate command */ +#define PEER_DOWN_USER_SHUTDOWN 11 /* neighbor shutdown command */ +#define PEER_DOWN_USER_RESET 12 /* clear ip bgp command */ +#define PEER_DOWN_NOTIFY_RECEIVED 13 /* notification received */ +#define PEER_DOWN_NOTIFY_SEND 14 /* notification send */ +#define PEER_DOWN_CLOSE_SESSION 15 /* tcp session close */ +#define PEER_DOWN_NEIGHBOR_DELETE 16 /* neghbor delete */ +#define PEER_DOWN_RMAP_BIND 17 /* neghbor peer-group command */ +#define PEER_DOWN_RMAP_UNBIND 18 /* no neighbor peer-group command */ +#define PEER_DOWN_CAPABILITY_CHANGE 19 /* neighbor capability command */ +#define PEER_DOWN_MULTIHOP_CHANGE 20 /* neighbor multihop command */ +#define PEER_DOWN_PASSWORD_CHANGE 21 /* neighbor password command */ +#define PEER_DOWN_NSF_CLOSE_SESSION 22 /* NSF tcp session close */ + + /* The kind of route-map Flags.*/ + u_char rmap_type; +#define PEER_RMAP_TYPE_IN (1 << 0) /* neighbor route-map in */ +#define PEER_RMAP_TYPE_OUT (1 << 1) /* neighbor route-map out */ +#define PEER_RMAP_TYPE_NETWORK (1 << 2) /* network route-map */ +#define PEER_RMAP_TYPE_REDISTRIBUTE (1 << 3) /* redistribute route-map */ +#define PEER_RMAP_TYPE_DEFAULT (1 << 4) /* default-originate route-map */ +#define PEER_RMAP_TYPE_NOSET (1 << 5) /* not allow to set commands */ + +#ifdef HAVE_OPENBSD_TCP_SIGNATURE + u_int32_t spi_in; + u_int32_t spi_out; +#endif /* HAVE_OPENBSD_TCP_SIGNATURE */ +}; + +/* This structure's member directly points incoming packet data + stream. */ +struct bgp_nlri +{ + /* AFI. */ + afi_t afi; + + /* SAFI. */ + safi_t safi; + + /* Pointer to NLRI byte stream. */ + u_char *nlri; + + /* Length of whole NLRI. */ + bgp_size_t length; +}; + +/* BGP versions. */ +#define BGP_VERSION_4 4 + +/* Default BGP port number. */ +#define BGP_PORT_DEFAULT 179 + +/* BGP message header and packet size. */ +#define BGP_MARKER_SIZE 16 +#define BGP_HEADER_SIZE 19 +#define BGP_MAX_PACKET_SIZE 4096 + +/* BGP minimum message size. */ +#define BGP_MSG_OPEN_MIN_SIZE (BGP_HEADER_SIZE + 10) +#define BGP_MSG_UPDATE_MIN_SIZE (BGP_HEADER_SIZE + 4) +#define BGP_MSG_NOTIFY_MIN_SIZE (BGP_HEADER_SIZE + 2) +#define BGP_MSG_KEEPALIVE_MIN_SIZE (BGP_HEADER_SIZE + 0) +#define BGP_MSG_ROUTE_REFRESH_MIN_SIZE (BGP_HEADER_SIZE + 4) +#define BGP_MSG_CAPABILITY_MIN_SIZE (BGP_HEADER_SIZE + 3) + +/* BGP message types. */ +#define BGP_MSG_OPEN 1 +#define BGP_MSG_UPDATE 2 +#define BGP_MSG_NOTIFY 3 +#define BGP_MSG_KEEPALIVE 4 +#define BGP_MSG_ROUTE_REFRESH_NEW 5 +#define BGP_MSG_CAPABILITY 6 +#define BGP_MSG_ROUTE_REFRESH_OLD 128 + +/* BGP open optional parameter. */ +#define BGP_OPEN_OPT_AUTH 1 +#define BGP_OPEN_OPT_CAP 2 + +/* BGP4 attribute type codes. */ +#define BGP_ATTR_ORIGIN 1 +#define BGP_ATTR_AS_PATH 2 +#define BGP_ATTR_NEXT_HOP 3 +#define BGP_ATTR_MULTI_EXIT_DISC 4 +#define BGP_ATTR_LOCAL_PREF 5 +#define BGP_ATTR_ATOMIC_AGGREGATE 6 +#define BGP_ATTR_AGGREGATOR 7 +#define BGP_ATTR_COMMUNITIES 8 +#define BGP_ATTR_ORIGINATOR_ID 9 +#define BGP_ATTR_CLUSTER_LIST 10 +#define BGP_ATTR_DPA 11 +#define BGP_ATTR_ADVERTISER 12 +#define BGP_ATTR_RCID_PATH 13 +#define BGP_ATTR_MP_REACH_NLRI 14 +#define BGP_ATTR_MP_UNREACH_NLRI 15 +#define BGP_ATTR_EXT_COMMUNITIES 16 +#define BGP_ATTR_NEW_ASPATH 17 +#define BGP_ATTR_NEW_AGGREGATOR 18 + +/* BGP update origin. */ +#define BGP_ORIGIN_IGP 0 +#define BGP_ORIGIN_EGP 1 +#define BGP_ORIGIN_INCOMPLETE 2 + +/* BGP notify message codes. */ +#define BGP_NOTIFY_HEADER_ERR 1 +#define BGP_NOTIFY_OPEN_ERR 2 +#define BGP_NOTIFY_UPDATE_ERR 3 +#define BGP_NOTIFY_HOLD_ERR 4 +#define BGP_NOTIFY_FSM_ERR 5 +#define BGP_NOTIFY_CEASE 6 +#define BGP_NOTIFY_CAPABILITY_ERR 7 +#define BGP_NOTIFY_MAX 8 + +/* BGP_NOTIFY_HEADER_ERR sub codes. */ +#define BGP_NOTIFY_HEADER_NOT_SYNC 1 +#define BGP_NOTIFY_HEADER_BAD_MESLEN 2 +#define BGP_NOTIFY_HEADER_BAD_MESTYPE 3 +#define BGP_NOTIFY_HEADER_MAX 4 + +/* BGP_NOTIFY_OPEN_ERR sub codes. */ +#define BGP_NOTIFY_OPEN_UNSUP_VERSION 1 +#define BGP_NOTIFY_OPEN_BAD_PEER_AS 2 +#define BGP_NOTIFY_OPEN_BAD_BGP_IDENT 3 +#define BGP_NOTIFY_OPEN_UNSUP_PARAM 4 +#define BGP_NOTIFY_OPEN_AUTH_FAILURE 5 +#define BGP_NOTIFY_OPEN_UNACEP_HOLDTIME 6 +#define BGP_NOTIFY_OPEN_UNSUP_CAPBL 7 +#define BGP_NOTIFY_OPEN_MAX 8 + +/* BGP_NOTIFY_UPDATE_ERR sub codes. */ +#define BGP_NOTIFY_UPDATE_MAL_ATTR 1 +#define BGP_NOTIFY_UPDATE_UNREC_ATTR 2 +#define BGP_NOTIFY_UPDATE_MISS_ATTR 3 +#define BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR 4 +#define BGP_NOTIFY_UPDATE_ATTR_LENG_ERR 5 +#define BGP_NOTIFY_UPDATE_INVAL_ORIGIN 6 +#define BGP_NOTIFY_UPDATE_AS_ROUTE_LOOP 7 +#define BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP 8 +#define BGP_NOTIFY_UPDATE_OPT_ATTR_ERR 9 +#define BGP_NOTIFY_UPDATE_INVAL_NETWORK 10 +#define BGP_NOTIFY_UPDATE_MAL_AS_PATH 11 +#define BGP_NOTIFY_UPDATE_MAX 12 + +/* BGP_NOTIFY_CEASE sub codes (draft-ietf-idr-cease-subcode-05). */ +#define BGP_NOTIFY_CEASE_MAX_PREFIX 1 +#define BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN 2 +#define BGP_NOTIFY_CEASE_PEER_UNCONFIG 3 +#define BGP_NOTIFY_CEASE_ADMIN_RESET 4 +#define BGP_NOTIFY_CEASE_CONNECT_REJECT 5 +#define BGP_NOTIFY_CEASE_CONFIG_CHANGE 6 +#define BGP_NOTIFY_CEASE_CONNECT_COLLISION 7 +#define BGP_NOTIFY_CEASE_OUT_OF_RESOURCE 8 +#define BGP_NOTIFY_CEASE_MAX 9 + +/* BGP_NOTIFY_CAPABILITY_ERR sub codes (draft-ietf-idr-dynamic-cap-02). */ +#define BGP_NOTIFY_CAPABILITY_INVALID_ACTION 1 +#define BGP_NOTIFY_CAPABILITY_INVALID_LENGTH 2 +#define BGP_NOTIFY_CAPABILITY_MALFORMED_CODE 3 +#define BGP_NOTIFY_CAPABILITY_MAX 4 + +/* BGP finite state machine status. */ +#define Idle 1 +#define Connect 2 +#define Active 3 +#define OpenSent 4 +#define OpenConfirm 5 +#define Established 6 +#define BGP_STATUS_MAX 7 + +/* BGP finite state machine events. */ +#define BGP_Start 1 +#define BGP_Stop 2 +#define TCP_connection_open 3 +#define TCP_connection_closed 4 +#define TCP_connection_open_failed 5 +#define TCP_fatal_error 6 +#define ConnectRetry_timer_expired 7 +#define Hold_Timer_expired 8 +#define KeepAlive_timer_expired 9 +#define Receive_OPEN_message 10 +#define Receive_KEEPALIVE_message 11 +#define Receive_UPDATE_message 12 +#define Receive_NOTIFICATION_message 13 +#define BGP_EVENTS_MAX 14 + +/* BGP timers default value. */ +#define BGP_PEER_FIRST_CREATE_TIMER 20 +#define BGP_INIT_START_TIMER 0 +#define BGP_ACTIVE_DELAY_TIMER 5 +#define BGP_ERROR_START_TIMER 30 +#define BGP_DEFAULT_HOLDTIME 180 +#define BGP_DEFAULT_KEEPALIVE 60 +#define BGP_DEFAULT_ASORIGINATE 15 +#define BGP_DEFAULT_EBGP_ROUTEADV 30 +#define BGP_DEFAULT_IBGP_ROUTEADV 5 +#define BGP_CLEAR_CONNECT_RETRY 20 +#define BGP_DEFAULT_CONNECT_RETRY 120 + +/* BGP default local preference. */ +#define BGP_DEFAULT_LOCAL_PREF 100 + +/* BGP graceful restart */ +#define BGP_DEFAULT_RESTART_TIME 120 +#define BGP_DEFAULT_STALEPATH_TIME 360 + +/* SAFI which used in open capability negotiation. */ +#define BGP_SAFI_VPNV4 128 +#define BGP_SAFI_VPNV6 129 + +/* Max TTL value. */ +#define TTL_MAX 255 + +/* BGP uptime string length. */ +#define BGP_UPTIME_LEN 25 + +/* Default configuration settings for bgpd. */ +#define BGP_VTY_PORT 2605 +#define BGP_VTYSH_PATH "/tmp/.bgpd" +#define BGP_DEFAULT_CONFIG "bgpd.conf" + +/* Check AS path loop when we send NLRI. */ +/* #define BGP_SEND_ASPATH_CHECK */ + +/* IBGP/EBGP identifier. We also have a CONFED peer, which is to say, + a peer who's AS is part of our Confederation. */ +enum +{ + BGP_PEER_IBGP, + BGP_PEER_EBGP, + BGP_PEER_INTERNAL, + BGP_PEER_CONFED +}; + +/* Flag for peer_clear_soft(). */ +enum bgp_clear_type +{ + BGP_CLEAR_SOFT_NONE, + BGP_CLEAR_SOFT_OUT, + BGP_CLEAR_SOFT_IN, + BGP_CLEAR_SOFT_BOTH, + BGP_CLEAR_SOFT_IN_ORF_PREFIX +}; + +/* Macros. */ +#define BGP_INPUT(P) ((P)->ibuf) +#define BGP_INPUT_PNT(P) (STREAM_PNT(BGP_INPUT(P))) + +/* Macro to check BGP information is alive or not. */ +#define BGP_INFO_HOLDDOWN(BI) \ + (! CHECK_FLAG ((BI)->flags, BGP_INFO_VALID) \ + || CHECK_FLAG ((BI)->flags, BGP_INFO_HISTORY) \ + || CHECK_FLAG ((BI)->flags, BGP_INFO_DAMPED)) + +/* Count prefix size from mask length */ +#define PSIZE(a) (((a) + 7) / (8)) + +/* BGP error codes. */ +#define BGP_SUCCESS 0 +#define BGP_ERR_INVALID_VALUE -1 +#define BGP_ERR_INVALID_FLAG -2 +#define BGP_ERR_INVALID_AS -3 +#define BGP_ERR_INVALID_BGP -4 +#define BGP_ERR_PEER_GROUP_MEMBER -5 +#define BGP_ERR_MULTIPLE_INSTANCE_USED -6 +#define BGP_ERR_PEER_GROUP_MEMBER_EXISTS -7 +#define BGP_ERR_PEER_BELONGS_TO_GROUP -8 +#define BGP_ERR_PEER_GROUP_AF_UNCONFIGURED -9 +#define BGP_ERR_PEER_GROUP_NO_REMOTE_AS -10 +#define BGP_ERR_PEER_GROUP_CANT_CHANGE -11 +#define BGP_ERR_PEER_GROUP_MISMATCH -12 +#define BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT -13 +#define BGP_ERR_MULTIPLE_INSTANCE_NOT_SET -14 +#define BGP_ERR_AS_MISMATCH -15 +#define BGP_ERR_PEER_INACTIVE -16 +#define BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER -17 +#define BGP_ERR_PEER_GROUP_HAS_THE_FLAG -18 +#define BGP_ERR_PEER_FLAG_CONFLICT -19 +#define BGP_ERR_PEER_GROUP_SHUTDOWN -20 +#define BGP_ERR_PEER_FILTER_CONFLICT -21 +#define BGP_ERR_NOT_INTERNAL_PEER -22 +#define BGP_ERR_REMOVE_PRIVATE_AS -23 +#define BGP_ERR_AF_UNCONFIGURED -24 +#define BGP_ERR_SOFT_RECONFIG_UNCONFIGURED -25 +#define BGP_ERR_INSTANCE_MISMATCH -26 +#define BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP -27 +#define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS -28 +#define BGP_ERR_MAX -29 + +extern struct bgp_master *bm; + +extern struct thread_master *master; + +/* Prototypes. */ +void bgp_terminate (void); +void bgp_reset (void); +void bgp_zclient_reset (); +int bgp_nexthop_set (union sockunion *, union sockunion *, + struct bgp_nexthop *, struct peer *); +struct bgp *bgp_get_default (); +struct bgp *bgp_lookup (as_t, char *); +struct bgp *bgp_lookup_by_name (char *); +struct peer *peer_lookup (struct bgp *, union sockunion *); +struct peer_group *peer_group_lookup (struct bgp *, char *); +struct peer_group *peer_group_get (struct bgp *, char *); +struct peer *peer_lookup_with_open (union sockunion *, as_t, struct in_addr *, + int *); +int peer_sort (struct peer *peer); +int peer_active (struct peer *); +int peer_active_nego (struct peer *); +struct peer *peer_create_accept (struct bgp *); +char *peer_uptime (time_t, char *, size_t); +void bgp_config_write_family_header (struct vty *, afi_t, safi_t, int *); + +void bgp_master_init (); + +void bgp_init (); + +int bgp_option_set (int); +int bgp_option_unset (int); +int bgp_option_check (int); + +int bgp_get (struct bgp **, as_t *, char *); +int bgp_delete (struct bgp *); + +int bgp_flag_set (struct bgp *, int); +int bgp_flag_unset (struct bgp *, int); +int bgp_flag_check (struct bgp *, int); + +int bgp_router_id_set (struct bgp *, struct in_addr *); +int bgp_router_id_unset (struct bgp *); + +int bgp_cluster_id_set (struct bgp *, struct in_addr *); +int bgp_cluster_id_unset (struct bgp *); + +int bgp_confederation_id_set (struct bgp *, as_t); +int bgp_confederation_id_unset (struct bgp *); +int bgp_confederation_peers_check (struct bgp *, as_t); + +int bgp_confederation_peers_add (struct bgp *, as_t); +int bgp_confederation_peers_remove (struct bgp *, as_t); + +int bgp_timers_set (struct bgp *, u_int32_t, u_int32_t); +int bgp_timers_unset (struct bgp *); + +int bgp_default_local_preference_set (struct bgp *, u_int32_t); +int bgp_default_local_preference_unset (struct bgp *); + +int peer_remote_as (struct bgp *, union sockunion *, as_t *, afi_t, safi_t); +int peer_group_remote_as (struct bgp *, char *, as_t *); +int peer_delete (struct peer *peer); +int peer_group_delete (struct peer_group *); +int peer_group_remote_as_delete (struct peer_group *); + +int peer_activate (struct peer *, afi_t, safi_t); +int peer_deactivate (struct peer *, afi_t, safi_t); + +int peer_group_member (struct peer *); +int peer_group_bind (struct bgp *, union sockunion *, struct peer_group *, + afi_t, safi_t, as_t *); +int peer_group_unbind (struct bgp *, struct peer *, struct peer_group *, + afi_t, safi_t); + +int peer_flag_set (struct peer *, u_int32_t); +int peer_flag_unset (struct peer *, u_int32_t); + +int peer_af_flag_set (struct peer *, afi_t, safi_t, u_int32_t); +int peer_af_flag_unset (struct peer *, afi_t, safi_t, u_int32_t); +int peer_af_flag_check (struct peer *, afi_t, safi_t, u_int32_t); + +int peer_ebgp_multihop_set (struct peer *, int); +int peer_ebgp_multihop_unset (struct peer *); + +int peer_description_set (struct peer *, char *); +int peer_description_unset (struct peer *); + +int peer_update_source_if_set (struct peer *, char *); +int peer_update_source_addr_set (struct peer *, union sockunion *); +int peer_update_source_unset (struct peer *); + +int peer_default_originate_set (struct peer *, afi_t, safi_t, char *); +int peer_default_originate_unset (struct peer *, afi_t, safi_t); + +int peer_port_set (struct peer *, u_int16_t); +int peer_port_unset (struct peer *); + +int peer_weight_set (struct peer *, u_int16_t, afi_t, safi_t); +int peer_weight_unset (struct peer *, afi_t, safi_t); + +int peer_timers_set (struct peer *, u_int32_t, u_int32_t); +int peer_timers_unset (struct peer *); + +int peer_advertise_interval_set (struct peer *, u_int32_t); +int peer_advertise_interval_unset (struct peer *); + +int peer_interface_set (struct peer *, char *); +int peer_interface_unset (struct peer *); + +int peer_distribute_set (struct peer *, afi_t, safi_t, int, char *); +int peer_distribute_unset (struct peer *, afi_t, safi_t, int); + +int peer_allowas_in_set (struct peer *, afi_t, safi_t, int); +int peer_allowas_in_unset (struct peer *, afi_t, safi_t); + +int peer_local_as_set (struct peer *, as_t, int); +int peer_local_as_unset (struct peer *); + +int peer_prefix_list_set (struct peer *, afi_t, safi_t, int, char *); +int peer_prefix_list_unset (struct peer *, afi_t, safi_t, int); + +int peer_aslist_set (struct peer *, afi_t, safi_t, int, char *); +int peer_aslist_unset (struct peer *,afi_t, safi_t, int); + +int peer_route_map_set (struct peer *, afi_t, safi_t, int, char *); +int peer_route_map_unset (struct peer *, afi_t, safi_t, int); + +int peer_unsuppress_map_set (struct peer *, afi_t, safi_t, char *); +int peer_unsuppress_map_unset (struct peer *, afi_t, safi_t); + +int peer_maximum_prefix_set (struct peer *, afi_t, safi_t, u_int32_t, u_char, int, u_int16_t); +int peer_maximum_prefix_unset (struct peer *, afi_t, safi_t); + +#ifdef HAVE_TCP_SIGNATURE +int peer_password_set (struct peer *, char *); +int peer_password_unset (struct peer *); +#endif /* HAVE_TCP_SIGNATURE */ + +int peer_clear (struct peer *); +int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type); + +void peer_nsf_stop (struct peer *); diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..a7983e6 --- /dev/null +++ b/config.guess @@ -0,0 +1,1321 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 +# Free Software Foundation, Inc. + +version='2000-11-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner . +# Please send patches to . +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of this system. + +Operation modes: + -h, --help print this help, then exit + -V, --version print version number, then exit" + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case "$1" in + --version | --vers* | -V ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + exec >&2 + echo "$me: invalid option $1" + echo "$help" + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + + +dummy=dummy-$$ +trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15 + +# Use $HOST_CC if defined. $CC may point to a cross-compiler +if test x"$CC_FOR_BUILD" = x; then + if test x"$HOST_CC" != x; then + CC_FOR_BUILD="$HOST_CC" + else + if test x"$CC" != x; then + CC_FOR_BUILD="$CC" + else + echo 'int dummy(){}' >$dummy.c + for c in cc c89 gcc; do + ($c $dummy.c -c) >/dev/null 2>&1 + if test $? = 0; then + CC_FOR_BUILD="$c"; break + fi + done + rm -f $dummy.c $dummy.o + if test x"$CC_FOR_BUILD" = x; then + CC_FOR_BUILD=no_compiler_found + fi + fi + fi +fi + + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # Netbsd (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # Determine the machine/vendor (is the vendor relevant). + case "${UNAME_MACHINE}" in + amiga) machine=m68k-unknown ;; + arm32) machine=arm-unknown ;; + atari*) machine=m68k-atari ;; + sun3*) machine=m68k-sun ;; + mac68k) machine=m68k-apple ;; + macppc) machine=powerpc-apple ;; + hp3[0-9][05]) machine=m68k-hp ;; + ibmrt|romp-ibm) machine=romp-ibm ;; + *) machine=${UNAME_MACHINE}-unknown ;; + esac + # The Operating System including object format. + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + # The OS release + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <$dummy.s + .data +\$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main +main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + esac + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy \ + && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` + if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` + if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi + rm -f $dummy.c $dummy + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + hppa*:OpenBSD:*:*) + echo hppa-unknown-openbsd + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | i?86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i386-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + *:Linux:*:*) + + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + ld_supported_emulations=`cd /; ld --help 2>&1 \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + *ia64) + echo "${UNAME_MACHINE}-unknown-linux" + exit 0 + ;; + i?86linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 + ;; + elf_i?86) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + i?86coff) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 + ;; + sparclinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32_sparc) + echo "${UNAME_MACHINE}-unknown-linux-gnu" + exit 0 + ;; + armlinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32arm*) + echo "${UNAME_MACHINE}-unknown-linux-gnuoldld" + exit 0 + ;; + armelf_linux*) + echo "${UNAME_MACHINE}-unknown-linux-gnu" + exit 0 + ;; + m68klinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32ppc | elf32ppclinux) + # Determine Lib Version + cat >$dummy.c < +#if defined(__GLIBC__) +extern char __libc_version[]; +extern char __libc_release[]; +#endif +main(argc, argv) + int argc; + char *argv[]; +{ +#if defined(__GLIBC__) + printf("%s %s\n", __libc_version, __libc_release); +#else + printf("unkown\n"); +#endif + return 0; +} +EOF + LIBC="" + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null + if test "$?" = 0 ; then + ./$dummy | grep 1\.99 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f $dummy.c $dummy + echo powerpc-unknown-linux-gnu${LIBC} + exit 0 + ;; + shelf_linux) + echo "${UNAME_MACHINE}-unknown-linux-gnu" + exit 0 + ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + cat <$dummy.s + .data + \$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main + main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + LIBC="" + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + esac + + objdump --private-headers $dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >$dummy.c < /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __MIPSEB__ + printf ("%s-unknown-linux-gnu\n", argv[1]); +#endif +#ifdef __MIPSEL__ + printf ("%sel-unknown-linux-gnu\n", argv[1]); +#endif + return 0; +} +EOF + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + elif test "${UNAME_MACHINE}" = "s390"; then + echo s390-ibm-linux && exit 0 + elif test "${UNAME_MACHINE}" = "x86_64"; then + echo x86_64-unknown-linux-gnu && exit 0 + elif test "${UNAME_MACHINE}" = "parisc" -o "${UNAME_MACHINE}" = "hppa"; then + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) + echo hppa1.1-unknown-linux-gnu + ;; + PA8*) + echo hppa2.0-unknown-linux-gnu + ;; + *) + echo hppa-unknown-linux-gnu + ;; + esac + exit 0 + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + test -z "$ld_supported_emulations" \ + && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >$dummy.c < +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i?86:*:5:7*) + # Fixed at (any) Pentium or better + UNAME_MACHINE=i586 + if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then + echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + i?86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + echo `uname -p`-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + if test "${UNAME_MACHINE}" = "x86pc"; then + UNAME_MACHINE=pc + fi + echo `uname -p`-${UNAME_MACHINE}-nto-qnx + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-[KW]:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0 +rm -f $dummy.c $dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess version = $version + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "version='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..276fc59 --- /dev/null +++ b/config.h.in @@ -0,0 +1,360 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* BSDI */ +#undef BSDI_NRL + +/* Disable BGP installation to zebra */ +#undef DISABLE_BGP_ANNOUNCE + +/* FreeBSD 3.2 */ +#undef FREEBSD_32 + +/* GNU Linux */ +#undef GNU_LINUX + +/* Define to 1 if you have the header file. */ +#undef HAVE_ASM_TYPES_H + +/* Define to 1 if you have the `bcopy' function. */ +#undef HAVE_BCOPY + +/* Broken Alias */ +#undef HAVE_BROKEN_ALIASES + +/* Define to 1 if you have the `bzero' function. */ +#undef HAVE_BZERO + +/* Define to 1 if you have the `daemon' function. */ +#undef HAVE_DAEMON + +/* Define to 1 if you have the `getaddrinfo' function. */ +#undef HAVE_GETADDRINFO + +/* Define to 1 if you have the `getifaddrs' function. */ +#undef HAVE_GETIFADDRS + +/* GNU regexp library */ +#undef HAVE_GNU_REGEX + +/* ifaliasreq */ +#undef HAVE_IFALIASREQ + +/* Define to 1 if you have the `if_indextoname' function. */ +#undef HAVE_IF_INDEXTONAME + +/* Define to 1 if you have the `if_nametoindex' function. */ +#undef HAVE_IF_NAMETOINDEX + +/* in6addr global variables e.g. in6addr_loopback */ +#undef HAVE_IN6ADDR_GLOBAL + +/* in6_aliasreq */ +#undef HAVE_IN6_ALIASREQ + +/* Define to 1 if you have the `inet_aton' function. */ +#undef HAVE_INET_ATON + +/* Define to 1 if you have the header file. */ +#undef HAVE_INET_ND_H + +/* inet_ntop */ +#undef HAVE_INET_NTOP + +/* inet_pton */ +#undef HAVE_INET_PTON + +/* in_pktinfo */ +#undef HAVE_INPKTINFO + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* IPv6 */ +#undef HAVE_IPV6 + +/* IRDP */ +#undef HAVE_IRDP + +/* Define to 1 if you have the header file. */ +#undef HAVE_KVM_H + +/* Define to 1 if you have the `crypt' library (-lcrypt). */ +#undef HAVE_LIBCRYPT + +/* Define to 1 if you have the `kvm' library (-lkvm). */ +#undef HAVE_LIBKVM + +/* Define to 1 if you have the `m' library (-lm). */ +#undef HAVE_LIBM + +/* Define to 1 if you have the `ncurses' library (-lncurses). */ +#undef HAVE_LIBNCURSES + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define to 1 if you have the `readline' library (-lreadline). */ +#undef HAVE_LIBREADLINE + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#undef HAVE_LIBRESOLV + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define to 1 if you have the `termcap' library (-ltermcap). */ +#undef HAVE_LIBTERMCAP + +/* Define to 1 if you have the `tinfo' library (-ltinfo). */ +#undef HAVE_LIBTINFO + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBUTIL_H + +/* Define to 1 if you have the `xnet' library (-lxnet). */ +#undef HAVE_LIBXNET + +/* Linux TCP Signature Option */ +#undef HAVE_LINUX_TCP_SIGNATURE + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_VERSION_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET6_ND6_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_ICMP6_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN6_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN6_VAR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_VAR_H + +/* netlink */ +#undef HAVE_NETLINK + +/* NET-SNMP */ +#undef HAVE_NETSNMP + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_DL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_VAR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_NETOPT_H + +/* NET_RT_IFLIST */ +#undef HAVE_NET_RT_IFLIST + +/* OSPF NSSA */ +#undef HAVE_NSSA + +/* OSPF Opaque LSA */ +#undef HAVE_OPAQUE_LSA + +/* OpenBSD TCP Signature Option */ +#undef HAVE_OPENBSD_TCP_SIGNATURE + +/* OSPF TE */ +#undef HAVE_OSPF_TE + +/* /proc/net/dev */ +#undef HAVE_PROC_NET_DEV + +/* /proc/net/if_inet6 */ +#undef HAVE_PROC_NET_IF_INET6 + +/* rt_addrinfo */ +#undef HAVE_RT_ADDRINFO + +/* rusage */ +#undef HAVE_RUSAGE + +/* sa_len */ +#undef HAVE_SA_LEN + +/* Define to 1 if you have the `setproctitle' function. */ +#undef HAVE_SETPROCTITLE + +/* scope id */ +#undef HAVE_SIN6_SCOPE_ID + +/* sin_len */ +#undef HAVE_SIN_LEN + +/* SNMP */ +#undef HAVE_SNMP + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* sockaddr_dl */ +#undef HAVE_SOCKADDR_DL + +/* socklen_t */ +#undef HAVE_SOCKLEN_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strlcat' function. */ +#undef HAVE_STRLCAT + +/* Define to 1 if you have the `strlcpy' function. */ +#undef HAVE_STRLCPY + +/* Define to 1 if you have the header file. */ +#undef HAVE_STROPTS_H + +/* sun_len */ +#undef HAVE_SUN_LEN + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_CONF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_KSYM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIMES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* TCP Signature Option */ +#undef HAVE_TCP_SIGNATURE + +/* Use TCP for zebra communication */ +#undef HAVE_TCP_ZEBRA + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Inria IPv6 */ +#undef INRIA_IPV6 + +/* KAME IPv6 */ +#undef KAME + +/* Linux IPv6 */ +#undef LINUX_IPV6 + +/* NRL */ +#undef NRL + +/* OpenBSD */ +#undef OPEN_BSD + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* bgpd PID */ +#undef PATH_BGPD_PID + +/* ospf6d PID */ +#undef PATH_OSPF6D_PID + +/* ospfd PID */ +#undef PATH_OSPFD_PID + +/* ripd PID */ +#undef PATH_RIPD_PID + +/* ripngd PID */ +#undef PATH_RIPNGD_PID + +/* zebra PID */ +#undef PATH_ZEBRA_PID + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* SunOS 5 */ +#undef SUNOS_5 + +/* Use PAM for authentication */ +#undef USE_PAM + +/* Version number of package */ +#undef VERSION + +/* VTY shell */ +#undef VTYSH + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +/* Define to 1 if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..004c7de --- /dev/null +++ b/config.sub @@ -0,0 +1,1332 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 +# Free Software Foundation, Inc. + +version='2000-11-10' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -V, --version print version number, then exit" + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case "$1" in + --version | --vers* | -V ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + exec >&2 + echo "$me: invalid option $1" + echo "$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | storm-chaos*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | armv[2345] | armv[345][lb] | pyramid | mn10200 | mn10300 | tron | a29k \ + | 580 | i960 | h8300 \ + | x86 | ppcbe | mipsbe | mipsle | shbe | shle | armbe | armle \ + | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ + | hppa64 \ + | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \ + | alphaev6[78] \ + | we32k | ns16k | clipper | i370 | sh | sh[34] \ + | powerpc | powerpcle \ + | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \ + | mips64orion | mips64orionel | mipstx39 | mipstx39el \ + | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ + | mips64vr5000 | miprs64vr5000el | mcore \ + | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \ + | thumb | d10v | d30v | fr30 | avr) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65 | pj | pjl) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[234567]86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + # FIXME: clean up the formatting here. + vax-* | tahoe-* | i[234567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ + | xmp-* | ymp-* \ + | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* | armbe-* | armle-* \ + | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \ + | hppa2.0n-* | hppa64-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \ + | alphaev6[78]-* \ + | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ + | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ + | mipstx39-* | mipstx39el-* | mcore-* \ + | f301-* | armv*-* | s390-* | sv1-* | t3e-* \ + | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ + | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* \ + | bs2000-* | tic54x-* | c54x-* | x86_64-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[34567]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[34567]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[34567]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[34567]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + i386-go32 | go32) + basic_machine=i386-unknown + os=-go32 + ;; + i386-mingw32 | mingw32) + basic_machine=i386-unknown + os=-mingw32 + ;; + i[34567]86-pw32 | pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + msdos) + basic_machine=i386-unknown + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i686-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sparclite-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=t3e-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4) + basic_machine=sh-unknown + ;; + sparc | sparcv9) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + c4x*) + basic_machine=c4x-none + os=-coff + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* | -storm-chaos*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i[34567]86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto*) + os=-nto-qnx + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -*MiNT) + os=-mint + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -*MiNT) + vendor=atari + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "version='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 0000000..11a7bb4 --- /dev/null +++ b/configure @@ -0,0 +1,9771 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59. +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="lib/zebra.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO AMTAR install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM AWK SET_MAKE build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE CPP AR ac_ct_AR RANLIB ac_ct_RANLIB EGREP MULTIPATH_NUM LIBPAM RT_METHOD KERNEL_METHOD OTHER_METHOD RTREAD_METHOD IF_METHOD IF_PROC IPFORWARD LIB_IPV6 ZEBRA BGPD RIPD RIPNGD OSPFD OSPF6D VTYSH INCLUDES CURSES LIB_REGEX LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking Speeds up one-time builds + --enable-dependency-tracking Do not reject slow dependency extractors + --enable-vtysh, Make integrated VTY version of zebra + --disable-ipv6 turn off IPv6 related features and daemons + --disable-zebra do not build zebra daemon + --disable-bgpd do not build bgpd + --disable-ripd do not build ripd + --disable-ripngd do not build ripngd + --disable-ospfd do not build ospfd + --disable-ospf6d do not build ospf6d + --enable-irdp enable IRDP server support in zebra + --disable-bgp-announce, turn off BGP route announcement + --enable-netlink force to use Linux netlink interface + --enable-broken-aliases enable aliases as distinct interfaces for Linux 2.2.X + --enable-snmp enable SNMP support + --enable-tcp-zebra enable TCP/IP socket connection between zebra and protocol daemon + --enable-nssa enable OSPF NSSA option + --enable-opaque-lsa enable OSPF Opaque-LSA support (RFC2370) + --enable-ospf-te enable Traffic Engineering Extension to OSPF + --enable-multipath=ARG enable multipath function, ARG must be digit + --enable-tcp-signature enable TCP MD5 Signature Option (RFC2385) (for Linux and OpenBSD) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-cflags Set CFLAGS for use in compilation. + --with-linkbase Set local library base for use in compilation. + --with-libpam use libpam for PAM support in vtysh + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + +am__api_version="1.6" +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +test "$program_prefix" != NONE && + program_transform_name="s,^,$program_prefix,;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$,$program_suffix,;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm conftest.sed + + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$AWK" && break +done + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + # test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +# Define the identity of the package. + PACKAGE=zebra + VERSION=0.95 + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. + + + +# Add the stamp file to the list of files AC keeps track of, +# along with our hook. + ac_config_headers="$ac_config_headers config.h" + + + + +# Make sure we can run config.sub. +$ac_config_sub sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 +echo "$as_me: error: cannot run $ac_config_sub" >&2;} + { (exit 1); exit 1; }; } + +echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6 +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_build_alias=$build_alias +test -z "$ac_cv_build_alias" && + ac_cv_build_alias=`$ac_config_guess` +test -z "$ac_cv_build_alias" && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6 +build=$ac_cv_build +build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6 +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_host_alias=$host_alias +test -z "$ac_cv_host_alias" && + ac_cv_host_alias=$ac_cv_build_alias +ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6 +host=$ac_cv_host +host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + + + +# Check whether --with-cflags or --without-cflags was given. +if test "${with_cflags+set}" = set; then + withval="$with_cflags" + +fi; +if test "x$with_cflags" != "x" ; then + CFLAGS="$with_cflags" ; cflags_specified=yes ; +elif test -n "$CFLAGS" ; then + cflags_specified=yes ; +fi + + +# Check whether --with-linkbase or --without-linkbase was given. +if test "${with_linkbase+set}" = set; then + withval="$with_linkbase" + +fi; +if test "x$with_linkbase" != "x" ; then + linkbase_specified=yes ; +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +rm -f .deps 2>/dev/null +mkdir .deps 2>/dev/null +if test -d .deps; then + DEPDIR=.deps +else + # MS-DOS does not allow filenames that begin with a dot. + DEPDIR=_deps +fi +rmdir .deps 2>/dev/null + + + ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +doit: + @echo done +END +# If we don't find an include directive, just comment out the code. +echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | fgrep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6 +rm -f confinc confmf + +# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval="$enable_dependency_tracking" + +fi; +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + + +depcc="$CC" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + echo '#include "conftest.h"' > conftest.c + echo 'int i;' > conftest.h + echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=conftest.c object=conftest.o \ + depfile=conftest.Po tmpdepfile=conftest.TPo \ + $SHELL ./depcomp $depcc -c conftest.c -o conftest.o >/dev/null 2>&1 && + grep conftest.h conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + + +if test "x$cflags_specified" = "x" ; then + CFLAGS="$CFLAGS -Wall" +fi + +if test "$linkbase_specified" = "yes" ; then + CFLAGS="$CFLAGS -I${with_linkbase}/include" ; + LIBS="$LIBS -L${with_linkbase}/lib" ; +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + echo "$as_me:$LINENO: result: $AR" >&5 +echo "${ECHO_T}$AR" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + echo "$as_me:$LINENO: result: $ac_ct_AR" >&5 +echo "${ECHO_T}$ac_ct_AR" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + AR=$ac_ct_AR +else + AR="$ac_cv_prog_AR" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + + +echo "$as_me:$LINENO: checking for AIX" >&5 +echo $ECHO_N "checking for AIX... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef _AIX + yes +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "yes" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +cat >>confdefs.h <<\_ACEOF +#define _ALL_SOURCE 1 +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + + +# Check whether --enable-vtysh or --disable-vtysh was given. +if test "${enable_vtysh+set}" = set; then + enableval="$enable_vtysh" + +fi; +# Check whether --enable-ipv6 or --disable-ipv6 was given. +if test "${enable_ipv6+set}" = set; then + enableval="$enable_ipv6" + +fi; +# Check whether --enable-zebra or --disable-zebra was given. +if test "${enable_zebra+set}" = set; then + enableval="$enable_zebra" + +fi; +# Check whether --enable-bgpd or --disable-bgpd was given. +if test "${enable_bgpd+set}" = set; then + enableval="$enable_bgpd" + +fi; +# Check whether --enable-ripd or --disable-ripd was given. +if test "${enable_ripd+set}" = set; then + enableval="$enable_ripd" + +fi; +# Check whether --enable-ripngd or --disable-ripngd was given. +if test "${enable_ripngd+set}" = set; then + enableval="$enable_ripngd" + +fi; +# Check whether --enable-ospfd or --disable-ospfd was given. +if test "${enable_ospfd+set}" = set; then + enableval="$enable_ospfd" + +fi; +# Check whether --enable-ospf6d or --disable-ospf6d was given. +if test "${enable_ospf6d+set}" = set; then + enableval="$enable_ospf6d" + +fi; +# Check whether --enable-irdp or --disable-irdp was given. +if test "${enable_irdp+set}" = set; then + enableval="$enable_irdp" + +fi; +# Check whether --enable-bgp-announce or --disable-bgp-announce was given. +if test "${enable_bgp_announce+set}" = set; then + enableval="$enable_bgp_announce" + +fi; +# Check whether --enable-netlink or --disable-netlink was given. +if test "${enable_netlink+set}" = set; then + enableval="$enable_netlink" + +fi; +# Check whether --enable-broken-aliases or --disable-broken-aliases was given. +if test "${enable_broken_aliases+set}" = set; then + enableval="$enable_broken_aliases" + +fi; +# Check whether --enable-snmp or --disable-snmp was given. +if test "${enable_snmp+set}" = set; then + enableval="$enable_snmp" + +fi; + +# Check whether --with-libpam or --without-libpam was given. +if test "${with_libpam+set}" = set; then + withval="$with_libpam" + +fi; +# Check whether --enable-tcpsock or --disable-tcpsock was given. +if test "${enable_tcpsock+set}" = set; then + enableval="$enable_tcpsock" + +fi; +# Check whether --enable-nssa or --disable-nssa was given. +if test "${enable_nssa+set}" = set; then + enableval="$enable_nssa" + +fi; +# Check whether --enable-opaque-lsa or --disable-opaque-lsa was given. +if test "${enable_opaque_lsa+set}" = set; then + enableval="$enable_opaque_lsa" + +fi; +# Check whether --enable-ospf-te or --disable-ospf-te was given. +if test "${enable_ospf_te+set}" = set; then + enableval="$enable_ospf_te" + +fi; +# Check whether --enable-multipath or --disable-multipath was given. +if test "${enable_multipath+set}" = set; then + enableval="$enable_multipath" + +fi; +# Check whether --enable-tcp-signature or --disable-tcp-signature was given. +if test "${enable_tcp_signature+set}" = set; then + enableval="$enable_tcp_signature" + +fi; + +if test "${enable_broken_aliases}" = "yes"; then + if test "${enable_netlink}" = "yes" + then + echo "Sorry, you can't use netlink with broken aliases" + exit 1 + fi + +cat >>confdefs.h <<\_ACEOF +#define HAVE_BROKEN_ALIASES +_ACEOF + + enable_netlink=no +fi + +if test "${enable_tcp_zebra}" = "yes"; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_TCP_ZEBRA +_ACEOF + +fi + +if test "${enable_nssa}" = "yes"; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_NSSA +_ACEOF + +fi + +if test "${enable_irdp}" = "yes"; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_IRDP +_ACEOF + +fi + +if test "${enable_opaque_lsa}" = "yes"; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_OPAQUE_LSA +_ACEOF + +fi + +if test "${enable_ospf_te}" = "yes"; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_OPAQUE_LSA +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define HAVE_OSPF_TE +_ACEOF + +fi + + +MULTIPATH_NUM=1 + +case "${enable_multipath}" in + [0-9]|[1-9][0-9]) + MULTIPATH_NUM="${enable_multipath}" + ;; + "") + ;; + *) + echo "Please specify digit to --enable-multipath ARG." + exit 1 + ;; +esac + + + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + + + + + + + + + + + + + + + + + + + + + +for ac_header in string.h stropts.h sys/conf.h sys/ksym.h sys/time.h sys/times.h sys/select.h sys/sysctl.h sys/sockio.h sys/types.h net/if_dl.h net/if_var.h linux/version.h kvm.h netdb.h netinet/in.h net/netopt.h netinet/in_var.h netinet/in6_var.h netinet/in6.h inet/nd.h asm/types.h netinet/icmp6.h netinet6/nd6.h libutil.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +echo "$as_me:$LINENO: checking return type of signal handlers" >&5 +echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6 +if test "${ac_cv_type_signal+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#ifdef signal +# undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int +main () +{ +int i; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_signal=void +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_signal=int +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5 +echo "${ECHO_T}$ac_cv_type_signal" >&6 + +cat >>confdefs.h <<_ACEOF +#define RETSIGTYPE $ac_cv_type_signal +_ACEOF + + + +case "$host" in + *-sunos5.6* | *-solaris2.6*) + opsys=sol2-6 + +cat >>confdefs.h <<\_ACEOF +#define SUNOS_5 +_ACEOF + + +echo "$as_me:$LINENO: checking for main in -lxnet" >&5 +echo $ECHO_N "checking for main in -lxnet... $ECHO_C" >&6 +if test "${ac_cv_lib_xnet_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lxnet $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_xnet_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_xnet_main=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_xnet_main" >&5 +echo "${ECHO_T}$ac_cv_lib_xnet_main" >&6 +if test $ac_cv_lib_xnet_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBXNET 1 +_ACEOF + + LIBS="-lxnet $LIBS" + +fi + + CURSES=-lcurses + ;; + *-sunos5* | *-solaris2*) + +cat >>confdefs.h <<\_ACEOF +#define SUNOS_5 +_ACEOF + + +echo "$as_me:$LINENO: checking for main in -lsocket" >&5 +echo $ECHO_N "checking for main in -lsocket... $ECHO_C" >&6 +if test "${ac_cv_lib_socket_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_socket_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_socket_main=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_socket_main" >&5 +echo "${ECHO_T}$ac_cv_lib_socket_main" >&6 +if test $ac_cv_lib_socket_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for main in -lnsl" >&5 +echo $ECHO_N "checking for main in -lnsl... $ECHO_C" >&6 +if test "${ac_cv_lib_nsl_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_nsl_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_nsl_main=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_main" >&5 +echo "${ECHO_T}$ac_cv_lib_nsl_main" >&6 +if test $ac_cv_lib_nsl_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNSL 1 +_ACEOF + + LIBS="-lnsl $LIBS" + +fi + + CURSES=-lcurses + ;; + *-linux-*) + opsys=gnu-linux + +cat >>confdefs.h <<\_ACEOF +#define GNU_LINUX +_ACEOF + + ;; + *-nec-sysv4*) + +echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5 +echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6 +if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname (); +int +main () +{ +gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_nsl_gethostbyname=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_nsl_gethostbyname=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5 +echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6 +if test $ac_cv_lib_nsl_gethostbyname = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNSL 1 +_ACEOF + + LIBS="-lnsl $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for socket in -lsocket" >&5 +echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6 +if test "${ac_cv_lib_socket_socket+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char socket (); +int +main () +{ +socket (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_socket_socket=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_socket_socket=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5 +echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6 +if test $ac_cv_lib_socket_socket = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + + ;; + *-freebsd3.2) + +cat >>confdefs.h <<\_ACEOF +#define FREEBSD_32 +_ACEOF + + ;; + *-openbsd*) + opsys=openbsd + +cat >>confdefs.h <<\_ACEOF +#define OPEN_BSD +_ACEOF + + ;; + *-bsdi*) + opsys=bsdi + OTHER_METHOD="mtu_kvm.o" + +echo "$as_me:$LINENO: checking for main in -lkvm" >&5 +echo $ECHO_N "checking for main in -lkvm... $ECHO_C" >&6 +if test "${ac_cv_lib_kvm_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lkvm $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_kvm_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_kvm_main=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_kvm_main" >&5 +echo "${ECHO_T}$ac_cv_lib_kvm_main" >&6 +if test $ac_cv_lib_kvm_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBKVM 1 +_ACEOF + + LIBS="-lkvm $LIBS" + +fi + + ;; +esac + +case "${enable_vtysh}" in + "yes") + VTYSH="vtysh"; + +cat >>confdefs.h <<\_ACEOF +#define VTYSH +_ACEOF + + +echo "$as_me:$LINENO: checking for tputs in -ltinfo" >&5 +echo $ECHO_N "checking for tputs in -ltinfo... $ECHO_C" >&6 +if test "${ac_cv_lib_tinfo_tputs+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ltinfo $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char tputs (); +int +main () +{ +tputs (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_tinfo_tputs=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_tinfo_tputs=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_tinfo_tputs" >&5 +echo "${ECHO_T}$ac_cv_lib_tinfo_tputs" >&6 +if test $ac_cv_lib_tinfo_tputs = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBTINFO 1 +_ACEOF + + LIBS="-ltinfo $LIBS" + +else + +echo "$as_me:$LINENO: checking for tputs in -lncurses" >&5 +echo $ECHO_N "checking for tputs in -lncurses... $ECHO_C" >&6 +if test "${ac_cv_lib_ncurses_tputs+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lncurses $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char tputs (); +int +main () +{ +tputs (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_ncurses_tputs=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_ncurses_tputs=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_ncurses_tputs" >&5 +echo "${ECHO_T}$ac_cv_lib_ncurses_tputs" >&6 +if test $ac_cv_lib_ncurses_tputs = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNCURSES 1 +_ACEOF + + LIBS="-lncurses $LIBS" + +else + +echo "$as_me:$LINENO: checking for tputs in -ltermcap" >&5 +echo $ECHO_N "checking for tputs in -ltermcap... $ECHO_C" >&6 +if test "${ac_cv_lib_termcap_tputs+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ltermcap $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char tputs (); +int +main () +{ +tputs (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_termcap_tputs=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_termcap_tputs=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_termcap_tputs" >&5 +echo "${ECHO_T}$ac_cv_lib_termcap_tputs" >&6 +if test $ac_cv_lib_termcap_tputs = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBTERMCAP 1 +_ACEOF + + LIBS="-ltermcap $LIBS" + +fi + +fi + +fi + + +echo "$as_me:$LINENO: checking for main in -lreadline" >&5 +echo $ECHO_N "checking for main in -lreadline... $ECHO_C" >&6 +if test "${ac_cv_lib_readline_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lreadline $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_readline_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_readline_main=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_readline_main" >&5 +echo "${ECHO_T}$ac_cv_lib_readline_main" >&6 +if test $ac_cv_lib_readline_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBREADLINE 1 +_ACEOF + + LIBS="-lreadline $LIBS" + +fi + + if test $ac_cv_lib_readline_main = no; then + { { echo "$as_me:$LINENO: error: vtysh needs libreadline but was not found on your system." >&5 +echo "$as_me: error: vtysh needs libreadline but was not found on your system." >&2;} + { (exit 1); exit 1; }; } + fi + if test "${ac_cv_header_readline_history_h+set}" = set; then + echo "$as_me:$LINENO: checking for readline/history.h" >&5 +echo $ECHO_N "checking for readline/history.h... $ECHO_C" >&6 +if test "${ac_cv_header_readline_history_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_readline_history_h" >&5 +echo "${ECHO_T}$ac_cv_header_readline_history_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking readline/history.h usability" >&5 +echo $ECHO_N "checking readline/history.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking readline/history.h presence" >&5 +echo $ECHO_N "checking readline/history.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: readline/history.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: readline/history.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: readline/history.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: readline/history.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: readline/history.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: readline/history.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: readline/history.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: readline/history.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: readline/history.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: readline/history.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: readline/history.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: readline/history.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: readline/history.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: readline/history.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: readline/history.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: readline/history.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for readline/history.h" >&5 +echo $ECHO_N "checking for readline/history.h... $ECHO_C" >&6 +if test "${ac_cv_header_readline_history_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_readline_history_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_readline_history_h" >&5 +echo "${ECHO_T}$ac_cv_header_readline_history_h" >&6 + +fi + + + if test $ac_cv_header_readline_history_h = no;then + { { echo "$as_me:$LINENO: error: readline is too old to have readline/history.h, please update to the latest readline library." >&5 +echo "$as_me: error: readline is too old to have readline/history.h, please update to the latest readline library." >&2;} + { (exit 1); exit 1; }; } + fi + ;; + "no") + VTYSH="" + ;; + *) + ;; +esac + +if test "$with_libpam" = "yes"; then +echo "$as_me:$LINENO: checking for pam_start in -lpam" >&5 +echo $ECHO_N "checking for pam_start in -lpam... $ECHO_C" >&6 +if test "${ac_cv_lib_pam_pam_start+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpam $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char pam_start (); +int +main () +{ +pam_start (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_pam_pam_start=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_pam_pam_start=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_start" >&5 +echo "${ECHO_T}$ac_cv_lib_pam_pam_start" >&6 +if test $ac_cv_lib_pam_pam_start = yes; then + echo "$as_me:$LINENO: checking for misc_conv in -lpam" >&5 +echo $ECHO_N "checking for misc_conv in -lpam... $ECHO_C" >&6 +if test "${ac_cv_lib_pam_misc_conv+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpam $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char misc_conv (); +int +main () +{ +misc_conv (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_pam_misc_conv=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_pam_misc_conv=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_pam_misc_conv" >&5 +echo "${ECHO_T}$ac_cv_lib_pam_misc_conv" >&6 +if test $ac_cv_lib_pam_misc_conv = yes; then + +cat >>confdefs.h <<\_ACEOF +#define USE_PAM +_ACEOF + + LIBPAM="-lpam" +else + +cat >>confdefs.h <<\_ACEOF +#define USE_PAM +_ACEOF + + LIBPAM="-lpam -lpam_misc" + +fi + + +else + echo "$as_me:$LINENO: checking for pam_end in -lpam" >&5 +echo $ECHO_N "checking for pam_end in -lpam... $ECHO_C" >&6 +if test "${ac_cv_lib_pam_pam_end+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpam -ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char pam_end (); +int +main () +{ +pam_end (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_pam_pam_end=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_pam_pam_end=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_end" >&5 +echo "${ECHO_T}$ac_cv_lib_pam_pam_end" >&6 +if test $ac_cv_lib_pam_pam_end = yes; then + echo "$as_me:$LINENO: checking for misc_conv in -lpam" >&5 +echo $ECHO_N "checking for misc_conv in -lpam... $ECHO_C" >&6 +if test "${ac_cv_lib_pam_misc_conv+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpam $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char misc_conv (); +int +main () +{ +misc_conv (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_pam_misc_conv=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_pam_misc_conv=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_pam_misc_conv" >&5 +echo "${ECHO_T}$ac_cv_lib_pam_misc_conv" >&6 +if test $ac_cv_lib_pam_misc_conv = yes; then + cat >>confdefs.h <<\_ACEOF +#define USE_PAM 1 +_ACEOF + + LIBPAM="-lpam -ldl" +else + cat >>confdefs.h <<\_ACEOF +#define USE_PAM 1 +_ACEOF + + LIBPAM="-lpam -ldl -lpam_misc" + +fi + + +else + { echo "$as_me:$LINENO: WARNING: *** pam support will not be built ***" >&5 +echo "$as_me: WARNING: *** pam support will not be built ***" >&2;} +fi + + + +fi + +fi + + +echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 +echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6 +if test "${ac_cv_c_bigendian+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # See if sys/param.h defines the BYTE_ORDER macro. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + # It does; now see whether it defined to BIG_ENDIAN or not. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_bigendian=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +# It does not; compile a test program. +if test "$cross_compiling" = yes; then + # try to guess the endianness by grepping values into an object file + ac_cv_c_bigendian=unknown + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; +short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; +void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; } +short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; +short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; +void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; } +int +main () +{ + _ascii (); _ebcdic (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then + ac_cv_c_bigendian=yes +fi +if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +int +main () +{ + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long l; + char c[sizeof (long)]; + } u; + u.l = 1; + exit (u.c[sizeof (long) - 1] == 1); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=no +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_c_bigendian=yes +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 +echo "${ECHO_T}$ac_cv_c_bigendian" >&6 +case $ac_cv_c_bigendian in + yes) + +cat >>confdefs.h <<\_ACEOF +#define WORDS_BIGENDIAN 1 +_ACEOF + ;; + no) + ;; + *) + { { echo "$as_me:$LINENO: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&5 +echo "$as_me: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} + { (exit 1); exit 1; }; } ;; +esac + + + + + + + + + + + + + + + +for ac_func in bcopy bzero strerror inet_aton daemon snprintf vsnprintf strlcat strlcpy if_nametoindex if_indextoname getifaddrs +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +for ac_func in setproctitle +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +else + echo "$as_me:$LINENO: checking for setproctitle in -lutil" >&5 +echo $ECHO_N "checking for setproctitle in -lutil... $ECHO_C" >&6 +if test "${ac_cv_lib_util_setproctitle+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lutil $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char setproctitle (); +int +main () +{ +setproctitle (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_util_setproctitle=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_util_setproctitle=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_util_setproctitle" >&5 +echo "${ECHO_T}$ac_cv_lib_util_setproctitle" >&6 +if test $ac_cv_lib_util_setproctitle = yes; then + LIBS="$LIBS -lutil"; cat >>confdefs.h <<\_ACEOF +#define HAVE_SETPROCTITLE 1 +_ACEOF + +fi + +fi +done + + +echo "$as_me:$LINENO: checking zebra between kernel interface method" >&5 +echo $ECHO_N "checking zebra between kernel interface method... $ECHO_C" >&6 +if test x"$opsys" = x"gnu-linux"; then + if test "${enable_netlink}" = "yes";then + echo "$as_me:$LINENO: result: netlink" >&5 +echo "${ECHO_T}netlink" >&6 + RT_METHOD=rt_netlink.o + +cat >>confdefs.h <<\_ACEOF +#define HAVE_NETLINK +_ACEOF + + netlink=yes + elif test "${enable_netlink}" = "no"; then + echo "$as_me:$LINENO: result: ioctl" >&5 +echo "${ECHO_T}ioctl" >&6 + RT_METHOD=rt_ioctl.o + netlink=no + else + echo "$as_me:$LINENO: result: netlink" >&5 +echo "${ECHO_T}netlink" >&6 + RT_METHOD=rt_netlink.o + +cat >>confdefs.h <<\_ACEOF +#define HAVE_NETLINK +_ACEOF + + netlink=yes + fi +else + if test "$opsys" = "sol2-6";then + echo "$as_me:$LINENO: result: solaris" >&5 +echo "${ECHO_T}solaris" >&6 + KERNEL_METHOD="kernel_socket.o" + RT_METHOD="rt_socket.o" + else + if test "$cross_compiling" = yes; then + KERNEL_METHOD=kernel_socket.o + RT_METHOD=rt_socket.o + echo "$as_me:$LINENO: result: socket" >&5 +echo "${ECHO_T}socket" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include + +main () +{ + int ac_sock; + + ac_sock = socket (AF_ROUTE, SOCK_RAW, 0); + if (ac_sock < 0 && errno == EINVAL) + exit (1); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + KERNEL_METHOD=kernel_socket.o + RT_METHOD=rt_socket.o + echo "$as_me:$LINENO: result: socket" >&5 +echo "${ECHO_T}socket" >&6 +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +RT_METHOD=rt_ioctl.o + echo "$as_me:$LINENO: result: ioctl" >&5 +echo "${ECHO_T}ioctl" >&6 +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + fi +fi + + + + +echo "$as_me:$LINENO: checking route read method check" >&5 +echo $ECHO_N "checking route read method check... $ECHO_C" >&6 +if test "${zebra_rtread+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$netlink" = yes; then + RTREAD_METHOD="rtread_netlink.o" + zebra_rtread="netlink" +else +for zebra_rtread in /proc/net/route /dev/ip /dev/null; +do + test x`ls $zebra_rtread 2>/dev/null` = x"$zebra_rtread" && break +done +case $zebra_rtread in + "/proc/net/route") RTREAD_METHOD="rtread_proc.o" + zebra_rtread="proc";; + "/dev/ip") RTREAD_METHOD="rtread_getmsg.o" + zebra_rtread="getmsg";; + *) RTREAD_METHOD="rtread_sysctl.o" + zebra_rtread="sysctl";; +esac +fi +fi +echo "$as_me:$LINENO: result: $zebra_rtread" >&5 +echo "${ECHO_T}$zebra_rtread" >&6 + + +echo "$as_me:$LINENO: checking interface looking up method" >&5 +echo $ECHO_N "checking interface looking up method... $ECHO_C" >&6 +if test "$netlink" = yes; then + echo "$as_me:$LINENO: result: netlink" >&5 +echo "${ECHO_T}netlink" >&6 + IF_METHOD=if_netlink.o +else + if test "$opsys" = "sol2-6";then + echo "$as_me:$LINENO: result: solaris" >&5 +echo "${ECHO_T}solaris" >&6 + IF_METHOD=if_ioctl.o + elif test "$opsys" = "openbsd";then + echo "$as_me:$LINENO: result: openbsd" >&5 +echo "${ECHO_T}openbsd" >&6 + IF_METHOD=if_ioctl.o + elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: sysctl" >&5 +echo "${ECHO_T}sysctl" >&6 + IF_METHOD=if_sysctl.o + +cat >>confdefs.h <<\_ACEOF +#define HAVE_NET_RT_IFLIST +_ACEOF + + else + echo "$as_me:$LINENO: result: ioctl" >&5 +echo "${ECHO_T}ioctl" >&6 + IF_METHOD=if_ioctl.o + fi +fi + + +if test -r /proc/net/dev; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_PROC_NET_DEV +_ACEOF + + IF_PROC=if_proc.o +fi + +if test -r /proc/net/if_inet6; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_PROC_NET_IF_INET6 +_ACEOF + + IF_PROC=if_proc.o +fi + + +echo "$as_me:$LINENO: checking ipforward method check" >&5 +echo $ECHO_N "checking ipforward method check... $ECHO_C" >&6 +if test "${zebra_ipforward_path+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + for zebra_ipforward_path in /proc/net/snmp /dev/ip /dev/null; +do + test x`ls $zebra_ipforward_path 2>/dev/null` = x"$zebra_ipforward_path" && break +done +case $zebra_ipforward_path in + "/proc/net/snmp") IPFORWARD=ipforward_proc.o + zebra_ipforward_path="proc";; + "/dev/ip") + case "$host" in + *-linux-*) IPFORWARD=ipforward_proc.o + zebra_ipforward_path="proc";; + *-nec-sysv4*) IPFORWARD=ipforward_ews.o + zebra_ipforward_path="ews";; + *) IPFORWARD=ipforward_solaris.o + zebra_ipforward_path="solaris";; + esac;; + *) IPFORWARD=ipforward_sysctl.o + zebra_ipforward_path="sysctl";; +esac +fi +echo "$as_me:$LINENO: result: $zebra_ipforward_path" >&5 +echo "${ECHO_T}$zebra_ipforward_path" >&6 + + + +for ac_func in getaddrinfo +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + have_getaddrinfo=yes +else + have_getaddrinfo=no +fi +done + + +echo "$as_me:$LINENO: checking whether does this OS have IPv6 stack" >&5 +echo $ECHO_N "checking whether does this OS have IPv6 stack... $ECHO_C" >&6 +if test "${enable_ipv6}" = "no"; then + echo "$as_me:$LINENO: result: disabled" >&5 +echo "${ECHO_T}disabled" >&6 +else +if grep IPV6_INRIA_VERSION /usr/include/netinet/in.h >/dev/null 2>&1; then + zebra_cv_ipv6=yes + +cat >>confdefs.h <<\_ACEOF +#define HAVE_IPV6 +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define INRIA_IPV6 +_ACEOF + + RIPNGD="ripngd" + OSPF6D="ospf6d" + LIB_IPV6="" + echo "$as_me:$LINENO: result: INRIA IPv6" >&5 +echo "${ECHO_T}INRIA IPv6" >&6 +fi +if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then + zebra_cv_ipv6=yes + +cat >>confdefs.h <<\_ACEOF +#define HAVE_IPV6 +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define KAME +_ACEOF + + RIPNGD="ripngd" + OSPF6D="ospf6d" + if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then + LIB_IPV6="-L/usr/local/v6/lib -linet6" + fi + echo "$as_me:$LINENO: result: KAME" >&5 +echo "${ECHO_T}KAME" >&6 +fi +if grep NRL /usr/include/netinet6/in6.h >/dev/null 2>&1; then + zebra_cv_ipv6=yes + +cat >>confdefs.h <<\_ACEOF +#define HAVE_IPV6 +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define NRL +_ACEOF + + RIPNGD="ripngd" + OSPF6D="ospf6d" + if test x"$opsys" = x"bsdi";then + +cat >>confdefs.h <<\_ACEOF +#define BSDI_NRL +_ACEOF + + echo "$as_me:$LINENO: result: BSDI_NRL" >&5 +echo "${ECHO_T}BSDI_NRL" >&6 + else + echo "$as_me:$LINENO: result: NRL" >&5 +echo "${ECHO_T}NRL" >&6 + fi +fi + +if test "${enable_ipv6}" = "yes"; then + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + #include + /* 2.1.128 or later */ + #if LINUX_VERSION_CODE >= 0x020180 + yes + #endif +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "yes" >/dev/null 2>&1; then + zebra_cv_ipv6=yes; zebra_cv_linux_ipv6=yes;echo "$as_me:$LINENO: result: Linux IPv6" >&5 +echo "${ECHO_T}Linux IPv6" >&6 +fi +rm -f conftest* + +else + if test x`ls /proc/net/ipv6_route 2>/dev/null` = x"/proc/net/ipv6_route" + then + zebra_cv_ipv6=yes + zebra_cv_linux_ipv6=yes + echo "$as_me:$LINENO: result: Linux IPv6" >&5 +echo "${ECHO_T}Linux IPv6" >&6 + fi +fi + +if test "$zebra_cv_linux_ipv6" = "yes";then + cat >>confdefs.h <<\_ACEOF +#define HAVE_IPV6 1 +_ACEOF + + echo "$as_me:$LINENO: checking for GNU libc 2.1" >&5 +echo $ECHO_N "checking for GNU libc 2.1... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 + yes +#endif +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "yes" >/dev/null 2>&1; then + glibc=yes; echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + +cat >>confdefs.h <<\_ACEOF +#define LINUX_IPV6 +_ACEOF + + RIPNGD="ripngd" + OSPF6D="ospf6d" + if test "$glibc" != "yes"; then + INCLUDES="-I/usr/inet6/include" + if test x`ls /usr/inet6/lib/libinet6.a 2>/dev/null` != x;then + LIB_IPV6="-L/usr/inet6/lib -linet6" + fi + fi +fi + +LIBS="$LIB_IPV6 $LIBS" + + +if test x"$RIPNGD" = x""; then + echo "$as_me:$LINENO: result: IPv4 only" >&5 +echo "${ECHO_T}IPv4 only" >&6 +fi +fi + +if test "${enable_tcp_signature}" = "yes"; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_TCP_SIGNATURE +_ACEOF + + case "$host" in + *-linux-*) + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LINUX_TCP_SIGNATURE +_ACEOF + + ;; + *-openbsd*) + +cat >>confdefs.h <<\_ACEOF +#define HAVE_OPENBSD_TCP_SIGNATURE +_ACEOF + + ;; + *) + echo "Sorry, your OS don't support TCP signature." + exit 1 + ;; + esac +fi + +if test "${enable_zebra}" = "no";then + ZEBRA="" +else + ZEBRA="zebra" +fi + +if test "${enable_bgpd}" = "no";then + BGPD="" +else + BGPD="bgpd" +fi + +if test "${enable_ripd}" = "no";then + RIPD="" +else + RIPD="ripd" +fi + +if test "${enable_ospfd}" = "no";then + OSPFD="" +else + OSPFD="ospfd" +fi + +case "${enable_ripngd}" in + "yes") RIPNGD="ripngd";; + "no" ) RIPNGD="";; + * ) ;; +esac + +case "${enable_ospf6d}" in + "yes") OSPF6D="ospf6d";; + "no" ) OSPF6D="";; + * ) ;; +esac + +if test "${enable_bgp_announce}" = "no";then + +cat >>confdefs.h <<\_ACEOF +#define DISABLE_BGP_ANNOUNCE +_ACEOF + +fi + + + + + + + + + + +echo "$as_me:$LINENO: checking for inet_ntop in -lc" >&5 +echo $ECHO_N "checking for inet_ntop in -lc... $ECHO_C" >&6 +if test "${ac_cv_lib_c_inet_ntop+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lc $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char inet_ntop (); +int +main () +{ +inet_ntop (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_c_inet_ntop=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_c_inet_ntop=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_c_inet_ntop" >&5 +echo "${ECHO_T}$ac_cv_lib_c_inet_ntop" >&6 +if test $ac_cv_lib_c_inet_ntop = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_INET_NTOP +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for inet_pton in -lc" >&5 +echo $ECHO_N "checking for inet_pton in -lc... $ECHO_C" >&6 +if test "${ac_cv_lib_c_inet_pton+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lc $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char inet_pton (); +int +main () +{ +inet_pton (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_c_inet_pton=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_c_inet_pton=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_c_inet_pton" >&5 +echo "${ECHO_T}$ac_cv_lib_c_inet_pton" >&6 +if test $ac_cv_lib_c_inet_pton = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_INET_PTON +_ACEOF + +fi + + +echo "$as_me:$LINENO: checking for crypt in -lcrypt" >&5 +echo $ECHO_N "checking for crypt in -lcrypt... $ECHO_C" >&6 +if test "${ac_cv_lib_crypt_crypt+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypt $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char crypt (); +int +main () +{ +crypt (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_crypt_crypt=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_crypt_crypt=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_crypt_crypt" >&5 +echo "${ECHO_T}$ac_cv_lib_crypt_crypt" >&6 +if test $ac_cv_lib_crypt_crypt = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBCRYPT 1 +_ACEOF + + LIBS="-lcrypt $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for res_init in -lresolv" >&5 +echo $ECHO_N "checking for res_init in -lresolv... $ECHO_C" >&6 +if test "${ac_cv_lib_resolv_res_init+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lresolv $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char res_init (); +int +main () +{ +res_init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_resolv_res_init=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_resolv_res_init=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_res_init" >&5 +echo "${ECHO_T}$ac_cv_lib_resolv_res_init" >&6 +if test $ac_cv_lib_resolv_res_init = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBRESOLV 1 +_ACEOF + + LIBS="-lresolv $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for main in -lm" >&5 +echo $ECHO_N "checking for main in -lm... $ECHO_C" >&6 +if test "${ac_cv_lib_m_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_m_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_m_main=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_m_main" >&5 +echo "${ECHO_T}$ac_cv_lib_m_main" >&6 +if test $ac_cv_lib_m_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBM 1 +_ACEOF + + LIBS="-lm $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for __inet_ntop" >&5 +echo $ECHO_N "checking for __inet_ntop... $ECHO_C" >&6 +if test "${ac_cv_func___inet_ntop+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define __inet_ntop to an innocuous variant, in case declares __inet_ntop. + For example, HP-UX 11i declares gettimeofday. */ +#define __inet_ntop innocuous___inet_ntop + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char __inet_ntop (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef __inet_ntop + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char __inet_ntop (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub___inet_ntop) || defined (__stub_____inet_ntop) +choke me +#else +char (*f) () = __inet_ntop; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != __inet_ntop; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func___inet_ntop=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func___inet_ntop=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func___inet_ntop" >&5 +echo "${ECHO_T}$ac_cv_func___inet_ntop" >&6 +if test $ac_cv_func___inet_ntop = yes; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_INET_NTOP 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for __inet_pton" >&5 +echo $ECHO_N "checking for __inet_pton... $ECHO_C" >&6 +if test "${ac_cv_func___inet_pton+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define __inet_pton to an innocuous variant, in case declares __inet_pton. + For example, HP-UX 11i declares gettimeofday. */ +#define __inet_pton innocuous___inet_pton + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char __inet_pton (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef __inet_pton + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char __inet_pton (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub___inet_pton) || defined (__stub_____inet_pton) +choke me +#else +char (*f) () = __inet_pton; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != __inet_pton; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func___inet_pton=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func___inet_pton=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func___inet_pton" >&5 +echo "${ECHO_T}$ac_cv_func___inet_pton" >&6 +if test $ac_cv_func___inet_pton = yes; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_INET_PTON 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for __inet_aton" >&5 +echo $ECHO_N "checking for __inet_aton... $ECHO_C" >&6 +if test "${ac_cv_func___inet_aton+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define __inet_aton to an innocuous variant, in case declares __inet_aton. + For example, HP-UX 11i declares gettimeofday. */ +#define __inet_aton innocuous___inet_aton + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char __inet_aton (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef __inet_aton + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char __inet_aton (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub___inet_aton) || defined (__stub_____inet_aton) +choke me +#else +char (*f) () = __inet_aton; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != __inet_aton; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func___inet_aton=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func___inet_aton=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func___inet_aton" >&5 +echo "${ECHO_T}$ac_cv_func___inet_aton" >&6 +if test $ac_cv_func___inet_aton = yes; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_INET_ATON 1 +_ACEOF + +fi + + +echo "$as_me:$LINENO: checking for regexec in -lc" >&5 +echo $ECHO_N "checking for regexec in -lc... $ECHO_C" >&6 +if test "${ac_cv_lib_c_regexec+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lc $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char regexec (); +int +main () +{ +regexec (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_c_regexec=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_c_regexec=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_c_regexec" >&5 +echo "${ECHO_T}$ac_cv_lib_c_regexec" >&6 +if test $ac_cv_lib_c_regexec = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_GNU_REGEX +_ACEOF + + LIB_REGEX="" +else + LIB_REGEX="regex.o" +fi + + + +if test "${enable_snmp}" = "yes"; then + saved_libs="${LIBS}" + LIBS="" + + unset link_dir link_dirs + test "${linkbase_specified}" = "yes" && link_dirs=${with_linkbase} + link_dirs="$link_dirs /usr/local" + for link_dir in '' ${link_dirs}; do + test "x${link_dir}" != "x" && link_dir="-L${link_dir}/lib" + LIBS=${link_dir} + + { echo "$as_me:$LINENO: try linking with LIBS: $LIBS" >&5 +echo "$as_me: try linking with LIBS: $LIBS" >&6;} + unset ac_cv_lib_netsnmp_asn_parse_int + echo "$as_me:$LINENO: checking for asn_parse_int in -lnetsnmp" >&5 +echo $ECHO_N "checking for asn_parse_int in -lnetsnmp... $ECHO_C" >&6 +if test "${ac_cv_lib_netsnmp_asn_parse_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnetsnmp $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char asn_parse_int (); +int +main () +{ +asn_parse_int (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_netsnmp_asn_parse_int=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_netsnmp_asn_parse_int=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_netsnmp_asn_parse_int" >&5 +echo "${ECHO_T}$ac_cv_lib_netsnmp_asn_parse_int" >&6 +if test $ac_cv_lib_netsnmp_asn_parse_int = yes; then + HAVE_SNMP=yes; ac_snmp_lib="$LIBS -lnetsnmp" +fi + + test "${HAVE_SNMP}" = "yes" && break + + unset ac_cv_lib_snmp_asn_parse_int + echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5 +echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6 +if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsnmp $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char asn_parse_int (); +int +main () +{ +asn_parse_int (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_snmp_asn_parse_int=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_snmp_asn_parse_int=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5 +echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6 +if test $ac_cv_lib_snmp_asn_parse_int = yes; then + HAVE_SNMP=yes; ac_snmp_lib="$LIBS -lsnmp" +fi + + test "${HAVE_SNMP}" = "yes" && break + + echo "$as_me:$LINENO: checking for main in -lcrypto" >&5 +echo $ECHO_N "checking for main in -lcrypto... $ECHO_C" >&6 +if test "${ac_cv_lib_crypto_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_crypto_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_crypto_main=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_main" >&5 +echo "${ECHO_T}$ac_cv_lib_crypto_main" >&6 +if test $ac_cv_lib_crypto_main = yes; then + NEED_CRYPTO=yes +fi + + test "${NEED_CRYPTO}" != "yes" && continue + LIBS="$LIBS -lcrypto" + + { echo "$as_me:$LINENO: try linking with LIBS: $LIBS" >&5 +echo "$as_me: try linking with LIBS: $LIBS" >&6;} + unset ac_cv_lib_netsnmp_asn_parse_int + echo "$as_me:$LINENO: checking for asn_parse_int in -lnetsnmp" >&5 +echo $ECHO_N "checking for asn_parse_int in -lnetsnmp... $ECHO_C" >&6 +if test "${ac_cv_lib_netsnmp_asn_parse_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnetsnmp -lcrypto $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char asn_parse_int (); +int +main () +{ +asn_parse_int (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_netsnmp_asn_parse_int=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_netsnmp_asn_parse_int=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_netsnmp_asn_parse_int" >&5 +echo "${ECHO_T}$ac_cv_lib_netsnmp_asn_parse_int" >&6 +if test $ac_cv_lib_netsnmp_asn_parse_int = yes; then + HAVE_SNMP=yes; ac_snmp_lib="$LIBS -lnetsnmp" +fi + + test "${HAVE_SNMP}" = "yes" && break + + unset ac_cv_lib_snmp_asn_parse_int + echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5 +echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6 +if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsnmp -lcrypto $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char asn_parse_int (); +int +main () +{ +asn_parse_int (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_snmp_asn_parse_int=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_snmp_asn_parse_int=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5 +echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6 +if test $ac_cv_lib_snmp_asn_parse_int = yes; then + HAVE_SNMP=yes; ac_snmp_lib="$LIBS -lsnmp" +fi + + test "${HAVE_SNMP}" = "yes" && break + done + if test "${HAVE_SNMP}" = ""; then + { { echo "$as_me:$LINENO: error: cannot find valid snmp library" >&5 +echo "$as_me: error: cannot find valid snmp library" >&2;} + { (exit 1); exit 1; }; } + fi + LIBS="${saved_libs} $ac_snmp_lib" + + echo "$as_me:$LINENO: checking for snmp library header" >&5 +echo $ECHO_N "checking for snmp library header... $ECHO_C" >&6 + unset link_dir link_dirs ac_snmp ac_snmps ac_snmp_dir ac_snmp_dirs + link_dirs="/usr/include"; + if test "${linkbase_specified}" = "yes"; then + link_dirs="${link_dirs} ${with_linkbase}/include" + fi + link_dirs="${link_dirs} /usr/local/include" + ac_snmp_dirs="net-snmp net-snmp/library ucd-snmp" + + for link_dir in '' ${link_dirs}; do + test -z $link_dir && continue + for ac_snmp_dir in '' ${ac_snmp_dirs}; do + test -z $ac_snmp_dir && continue + ac_snmps="${ac_snmps} ${link_dir}/${ac_snmp_dir}/asn1.h" + done + done + ac_snmps="${ac_snmps}" + + for ac_snmp in '' ${ac_snmps}; do + test -z ${ac_snmp} && continue + test -f ${ac_snmp} && break + done + ac_snmp_header=`echo ${ac_snmp} | sed -e 's/\/asn1.h//'` + ac_snmp_header="-I${ac_snmp_header}" + + case ${ac_snmp} in + /usr/local/include/net-snmp/*) + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SNMP +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define HAVE_NETSNMP +_ACEOF + + CFLAGS="${CFLAGS} -I/usr/local/include" + ;; + */net-snmp/*) + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SNMP +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define HAVE_NETSNMP +_ACEOF + + ;; + /usr/local/include/ucd-snmp/*) + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SNMP +_ACEOF + + CFLAGS="${CFLAGS} -I/usr/local/include" + ;; + */ucd-snmp/*) + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SNMP +_ACEOF + + ;; + esac + echo "$as_me:$LINENO: result: $ac_snmp_header" >&5 +echo "${ECHO_T}$ac_snmp_header" >&6 + CFLAGS="${CFLAGS} ${ac_snmp_header}" +fi + +echo "$as_me:$LINENO: checking whether struct sockaddr has a sa_len field" >&5 +echo $ECHO_N "checking whether struct sockaddr has a sa_len field... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +static struct sockaddr ac_i;int ac_j = sizeof (ac_i.sa_len); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SA_LEN +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +echo "$as_me:$LINENO: checking whether struct sockaddr_in has a sin_len field" >&5 +echo $ECHO_N "checking whether struct sockaddr_in has a sin_len field... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +static struct sockaddr_in ac_i;int ac_j = sizeof (ac_i.sin_len); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SIN_LEN +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +echo "$as_me:$LINENO: checking whether struct sockaddr_un has a sun_len field" >&5 +echo $ECHO_N "checking whether struct sockaddr_un has a sun_len field... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +static struct sockaddr_un ac_i;int ac_j = sizeof (ac_i.sun_len); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SUN_LEN +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test "$zebra_cv_ipv6" = yes; then + echo "$as_me:$LINENO: checking whether struct sockaddr_in6 has a sin6_scope_id field" >&5 +echo $ECHO_N "checking whether struct sockaddr_in6 has a sin6_scope_id field... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +static struct sockaddr_in6 ac_i;int ac_j = sizeof (ac_i.sin6_scope_id); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SIN6_SCOPE_ID +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +if test "$zebra_cv_ipv6" = yes; then + echo "$as_me:$LINENO: checking whether in6addr_loopback is usable" >&5 +echo $ECHO_N "checking whether in6addr_loopback is usable... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +static struct in6_addr ac_i; ac_i = in6addr_loopback; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_IN6ADDR_GLOBAL +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +echo "$as_me:$LINENO: checking whther socklen_t is defined" >&5 +echo $ECHO_N "checking whther socklen_t is defined... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +socklen_t ac_x; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SOCKLEN_T +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +echo "$as_me:$LINENO: checking whether struct sockaddr_dl exist" >&5 +echo $ECHO_N "checking whether struct sockaddr_dl exist... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "sockaddr_dl" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SOCKADDR_DL +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + +echo "$as_me:$LINENO: checking whether struct ifaliasreq exist" >&5 +echo $ECHO_N "checking whether struct ifaliasreq exist... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "ifaliasreq" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_IFALIASREQ +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + +echo "$as_me:$LINENO: checking whether struct if6_aliasreq exist" >&5 +echo $ECHO_N "checking whether struct if6_aliasreq exist... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "in6_aliasreq" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_IN6_ALIASREQ +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + +echo "$as_me:$LINENO: checking whether struct rt_addrinfo exist" >&5 +echo $ECHO_N "checking whether struct rt_addrinfo exist... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "rt_addrinfo" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_RT_ADDRINFO +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + +echo "$as_me:$LINENO: checking whether struct in_pktinfo exist" >&5 +echo $ECHO_N "checking whether struct in_pktinfo exist... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +int +main () +{ +struct in_pktinfo ac_x; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_INPKTINFO +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +echo "$as_me:$LINENO: checking whether getrusage is available" >&5 +echo $ECHO_N "checking whether getrusage is available... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +int +main () +{ +struct rusage ac_x; getrusage (RUSAGE_SELF, &ac_x); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_RUSAGE +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +file="${srcdir}/lib/version.h" +VERSION=`sed -ne 's/^#.*ZEBRA_VERSION.*\"\([^\"]*\)\"$/\1/p' $file` + + +echo "$as_me:$LINENO: checking pid file directory" >&5 +echo $ECHO_N "checking pid file directory... $ECHO_C" >&6 +if test "${ac_piddir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + for ZEBRA_PID_DIR in /var/run /var/adm /etc /dev/null; +do + test -d $ZEBRA_PID_DIR && break +done +ac_piddir=$ZEBRA_PID_DIR +if test $ZEBRA_PID_DIR = "/dev/null"; then + echo "PID DIRECTORY NOT FOUND!" +fi +fi +echo "$as_me:$LINENO: result: $ac_piddir" >&5 +echo "${ECHO_T}$ac_piddir" >&6 + +cat >>confdefs.h <<_ACEOF +#define PATH_ZEBRA_PID "$ac_piddir/zebra.pid" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PATH_RIPD_PID "$ac_piddir/ripd.pid" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PATH_RIPNGD_PID "$ac_piddir/ripngd.pid" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PATH_BGPD_PID "$ac_piddir/bgpd.pid" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PATH_OSPFD_PID "$ac_piddir/ospfd.pid" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PATH_OSPF6D_PID "$ac_piddir/ospf6d.pid" +_ACEOF + + + +echo "$as_me:$LINENO: checking for working htonl" >&5 +echo $ECHO_N "checking for working htonl... $ECHO_C" >&6 +if test "${ac_cv_htonl_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +int +main () +{ +htonl (0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_htonl_works=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_htonl_works=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +echo "$as_me:$LINENO: result: $ac_cv_htonl_works" >&5 +echo "${ECHO_T}$ac_cv_htonl_works" >&6 + + ac_config_files="$ac_config_files Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile ospf6d/Makefile vtysh/Makefile doc/Makefile" +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS section. +# + +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; + "zebra/Makefile" ) CONFIG_FILES="$CONFIG_FILES zebra/Makefile" ;; + "ripd/Makefile" ) CONFIG_FILES="$CONFIG_FILES ripd/Makefile" ;; + "ripngd/Makefile" ) CONFIG_FILES="$CONFIG_FILES ripngd/Makefile" ;; + "bgpd/Makefile" ) CONFIG_FILES="$CONFIG_FILES bgpd/Makefile" ;; + "ospfd/Makefile" ) CONFIG_FILES="$CONFIG_FILES ospfd/Makefile" ;; + "ospf6d/Makefile" ) CONFIG_FILES="$CONFIG_FILES ospf6d/Makefile" ;; + "vtysh/Makefile" ) CONFIG_FILES="$CONFIG_FILES vtysh/Makefile" ;; + "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t +s,@ACLOCAL@,$ACLOCAL,;t t +s,@AUTOCONF@,$AUTOCONF,;t t +s,@AUTOMAKE@,$AUTOMAKE,;t t +s,@AUTOHEADER@,$AUTOHEADER,;t t +s,@MAKEINFO@,$MAKEINFO,;t t +s,@AMTAR@,$AMTAR,;t t +s,@install_sh@,$install_sh,;t t +s,@STRIP@,$STRIP,;t t +s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t +s,@AWK@,$AWK,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@DEPDIR@,$DEPDIR,;t t +s,@am__include@,$am__include,;t t +s,@am__quote@,$am__quote,;t t +s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t +s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t +s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t +s,@CCDEPMODE@,$CCDEPMODE,;t t +s,@CPP@,$CPP,;t t +s,@AR@,$AR,;t t +s,@ac_ct_AR@,$ac_ct_AR,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@EGREP@,$EGREP,;t t +s,@MULTIPATH_NUM@,$MULTIPATH_NUM,;t t +s,@LIBPAM@,$LIBPAM,;t t +s,@RT_METHOD@,$RT_METHOD,;t t +s,@KERNEL_METHOD@,$KERNEL_METHOD,;t t +s,@OTHER_METHOD@,$OTHER_METHOD,;t t +s,@RTREAD_METHOD@,$RTREAD_METHOD,;t t +s,@IF_METHOD@,$IF_METHOD,;t t +s,@IF_PROC@,$IF_PROC,;t t +s,@IPFORWARD@,$IPFORWARD,;t t +s,@LIB_IPV6@,$LIB_IPV6,;t t +s,@ZEBRA@,$ZEBRA,;t t +s,@BGPD@,$BGPD,;t t +s,@RIPD@,$RIPD,;t t +s,@RIPNGD@,$RIPNGD,;t t +s,@OSPFD@,$OSPFD,;t t +s,@OSPF6D@,$OSPF6D,;t t +s,@VTYSH@,$VTYSH,;t t +s,@INCLUDES@,$INCLUDES,;t t +s,@CURSES@,$CURSES,;t t +s,@LIB_REGEX@,$LIB_REGEX,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi + # Run the commands associated with the file. + case $ac_file in + config.h ) # update the timestamp +echo 'timestamp for config.h' >"./stamp-h1" + ;; + esac +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_COMMANDS section. +# +for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_dir=`(dirname "$ac_dest") 2>/dev/null || +$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_dest" : 'X\(//\)[^/]' \| \ + X"$ac_dest" : 'X\(//\)$' \| \ + X"$ac_dest" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_dest" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`(dirname "$mf") 2>/dev/null || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + else + continue + fi + grep '^DEP_FILES *= *[^ #]' < "$mf" > /dev/null || continue + # Extract the definition of DEP_FILES from the Makefile without + # running `make'. + DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"` + test -z "$DEPDIR" && continue + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n -e '/^U = / s///p' < "$mf"` + test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" + # We invoke sed twice because it is the simplest approach to + # changing $(DEPDIR) to its actual value in the expansion. + for file in `sed -n -e ' + /^DEP_FILES = .*\\\\$/ { + s/^DEP_FILES = // + :loop + s/\\\\$// + p + n + /\\\\$/ b loop + p + } + /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`(dirname "$file") 2>/dev/null || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p $dirpart/$fdir + else + as_dir=$dirpart/$fdir + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5 +echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;} + { (exit 1); exit 1; }; }; } + + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + esac +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + + +echo " +zebra configuration +------------------- +zebra version : ${VERSION} +host operationg system : ${host_os} +source code location : ${srcdir} +compiler : ${CC} +compiler flags : ${CFLAGS} +link libraries : ${LIBS} +directory for pid files : ${ac_piddir} +" diff --git a/configure.ac b/configure.ac new file mode 100755 index 0000000..55ffef5 --- /dev/null +++ b/configure.ac @@ -0,0 +1,913 @@ +## +## Configure template file for Zebra. +## autoconf will generate configure script. +## +## Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro +## +AC_PREREQ(2.53) + +AC_INIT(lib/zebra.h) +AM_INIT_AUTOMAKE(zebra, 0.95) +AM_CONFIG_HEADER(config.h) + +dnl ----------------------------------- +dnl Get hostname and other information. +dnl ----------------------------------- +AC_CANONICAL_HOST + +dnl ------------ +dnl Check CFLAGS +dnl ------------ +AC_ARG_WITH(cflags, +[ --with-cflags Set CFLAGS for use in compilation.]) +if test "x$with_cflags" != "x" ; then + CFLAGS="$with_cflags" ; cflags_specified=yes ; +elif test -n "$CFLAGS" ; then + cflags_specified=yes ; +fi + +dnl ------------ +dnl Check LINKBASE +dnl ------------ +AC_ARG_WITH(linkbase, +[ --with-linkbase Set local library base for use in compilation.]) +if test "x$with_linkbase" != "x" ; then + linkbase_specified=yes ; +fi + +dnl -------- +dnl Check CC +dnl -------- +AC_PROG_CC + +dnl ----------------------------------------- +dnl If CLFAGS doesn\'t exist set default value +dnl ----------------------------------------- +if test "x$cflags_specified" = "x" ; then + CFLAGS="$CFLAGS -Wall" +fi + +dnl ----------------------------------------- +dnl If linkbase specified expand it +dnl ----------------------------------------- +if test "$linkbase_specified" = "yes" ; then + CFLAGS="$CFLAGS -I${with_linkbase}/include" ; + LIBS="$LIBS -L${with_linkbase}/lib" ; +fi + +dnl -------------- +dnl Check programs +dnl -------------- +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_MAKE_SET +AC_CHECK_TOOL(AR, ar) +AC_CHECK_TOOL(RANLIB, ranlib, :) + +dnl --------- +dnl AIX check +dnl --------- +AC_AIX + +dnl ---------------------- +dnl Packages configuration +dnl ---------------------- +AC_ARG_ENABLE(vtysh, +[ --enable-vtysh, Make integrated VTY version of zebra]) +AC_ARG_ENABLE(ipv6, +[ --disable-ipv6 turn off IPv6 related features and daemons]) +AC_ARG_ENABLE(zebra, +[ --disable-zebra do not build zebra daemon]) +AC_ARG_ENABLE(bgpd, +[ --disable-bgpd do not build bgpd]) +AC_ARG_ENABLE(ripd, +[ --disable-ripd do not build ripd]) +AC_ARG_ENABLE(ripngd, +[ --disable-ripngd do not build ripngd]) +AC_ARG_ENABLE(ospfd, +[ --disable-ospfd do not build ospfd]) +AC_ARG_ENABLE(ospf6d, +[ --disable-ospf6d do not build ospf6d]) +AC_ARG_ENABLE(irdp, +[ --enable-irdp enable IRDP server support in zebra]) +AC_ARG_ENABLE(bgp-announce, +[ --disable-bgp-announce, turn off BGP route announcement]) +AC_ARG_ENABLE(netlink, +[ --enable-netlink force to use Linux netlink interface]) +AC_ARG_ENABLE(broken-aliases, +[ --enable-broken-aliases enable aliases as distinct interfaces for Linux 2.2.X]) +AC_ARG_ENABLE(snmp, +[ --enable-snmp enable SNMP support]) +AC_ARG_WITH(libpam, +[ --with-libpam use libpam for PAM support in vtysh]) +AC_ARG_ENABLE(tcpsock, +[ --enable-tcp-zebra enable TCP/IP socket connection between zebra and protocol daemon]) +dnl Temporary option until OSPF NSSA implementation complete +AC_ARG_ENABLE(nssa, +[ --enable-nssa enable OSPF NSSA option]) +AC_ARG_ENABLE(opaque-lsa, +[ --enable-opaque-lsa enable OSPF Opaque-LSA support (RFC2370)]) +AC_ARG_ENABLE(ospf-te, +[ --enable-ospf-te enable Traffic Engineering Extension to OSPF]) +AC_ARG_ENABLE(multipath, +[ --enable-multipath=ARG enable multipath function, ARG must be digit]) +AC_ARG_ENABLE(tcp-signature, +[ --enable-tcp-signature enable TCP MD5 Signature Option (RFC2385) (for Linux and OpenBSD)]) + +if test "${enable_broken_aliases}" = "yes"; then + if test "${enable_netlink}" = "yes" + then + echo "Sorry, you can't use netlink with broken aliases" + exit 1 + fi + AC_DEFINE(HAVE_BROKEN_ALIASES,,Broken Alias) + enable_netlink=no +fi + +if test "${enable_tcp_zebra}" = "yes"; then + AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication) +fi + +if test "${enable_nssa}" = "yes"; then + AC_DEFINE(HAVE_NSSA,,OSPF NSSA) +fi + +if test "${enable_irdp}" = "yes"; then + AC_DEFINE(HAVE_IRDP,, IRDP ) +fi + +if test "${enable_opaque_lsa}" = "yes"; then + AC_DEFINE(HAVE_OPAQUE_LSA,,OSPF Opaque LSA) +fi + +if test "${enable_ospf_te}" = "yes"; then + AC_DEFINE(HAVE_OPAQUE_LSA,,OSPF Opaque LSA) + AC_DEFINE(HAVE_OSPF_TE,,OSPF TE) +fi + +changequote(, )dnl + +MULTIPATH_NUM=1 + +case "${enable_multipath}" in + [0-9]|[1-9][0-9]) + MULTIPATH_NUM="${enable_multipath}" + ;; + "") + ;; + *) + echo "Please specify digit to --enable-multipath ARG." + exit 1 + ;; +esac + +changequote([, ])dnl + +AC_SUBST(MULTIPATH_NUM) + +dnl ------------------- +dnl Check header files. +dnl ------------------- +AC_STDC_HEADERS +AC_CHECK_HEADERS(string.h stropts.h sys/conf.h sys/ksym.h sys/time.h sys/times.h sys/select.h sys/sysctl.h sys/sockio.h sys/types.h net/if_dl.h net/if_var.h linux/version.h kvm.h netdb.h netinet/in.h net/netopt.h netinet/in_var.h netinet/in6_var.h netinet/in6.h inet/nd.h asm/types.h netinet/icmp6.h netinet6/nd6.h libutil.h) + +dnl check some types +AC_C_CONST +dnl AC_TYPE_PID_T +AC_TYPE_SIGNAL + +dnl Some systems (Solaris 2.x) require libnsl (Network Services Library) +case "$host" in + *-sunos5.6* | *-solaris2.6*) + opsys=sol2-6 + AC_DEFINE(SUNOS_5,,SunOS 5) + AC_CHECK_LIB(xnet, main) + CURSES=-lcurses + ;; + *-sunos5* | *-solaris2*) + AC_DEFINE(SUNOS_5,,SunOS 5) + AC_CHECK_LIB(socket, main) + AC_CHECK_LIB(nsl, main) + CURSES=-lcurses + ;; + *-linux-*) + opsys=gnu-linux + AC_DEFINE(GNU_LINUX,,GNU Linux) + ;; + *-nec-sysv4*) + AC_CHECK_LIB(nsl, gethostbyname) + AC_CHECK_LIB(socket, socket) + ;; + *-freebsd3.2) + AC_DEFINE(FREEBSD_32,,FreeBSD 3.2) + ;; + *-openbsd*) + opsys=openbsd + AC_DEFINE(OPEN_BSD,,OpenBSD) + ;; + *-bsdi*) + opsys=bsdi + OTHER_METHOD="mtu_kvm.o" + AC_CHECK_LIB(kvm, main) + ;; +esac + +dnl --------------------- +dnl Integrated VTY option +dnl --------------------- +case "${enable_vtysh}" in + "yes") + VTYSH="vtysh"; + AC_DEFINE(VTYSH,,VTY shell) + AC_CHECK_LIB(tinfo, tputs, , AC_CHECK_LIB(ncurses, tputs, , + AC_CHECK_LIB(termcap, tputs))) + AC_CHECK_LIB(readline, main) + if test $ac_cv_lib_readline_main = no; then + AC_MSG_ERROR([vtysh needs libreadline but was not found on your system.]) + fi + AC_CHECK_HEADER(readline/history.h) + if test $ac_cv_header_readline_history_h = no;then + AC_MSG_ERROR([readline is too old to have readline/history.h, please update to the latest readline library.]) + fi + ;; + "no") + VTYSH="" + ;; + *) + ;; +esac + +dnl ---------- +dnl PAM module +dnl ---------- +if test "$with_libpam" = "yes"; then +dnl took this test from proftpd's configure.in and suited to our needs +dnl ------------------------------------------------------------------------- +dnl +dnl This next check looks funky due to a linker problem with some versions +dnl of the PAM library. Prior to 0.72 release, the Linux PAM shared library +dnl omitted requiring libdl linking information. PAM-0.72 or better ships +dnl with RedHat 6.2 and Debian 2.2 or better. +AC_CHECK_LIB(pam, pam_start, + [AC_CHECK_LIB(pam, misc_conv, + [AC_DEFINE(USE_PAM,,Use PAM for authentication) + LIBPAM="-lpam"], + [AC_DEFINE(USE_PAM,,Use PAM for authentication) + LIBPAM="-lpam -lpam_misc"] + ) + ], + + [AC_CHECK_LIB(pam, pam_end, + [AC_CHECK_LIB(pam, misc_conv, + [AC_DEFINE(USE_PAM) + LIBPAM="-lpam -ldl"], + [AC_DEFINE(USE_PAM) + LIBPAM="-lpam -ldl -lpam_misc"] + ) + ],AC_MSG_WARN([*** pam support will not be built ***]), + [-ldl]) + ] +) +fi +AC_SUBST(LIBPAM) + +dnl ------------------------------- +dnl Endian-ness check +dnl ------------------------------- +AC_WORDS_BIGENDIAN + +dnl ------------------------------- +dnl check the size in byte of the C +dnl ------------------------------- +dnl AC_CHECK_SIZEOF(char) +dnl AC_CHECK_SIZEOF(int) +dnl AC_CHECK_SIZEOF(short) +dnl AC_CHECK_SIZEOF(long) + +dnl ---------------------------- +dnl check existance of functions +dnl ---------------------------- +AC_CHECK_FUNCS(bcopy bzero strerror inet_aton daemon snprintf vsnprintf strlcat strlcpy if_nametoindex if_indextoname getifaddrs) +AC_CHECK_FUNCS(setproctitle, ,[AC_CHECK_LIB(util, setproctitle, [LIBS="$LIBS -lutil"; AC_DEFINE(HAVE_SETPROCTITLE)])]) + +dnl ------------------------------------ +dnl Determine routing get and set method +dnl ------------------------------------ +AC_MSG_CHECKING(zebra between kernel interface method) +if test x"$opsys" = x"gnu-linux"; then + if test "${enable_netlink}" = "yes";then + AC_MSG_RESULT(netlink) + RT_METHOD=rt_netlink.o + AC_DEFINE(HAVE_NETLINK,,netlink) + netlink=yes + elif test "${enable_netlink}" = "no"; then + AC_MSG_RESULT(ioctl) + RT_METHOD=rt_ioctl.o + netlink=no + else + AC_MSG_RESULT(netlink) + RT_METHOD=rt_netlink.o + AC_DEFINE(HAVE_NETLINK,,netlink) + netlink=yes + fi +else + if test "$opsys" = "sol2-6";then + AC_MSG_RESULT(solaris) + KERNEL_METHOD="kernel_socket.o" + RT_METHOD="rt_socket.o" + else + AC_TRY_RUN([#include +#include +#include + +main () +{ + int ac_sock; + + ac_sock = socket (AF_ROUTE, SOCK_RAW, 0); + if (ac_sock < 0 && errno == EINVAL) + exit (1); + exit (0); +}], + [KERNEL_METHOD=kernel_socket.o + RT_METHOD=rt_socket.o + AC_MSG_RESULT(socket)], + [RT_METHOD=rt_ioctl.o + AC_MSG_RESULT(ioctl)], + [KERNEL_METHOD=kernel_socket.o + RT_METHOD=rt_socket.o + AC_MSG_RESULT(socket)]) + fi +fi +AC_SUBST(RT_METHOD) +AC_SUBST(KERNEL_METHOD) +AC_SUBST(OTHER_METHOD) + +dnl ------------------------------ +dnl check kernel route read method +dnl ------------------------------ +AC_CACHE_CHECK(route read method check, zebra_rtread, +[if test "$netlink" = yes; then + RTREAD_METHOD="rtread_netlink.o" + zebra_rtread="netlink" +else +for zebra_rtread in /proc/net/route /dev/ip /dev/null; +do + test x`ls $zebra_rtread 2>/dev/null` = x"$zebra_rtread" && break +done +case $zebra_rtread in + "/proc/net/route") RTREAD_METHOD="rtread_proc.o" + zebra_rtread="proc";; + "/dev/ip") RTREAD_METHOD="rtread_getmsg.o" + zebra_rtread="getmsg";; + *) RTREAD_METHOD="rtread_sysctl.o" + zebra_rtread="sysctl";; +esac +fi]) +AC_SUBST(RTREAD_METHOD) + +dnl ----------------------------- +dnl check interface lookup method +dnl ----------------------------- +AC_MSG_CHECKING(interface looking up method) +if test "$netlink" = yes; then + AC_MSG_RESULT(netlink) + IF_METHOD=if_netlink.o +else + if test "$opsys" = "sol2-6";then + AC_MSG_RESULT(solaris) + IF_METHOD=if_ioctl.o + elif test "$opsys" = "openbsd";then + AC_MSG_RESULT(openbsd) + IF_METHOD=if_ioctl.o + elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then + AC_MSG_RESULT(sysctl) + IF_METHOD=if_sysctl.o + AC_DEFINE(HAVE_NET_RT_IFLIST,,NET_RT_IFLIST) + else + AC_MSG_RESULT(ioctl) + IF_METHOD=if_ioctl.o + fi +fi +AC_SUBST(IF_METHOD) + +dnl ----------------------- +dnl check proc file system. +dnl ----------------------- +if test -r /proc/net/dev; then + AC_DEFINE(HAVE_PROC_NET_DEV,,/proc/net/dev) + IF_PROC=if_proc.o +fi + +if test -r /proc/net/if_inet6; then + AC_DEFINE(HAVE_PROC_NET_IF_INET6,,/proc/net/if_inet6) + IF_PROC=if_proc.o +fi +AC_SUBST(IF_PROC) + +dnl ----------------------------- +dnl check ipforward detect method +dnl ----------------------------- +AC_CACHE_CHECK(ipforward method check, zebra_ipforward_path, +[for zebra_ipforward_path in /proc/net/snmp /dev/ip /dev/null; +do + test x`ls $zebra_ipforward_path 2>/dev/null` = x"$zebra_ipforward_path" && break +done +case $zebra_ipforward_path in + "/proc/net/snmp") IPFORWARD=ipforward_proc.o + zebra_ipforward_path="proc";; + "/dev/ip") + case "$host" in + *-linux-*) IPFORWARD=ipforward_proc.o + zebra_ipforward_path="proc";; + *-nec-sysv4*) IPFORWARD=ipforward_ews.o + zebra_ipforward_path="ews";; + *) IPFORWARD=ipforward_solaris.o + zebra_ipforward_path="solaris";; + esac;; + *) IPFORWARD=ipforward_sysctl.o + zebra_ipforward_path="sysctl";; +esac]) +AC_SUBST(IPFORWARD) + +AC_CHECK_FUNCS(getaddrinfo, [have_getaddrinfo=yes], [have_getaddrinfo=no]) + +dnl ---------- +dnl IPv6 check +dnl ---------- +AC_MSG_CHECKING(whether does this OS have IPv6 stack) +if test "${enable_ipv6}" = "no"; then + AC_MSG_RESULT(disabled) +else +dnl ---------- +dnl INRIA IPv6 +dnl ---------- +if grep IPV6_INRIA_VERSION /usr/include/netinet/in.h >/dev/null 2>&1; then + zebra_cv_ipv6=yes + AC_DEFINE(HAVE_IPV6,,IPv6) + AC_DEFINE(INRIA_IPV6,,Inria IPv6) + RIPNGD="ripngd" + OSPF6D="ospf6d" + LIB_IPV6="" + AC_MSG_RESULT(INRIA IPv6) +fi +dnl --------- +dnl KAME IPv6 +dnl --------- +if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then + zebra_cv_ipv6=yes + AC_DEFINE(HAVE_IPV6,,IPv6) + AC_DEFINE(KAME,,KAME IPv6) + RIPNGD="ripngd" + OSPF6D="ospf6d" + if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then + LIB_IPV6="-L/usr/local/v6/lib -linet6" + fi + AC_MSG_RESULT(KAME) +fi +dnl --------- +dnl NRL check +dnl --------- +if grep NRL /usr/include/netinet6/in6.h >/dev/null 2>&1; then + zebra_cv_ipv6=yes + AC_DEFINE(HAVE_IPV6,,IPv6) + AC_DEFINE(NRL,,NRL) + RIPNGD="ripngd" + OSPF6D="ospf6d" + if test x"$opsys" = x"bsdi";then + AC_DEFINE(BSDI_NRL,,BSDI) + AC_MSG_RESULT(BSDI_NRL) + else + AC_MSG_RESULT(NRL) + fi +fi + +dnl ---------- +dnl Linux IPv6 +dnl ---------- +if test "${enable_ipv6}" = "yes"; then + AC_EGREP_CPP(yes, [ + #include + /* 2.1.128 or later */ + #if LINUX_VERSION_CODE >= 0x020180 + yes + #endif], + [zebra_cv_ipv6=yes; zebra_cv_linux_ipv6=yes;AC_MSG_RESULT(Linux IPv6)]) +else + if test x`ls /proc/net/ipv6_route 2>/dev/null` = x"/proc/net/ipv6_route" + then + zebra_cv_ipv6=yes + zebra_cv_linux_ipv6=yes + AC_MSG_RESULT(Linux IPv6) + fi +fi + +if test "$zebra_cv_linux_ipv6" = "yes";then + AC_DEFINE(HAVE_IPV6) + AC_MSG_CHECKING(for GNU libc 2.1) + AC_EGREP_CPP(yes, [ +#include +#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 + yes +#endif], [glibc=yes; AC_MSG_RESULT(yes)], AC_MSG_RESULT(no)) + AC_DEFINE(LINUX_IPV6,,Linux IPv6) + RIPNGD="ripngd" + OSPF6D="ospf6d" + if test "$glibc" != "yes"; then + INCLUDES="-I/usr/inet6/include" + if test x`ls /usr/inet6/lib/libinet6.a 2>/dev/null` != x;then + LIB_IPV6="-L/usr/inet6/lib -linet6" + fi + fi +fi + +dnl ----------------------- +dnl Set IPv6 related values +dnl ----------------------- +LIBS="$LIB_IPV6 $LIBS" +AC_SUBST(LIB_IPV6) + +if test x"$RIPNGD" = x""; then + AC_MSG_RESULT(IPv4 only) +fi +fi + +dnl ---------------------------- +dnl Check TCP Signature support. +dnl ---------------------------- +if test "${enable_tcp_signature}" = "yes"; then + AC_DEFINE(HAVE_TCP_SIGNATURE,,TCP Signature Option) + case "$host" in + *-linux-*) + AC_DEFINE(HAVE_LINUX_TCP_SIGNATURE,,Linux TCP Signature Option) + ;; + *-openbsd*) + AC_DEFINE(HAVE_OPENBSD_TCP_SIGNATURE,,OpenBSD TCP Signature Option) + ;; + *) + echo "Sorry, your OS don't support TCP signature." + exit 1 + ;; + esac +fi + +dnl -------------------- +dnl Daemon disable check +dnl -------------------- +if test "${enable_zebra}" = "no";then + ZEBRA="" +else + ZEBRA="zebra" +fi + +if test "${enable_bgpd}" = "no";then + BGPD="" +else + BGPD="bgpd" +fi + +if test "${enable_ripd}" = "no";then + RIPD="" +else + RIPD="ripd" +fi + +if test "${enable_ospfd}" = "no";then + OSPFD="" +else + OSPFD="ospfd" +fi + +case "${enable_ripngd}" in + "yes") RIPNGD="ripngd";; + "no" ) RIPNGD="";; + * ) ;; +esac + +case "${enable_ospf6d}" in + "yes") OSPF6D="ospf6d";; + "no" ) OSPF6D="";; + * ) ;; +esac + +if test "${enable_bgp_announce}" = "no";then + AC_DEFINE(DISABLE_BGP_ANNOUNCE,,Disable BGP installation to zebra) +fi + +AC_SUBST(ZEBRA) +AC_SUBST(BGPD) +AC_SUBST(RIPD) +AC_SUBST(RIPNGD) +AC_SUBST(OSPFD) +AC_SUBST(OSPF6D) +AC_SUBST(VTYSH) +AC_SUBST(INCLUDES) +AC_SUBST(CURSES) +AC_CHECK_LIB(c, inet_ntop, [AC_DEFINE(HAVE_INET_NTOP,,inet_ntop)]) +AC_CHECK_LIB(c, inet_pton, [AC_DEFINE(HAVE_INET_PTON,,inet_pton)]) +AC_CHECK_LIB(crypt, crypt) +AC_CHECK_LIB(resolv, res_init) +AC_CHECK_LIB(m, main) + +dnl --------------------------------------------------- +dnl BSD/OS 4.1 define inet_XtoY function as __inet_XtoY +dnl --------------------------------------------------- +AC_CHECK_FUNC(__inet_ntop, AC_DEFINE(HAVE_INET_NTOP)) +AC_CHECK_FUNC(__inet_pton, AC_DEFINE(HAVE_INET_PTON)) +AC_CHECK_FUNC(__inet_aton, AC_DEFINE(HAVE_INET_ATON)) + +dnl --------------------------- +dnl check system has GNU regexp +dnl --------------------------- +dnl AC_MSG_CHECKING(whether system has GNU regex) +AC_CHECK_LIB(c, regexec, +[AC_DEFINE(HAVE_GNU_REGEX,,GNU regexp library) + LIB_REGEX=""], +[LIB_REGEX="regex.o"]) +AC_SUBST(LIB_REGEX) + +dnl ------------------ +dnl check SNMP library +dnl ------------------ +if test "${enable_snmp}" = "yes"; then + saved_libs="${LIBS}" + LIBS="" + + unset link_dir link_dirs + test "${linkbase_specified}" = "yes" && link_dirs=${with_linkbase} + link_dirs="$link_dirs /usr/local" + for link_dir in '' ${link_dirs}; do + test "x${link_dir}" != "x" && link_dir="-L${link_dir}/lib" + LIBS=${link_dir} + + AC_MSG_NOTICE(try linking with LIBS: $LIBS) + unset ac_cv_lib_netsnmp_asn_parse_int + AC_CHECK_LIB(netsnmp, asn_parse_int, + [HAVE_SNMP=yes; ac_snmp_lib="$LIBS -lnetsnmp"]) + test "${HAVE_SNMP}" = "yes" && break + + unset ac_cv_lib_snmp_asn_parse_int + AC_CHECK_LIB(snmp, asn_parse_int, + [HAVE_SNMP=yes; ac_snmp_lib="$LIBS -lsnmp"]) + test "${HAVE_SNMP}" = "yes" && break + + AC_CHECK_LIB(crypto, main, [NEED_CRYPTO=yes]) + test "${NEED_CRYPTO}" != "yes" && continue + LIBS="$LIBS -lcrypto" + + AC_MSG_NOTICE(try linking with LIBS: $LIBS) + unset ac_cv_lib_netsnmp_asn_parse_int + AC_CHECK_LIB(netsnmp, asn_parse_int, + [HAVE_SNMP=yes; ac_snmp_lib="$LIBS -lnetsnmp"],, -lcrypto) + test "${HAVE_SNMP}" = "yes" && break + + unset ac_cv_lib_snmp_asn_parse_int + AC_CHECK_LIB(snmp, asn_parse_int, + [HAVE_SNMP=yes; ac_snmp_lib="$LIBS -lsnmp"],, -lcrypto) + test "${HAVE_SNMP}" = "yes" && break + done + if test "${HAVE_SNMP}" = ""; then + AC_MSG_ERROR(cannot find valid snmp library) + fi + LIBS="${saved_libs} $ac_snmp_lib" + + AC_MSG_CHECKING(for snmp library header) + unset link_dir link_dirs ac_snmp ac_snmps ac_snmp_dir ac_snmp_dirs + link_dirs="/usr/include"; + if test "${linkbase_specified}" = "yes"; then + link_dirs="${link_dirs} ${with_linkbase}/include" + fi + link_dirs="${link_dirs} /usr/local/include" + ac_snmp_dirs="net-snmp net-snmp/library ucd-snmp" + + for link_dir in '' ${link_dirs}; do + test -z $link_dir && continue + for ac_snmp_dir in '' ${ac_snmp_dirs}; do + test -z $ac_snmp_dir && continue + ac_snmps="${ac_snmps} ${link_dir}/${ac_snmp_dir}/asn1.h" + done + done + ac_snmps="${ac_snmps}" + + for ac_snmp in '' ${ac_snmps}; do + test -z ${ac_snmp} && continue + test -f ${ac_snmp} && break + done + ac_snmp_header=`echo ${ac_snmp} | sed -e 's/\/asn1.h//'` + ac_snmp_header="-I${ac_snmp_header}" + + case ${ac_snmp} in + /usr/local/include/net-snmp/*) + AC_DEFINE(HAVE_SNMP,,SNMP) + AC_DEFINE(HAVE_NETSNMP,,NET-SNMP) + CFLAGS="${CFLAGS} -I/usr/local/include" + ;; + */net-snmp/*) + AC_DEFINE(HAVE_SNMP,,SNMP) + AC_DEFINE(HAVE_NETSNMP,,NET-SNMP) + ;; + /usr/local/include/ucd-snmp/*) + AC_DEFINE(HAVE_SNMP,,SNMP) + CFLAGS="${CFLAGS} -I/usr/local/include" + ;; + */ucd-snmp/*) + AC_DEFINE(HAVE_SNMP,,SNMP) + ;; + esac + AC_MSG_RESULT($ac_snmp_header) + CFLAGS="${CFLAGS} ${ac_snmp_header}" +fi + +dnl ---------------------------- +dnl check sa_len of sockaddr +dnl ---------------------------- +AC_MSG_CHECKING(whether struct sockaddr has a sa_len field) +AC_TRY_COMPILE([#include +#include +],[static struct sockaddr ac_i;int ac_j = sizeof (ac_i.sa_len);], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SA_LEN,,sa_len)], + AC_MSG_RESULT(no)) + +dnl ---------------------------- +dnl check sin_len of sockaddr_in +dnl ---------------------------- +AC_MSG_CHECKING(whether struct sockaddr_in has a sin_len field) +AC_TRY_COMPILE([#include +#include +],[static struct sockaddr_in ac_i;int ac_j = sizeof (ac_i.sin_len);], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SIN_LEN,,sin_len)], + AC_MSG_RESULT(no)) + +dnl ---------------------------- +dnl check sun_len of sockaddr_un +dnl ---------------------------- +AC_MSG_CHECKING(whether struct sockaddr_un has a sun_len field) +AC_TRY_COMPILE([#include +#include +],[static struct sockaddr_un ac_i;int ac_j = sizeof (ac_i.sun_len);], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SUN_LEN,,sun_len)], + AC_MSG_RESULT(no)) + +dnl ----------------------------------- +dnl check sin6_scope_id of sockaddr_in6 +dnl ----------------------------------- +if test "$zebra_cv_ipv6" = yes; then + AC_MSG_CHECKING(whether struct sockaddr_in6 has a sin6_scope_id field) + AC_TRY_COMPILE([#include +#include +],[static struct sockaddr_in6 ac_i;int ac_j = sizeof (ac_i.sin6_scope_id);], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SIN6_SCOPE_ID,,scope id)], + AC_MSG_RESULT(no)) +fi + +dnl ----------------------------------- +dnl check in6addr_loopback global variable +dnl ----------------------------------- +if test "$zebra_cv_ipv6" = yes; then + AC_MSG_CHECKING(whether in6addr_loopback is usable) + AC_TRY_COMPILE([#include +#include +],[static struct in6_addr ac_i; ac_i = in6addr_loopback;], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IN6ADDR_GLOBAL,,in6addr global variables e.g. in6addr_loopback)], + AC_MSG_RESULT(no)) +fi + +dnl ---------------------------- +dnl check socklen_t exist or not +dnl ---------------------------- +AC_MSG_CHECKING(whther socklen_t is defined) +AC_TRY_COMPILE([#include +#include +#include +],[socklen_t ac_x;], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SOCKLEN_T,,socklen_t)], + AC_MSG_RESULT(no)) + +dnl ------------------------ +dnl check struct sockaddr_dl +dnl ------------------------ +AC_MSG_CHECKING(whether struct sockaddr_dl exist) +AC_EGREP_HEADER(sockaddr_dl, +net/if_dl.h, +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SOCKADDR_DL,,sockaddr_dl)], + AC_MSG_RESULT(no)) + +dnl -------------------------- +dnl check structure ifaliasreq +dnl -------------------------- +AC_MSG_CHECKING(whether struct ifaliasreq exist) +AC_EGREP_HEADER(ifaliasreq, +net/if.h, +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IFALIASREQ,,ifaliasreq)], + AC_MSG_RESULT(no)) + +dnl ---------------------------- +dnl check structure in6_aliasreq +dnl ---------------------------- +AC_MSG_CHECKING(whether struct if6_aliasreq exist) +AC_EGREP_HEADER(in6_aliasreq, +netinet6/in6_var.h, +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IN6_ALIASREQ,,in6_aliasreq)], + AC_MSG_RESULT(no)) + +dnl --------------------------- +dnl check structure rt_addrinfo +dnl --------------------------- +AC_MSG_CHECKING(whether struct rt_addrinfo exist) +AC_EGREP_HEADER(rt_addrinfo, +net/route.h, +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RT_ADDRINFO,,rt_addrinfo)], + AC_MSG_RESULT(no)) + +dnl -------------------------- +dnl check structure in_pktinfo +dnl -------------------------- +AC_MSG_CHECKING(whether struct in_pktinfo exist) +AC_TRY_COMPILE([#include +],[struct in_pktinfo ac_x;], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_INPKTINFO,,in_pktinfo)], + AC_MSG_RESULT(no)) + +dnl -------------------------------------- +dnl checking for getrusage struct and call +dnl -------------------------------------- +AC_MSG_CHECKING(whether getrusage is available) +AC_TRY_COMPILE([#include +],[struct rusage ac_x; getrusage (RUSAGE_SELF, &ac_x);], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RUSAGE,,rusage)], + AC_MSG_RESULT(no)) + +dnl ------------- +dnl check version +dnl ------------- +file="${srcdir}/lib/version.h" +VERSION=`sed -ne 's/^#.*ZEBRA_VERSION.*\"\([^\"]*\)\"$/\1/p' $file` +AC_SUBST(VERSION) + +dnl ------------------------------ +dnl set paths for process id files +dnl ------------------------------ +AC_CACHE_CHECK(pid file directory,ac_piddir, +[for ZEBRA_PID_DIR in /var/run dnl + /var/adm dnl + /etc dnl + /dev/null; +do + test -d $ZEBRA_PID_DIR && break +done +ac_piddir=$ZEBRA_PID_DIR +if test $ZEBRA_PID_DIR = "/dev/null"; then + echo "PID DIRECTORY NOT FOUND!" +fi]) +AC_DEFINE_UNQUOTED(PATH_ZEBRA_PID, "$ac_piddir/zebra.pid",zebra PID) +AC_DEFINE_UNQUOTED(PATH_RIPD_PID, "$ac_piddir/ripd.pid",ripd PID) +AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$ac_piddir/ripngd.pid",ripngd PID) +AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$ac_piddir/bgpd.pid",bgpd PID) +AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$ac_piddir/ospfd.pid",ospfd PID) +AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$ac_piddir/ospf6d.pid",ospf6d PID) + + +dnl --------------------------- +dnl Check htonl works correctly +dnl --------------------------- +AC_MSG_CHECKING(for working htonl) +AC_CACHE_VAL(ac_cv_htonl_works, [ +AC_TRY_LINK([#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif], +[htonl (0);], +ac_cv_htonl_works=yes, +ac_cv_htonl_works=no)]) +AC_MSG_RESULT($ac_cv_htonl_works) + +AC_OUTPUT(Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile ospf6d/Makefile vtysh/Makefile doc/Makefile) + +echo " +zebra configuration +------------------- +zebra version : ${VERSION} +host operationg system : ${host_os} +source code location : ${srcdir} +compiler : ${CC} +compiler flags : ${CFLAGS} +link libraries : ${LIBS} +directory for pid files : ${ac_piddir} +" diff --git a/depcomp b/depcomp new file mode 100755 index 0000000..807b991 --- /dev/null +++ b/depcomp @@ -0,0 +1,423 @@ +#! /bin/sh + +# depcomp - compile a program generating dependencies as side-effects +# Copyright 1999, 2000 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi +# `libtool' can also be set to `yes' or `no'. + +if test -z "$depfile"; then + base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'` + dir=`echo "$object" | sed 's,/.*$,/,'` + if test "$dir" = "$object"; then + dir= + fi + # FIXME: should be _deps on DOS. + depfile="$dir.deps/$base" +fi + +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. This file always lives in the current directory. + # Also, the AIX compiler puts `$object:' at the start of each line; + # $object doesn't have directory information. + stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + outname="$stripped.o" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + tmpdepfile1="$dir.libs/$base.lo.d" + tmpdepfile2="$dir.libs/$base.d" + "$@" -Wc,-MD + else + tmpdepfile1="$dir$base.o.d" + tmpdepfile2="$dir$base.d" + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + if test -f "$tmpdepfile1"; then + tmpdepfile="$tmpdepfile1" + else + tmpdepfile="$tmpdepfile2" + fi + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a space and a tab in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. We will use -o /dev/null later, + # however we can't do the remplacement now because + # `-o $object' might simply not be used + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + "$@" -o /dev/null $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + -*) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 diff --git a/doc/BGP-TypeCode b/doc/BGP-TypeCode new file mode 100644 index 0000000..0904e19 --- /dev/null +++ b/doc/BGP-TypeCode @@ -0,0 +1,24 @@ + + BGP-4[+] UPDATE Attribute TypeCode list + + Value Attribute References +========================================================================= + 1 ORIGIN [RFC 1771] + 2 AS_PATH [RFC 1771] + 3 NEXT_HOP [RFC 1771] + 4 MULTI_EXIT_DISC [RFC 1771] + 5 LOCAL_PREF [RFC 1771] + 6 ATOMIC_AGGREGATE [RFC 1771] + 7 AGGREGATOR [RFC 1771] + 8 COMMUNITIES [RFC 1997] + 9 ORIGINATOR_ID [RFC 1966] + 10 CLUSTER_LIST [RFC 1966] + 11 DPA [draft-ietf-idr-bgp-dpa-05.txt(expired)] + 12 ADVERTISER [Changed from RFC 1863 bgp@ans.net ML?] + 13 RCID_PATH [Changed from RFC 1863 bgp@ans.net ML?] + 14 MP_REACH_NLRI [RFC 2283] + 15 MP_UNREACH_NLRI [RFC 2283] + 16 EXT_COMMUNITIES [draft-ramachandra-bgp-ext-communities-09.txt] + 254 RCID_PATH [RFC 1863] + 255 ADVERTISER [RFC 1863] +========================================================================= diff --git a/doc/ChangeLog b/doc/ChangeLog new file mode 100644 index 0000000..8aa0c80 --- /dev/null +++ b/doc/ChangeLog @@ -0,0 +1,94 @@ +2003-01-22 Christian Hammers + + * ospfd.texi (OSPF router, OSPF router): Add description. + +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2001-02-07 Pekka Savola + + * Correct bad English ;-). + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 released. + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 released. + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 released. + +2000-10-02 Horms + + * Makefile.am: Fix texinfo file installation problem. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 released. + + * ospfd.texi (Redistribute routes to OSPF): distance <1-255> + @var{source} command is temporary disabled. So it is removed from + document. + +2000-07-04 Kunihiro Ishiguro + + * vtysh.1: Add man entry for vtysh. + + * bgpd.1: Change section to 8. + * ospfd.1: Likewise. + * ospf6d.1: Likewise. + * ripd.1: Likewise. + * ripngd.1: Likewise. + * zebra.1: Likewise. + +1999-09-01 "A.Waddington" + + * zebra.texi: Replace @command with @code until it gets ready. + Remove @macro. + +1999-08-26 Andrew Waddington + + * bgpd.1: Add man page. + ospf6d.1: Likewise. + ospfd.1: Likewise. + ripd.1: Likewise. + ripngd.1: Likewise. + zebra.1: Likewise. + +1999-08-14 Andrew Waddington + + * zebra.texi: Many typo is fixed. Some grammatical rectifications + is made. + +1999-07-27 Gerhard Poul + + * zebra.texi: Update zebra.texi. + +1999-07-02 Gerhard Poul + + * draft-zebra-00.ms: New file added. This is groff version of + draft-zebra-00.txt. This is a master file of draft-zebra-00.txt. + + * draft-zebra-00.txt: Generated from draft-zebra-00.txt. + +1999-05-07 Kunihiro Ishiguro + + * zebra.texi (Top): Add ospf6d chapter. + +1999-03-31 Jeroen Ruigrok/Asmodai + + * zebra.texi: Improve some sections. + +1999-03-04 Kunihiro Ishiguro + + * archfig.tex, zebra.sty, zebra.tex: Temporary removed due to the + description is out of date. + +1999-02-24 Kunihiro Ishiguro + + * texinfo.tex: New file added. Automake complains the absence of + texinfo.tex. diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..ee49cbd --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,14 @@ +## Process this file with automake to produce Makefile.in. + +info_TEXINFOS = zebra.texi + +zebra_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi install.texi \ + ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi overview.texi \ + protocol.texi ripd.texi ripngd.texi routemap.texi snmp.texi vtysh.texi + +man_MANS = vtysh.1 bgpd.8 ospf6d.8 ospfd.8 ripd.8 ripngd.8 zebra.8 + +EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt $(man_MANS) + +draft-zebra-00.txt: + groff -T ascii -ms draft-zebra-00.ms > draft-zebra-00.txt diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 0000000..e7f706e --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,431 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CPP = @CPP@ +CURSES = @CURSES@ +DEPDIR = @DEPDIR@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ +INCLUDES = @INCLUDES@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LIBPAM = @LIBPAM@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ + +info_TEXINFOS = zebra.texi + +zebra_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi install.texi \ + ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi overview.texi \ + protocol.texi ripd.texi ripngd.texi routemap.texi snmp.texi vtysh.texi + + +man_MANS = vtysh.1 bgpd.8 ospf6d.8 ospfd.8 ripd.8 ripngd.8 zebra.8 + +EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt $(man_MANS) +subdir = doc +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = +INFO_DEPS = zebra.info +DVIS = zebra.dvi +TEXINFOS = zebra.texi + +NROFF = nroff +MANS = $(man_MANS) +DIST_COMMON = $(zebra_TEXINFOS) ChangeLog Makefile.am Makefile.in \ + texinfo.tex +all: all-am + +.SUFFIXES: +.SUFFIXES: .dvi .info .ps .texi +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign doc/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +zebra.info: zebra.texi $(zebra_TEXINFOS) +zebra.dvi: zebra.texi $(zebra_TEXINFOS) + +.texi.info: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) \ + `echo $< | sed 's,.*/,,'` + +.texi.dvi: + TEXINPUTS="$(srcdir)$(PATH_SEPARATOR)$$TEXINPUTS" \ + MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ + $(TEXI2DVI) $< + +.texi: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) \ + `echo $< | sed 's,.*/,,'` + +MAKEINFO = @MAKEINFO@ +TEXI2DVI = texi2dvi +DVIPS = dvips +.dvi.ps: + $(DVIPS) $< -o $@ + +uninstall-info-am: + $(PRE_UNINSTALL) + @if (install-info --version && \ + install-info --version | fgrep -i -v debian) >/dev/null 2>&1; then \ + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + echo " install-info --info-dir=$(DESTDIR)$(infodir) --remove $(DESTDIR)$(infodir)/$$file"; \ + install-info --info-dir=$(DESTDIR)$(infodir) --remove $(DESTDIR)$(infodir)/$$file; \ + done; \ + else :; fi + @$(NORMAL_UNINSTALL) + @list='$(INFO_DEPS)'; \ + for file in $$list; do \ + (if cd $(DESTDIR)$(infodir); then \ + echo " rm -f $$file $$file-[0-9] $$file-[0-9][0-9])"; \ + rm -f $$file $$file-[0-9] $$file-[0-9][0-9]; \ + else :; fi); \ + done + +dist-info: $(INFO_DEPS) + list='$(INFO_DEPS)'; \ + for base in $$list; do \ + d=$(srcdir); \ + for file in $$d/$$base*; do \ + relfile=`expr "$$file" : "$$d/\(.*\)"`; \ + test -f $(distdir)/$$relfile || \ + cp -p $$file $(distdir)/$$relfile; \ + done; \ + done + +mostlyclean-aminfo: + -rm -f zebra.aux zebra.cp zebra.cps zebra.dvi zebra.fn zebra.ky zebra.log \ + zebra.op zebra.pg zebra.ps zebra.tmp zebra.toc zebra.tp \ + zebra.vr + +maintainer-clean-aminfo: + cd $(srcdir) && \ + list='$(INFO_DEPS)'; for i in $$list; do \ + rm -f $$i; \ + if test "`echo $$i-[0-9]*`" != "$$i-[0-9]*"; then \ + rm -f $$i-[0-9]*; \ + fi; \ + done + +man1dir = $(mandir)/man1 +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(man1dir) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \ + rm -f $(DESTDIR)$(man1dir)/$$inst; \ + done + +man8dir = $(mandir)/man8 +install-man8: $(man8_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(man8dir) + @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 8*) ;; \ + *) ext='8' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ + done +uninstall-man8: + @$(NORMAL_UNINSTALL) + @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ + rm -f $(DESTDIR)$(man8dir)/$$inst; \ + done +tags: TAGS +TAGS: + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="${top_distdir}" distdir="$(distdir)" \ + dist-info +check-am: all-am +check: check-am +all-am: Makefile $(INFO_DEPS) $(MANS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(infodir) $(DESTDIR)$(man1dir) $(DESTDIR)$(man8dir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: $(DVIS) + +info: info-am + +info-am: $(INFO_DEPS) + +install-data-am: install-info-am install-man + +install-exec-am: + +install-info: install-info-am + +install-info-am: $(INFO_DEPS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(infodir) + @list='$(INFO_DEPS)'; \ + for file in $$list; do \ + d=$(srcdir); \ + for ifile in echo $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9]; do \ + if test -f $$ifile; then \ + relfile=`expr "$$ifile" : "$$d/\(.*\)"`; \ + echo " $(INSTALL_DATA) $$ifile $(DESTDIR)$(infodir)/$$relfile"; \ + $(INSTALL_DATA) $$ifile $(DESTDIR)$(infodir)/$$relfile; \ + else : ; fi; \ + done; \ + done + @$(POST_INSTALL) + @if (install-info --version && \ + install-info --version | fgrep -i -v debian) >/dev/null 2>&1; then \ + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + echo " install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file";\ + install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file || :;\ + done; \ + else : ; fi +install-man: install-man1 install-man8 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-aminfo \ + maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-aminfo mostlyclean-generic + +uninstall-am: uninstall-info-am uninstall-man + +uninstall-man: uninstall-man1 uninstall-man8 + +.PHONY: all all-am check check-am clean clean-generic dist-info \ + distclean distclean-generic distdir dvi dvi-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-man1 install-man8 install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-aminfo maintainer-clean-generic mostlyclean \ + mostlyclean-aminfo mostlyclean-generic uninstall uninstall-am \ + uninstall-info-am uninstall-man uninstall-man1 uninstall-man8 + + +draft-zebra-00.txt: + groff -T ascii -ms draft-zebra-00.ms > draft-zebra-00.txt +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/doc/appendix.texi b/doc/appendix.texi new file mode 100644 index 0000000..7a052bc --- /dev/null +++ b/doc/appendix.texi @@ -0,0 +1,238 @@ +@node Packet Binary Dump Format, , Zebra Protocol, Top +@comment node-name, next, previous, up +@appendix Packet Binary Dump Format + + Zebra can dump routing protocol packet into file with a binary format +(@pxref{Dump BGP packets and table}). + + It seems to be better that we share the MRT's header format for +backward compatibility with MRT's dump logs. We should also define the +binary format excluding the header, because we must support both IP +v4 and v6 addresses as socket addresses and / or routing entries. + + In the last meeting, we discussed to have a version field in the +header. But Masaki told us that we can define new `type' value rather +than having a `version' field, and it seems to be better because we +don't need to change header format. + + Here is the common header format. This is same as that of MRT. + +@example +@group +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Time | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Type | Subtype | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Length | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + + If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE, and +Address Family == IP (version 4) + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source AS number | Destination AS number | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Interface Index | Address Family | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Old State | New State | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + +Where State is the value defined in RFC1771. + +If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE, +and Address Family == IP version 6 + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source AS number | Destination AS number | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Interface Index | Address Family | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Old State | New State | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + +If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE, +and Address Family == IP (version 4) + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source AS number | Destination AS number | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Interface Index | Address Family | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| BGP Message Packet | +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + +Where BGP Message Packet is the whole contents of the +BGP4 message including header portion. + +If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE, +and Address Family == IP version 6 + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source AS number | Destination AS number | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Interface Index | Address Family | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Source IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Destination IP address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| BGP Message Packet | +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + +If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY, +and Address Family == IP (version 4) + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| View # | Status | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Time Last Change | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Address Family | SAFI | Next-Hop-Len | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Next Hop Address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Prefix Length | Address Prefix [variable] | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Attribute Length | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| BGP Attribute [variable length] | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + +If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY, +and Address Family == IP version 6 + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| View # | Status | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Time Last Change | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Address Family | SAFI | Next-Hop-Len | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Next Hop Address | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Next Hop Address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Next Hop Address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Next Hop Address (Cont'd) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Prefix Length | Address Prefix [variable] | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Address Prefix (cont'd) [variable] | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Attribute Length | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| BGP Attribute [variable length] | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + + BGP4 Attribute must not contain MP_UNREACH_NLRI. + If BGP Attribute has MP_REACH_NLRI field, it must has + zero length NLRI, e.g., MP_REACH_NLRI has only Address + Family, SAFI and next-hop values. + +If `type' is PROTOCOL_BGP4MP and `subtype' is BGP4MP_SNAPSHOT, + +@example +@group + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| View # | File Name [variable] | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + + The file specified in "File Name" contains all routing entries, + which are in the format of ``subtype == BGP4MP_ENTRY''. + +@example +@group +Constants: + /* type value */ + #define MSG_PROTOCOL_BGP4MP 16 + /* subtype value */ + #define BGP4MP_STATE_CHANGE 0 + #define BGP4MP_MESSAGE 1 + #define BGP4MP_ENTRY 2 + #define BGP4MP_SNAPSHOT 3 +@end group +@end example diff --git a/doc/basic.texi b/doc/basic.texi new file mode 100644 index 0000000..8812b78 --- /dev/null +++ b/doc/basic.texi @@ -0,0 +1,510 @@ +@node Basic commands +@comment node-name, next, previous, up +@chapter Basic commands + +There are five routing daemons in use, and there is one manager daemon. +These daemons may be located on separate machines from the manager +daemon. Each of these daemons will listen on a particular port for +incoming VTY connections. The routing daemons are: + +@itemize @bullet +@item @command{ripd}, @command{ripngd}, @command{ospfd}, @command{ospf6d}, @command{bgpd} +@item @command{zebra} +@end itemize + +The following sections discuss commands common to all the routing +daemons. + +@menu +* Config Commands:: Commands used in config files +* Common Invocation Options:: Starting the daemons +* Virtual Terminal Interfaces:: Interacting with the daemons +@end menu + + + +@node Config Commands, Common Invocation Options, Basic commands, Basic commands +@comment node-name, next, previous, up +@section Config Commands + +@cindex Configuration files for running the software +@c A -not configuration files for installing the software +@cindex Files for running configurations +@cindex Modifying the herd's behavior +@cindex Getting the herd running + + +@menu +* Basic Config Commands:: Some of the generic config commands +* Sample Config File:: An example config file +@end menu + + +In a config file, you can write the debugging options, a vty's password, +routing daemon configurations, a log file name, and so forth. This +information forms the initial command set for a routing beast as it is +starting. + +Config files are generally found in: + +@itemize @asis +@item @file{@value{INSTALL_PREFIX_ETC}/*.conf} +@end itemize + +Each of the daemons has its own +config file. For example, zebra's default config file name is: + +@itemize @asis +@item @file{@value{INSTALL_PREFIX_ETC}/zebra.conf} +@end itemize + +The daemon name plus @file{.conf} is the default config file name. You +can specify a config file using the @kbd{-f} or @kbd{--config-file} +options when starting the daemon. + + + +@node Basic Config Commands, Sample Config File, Config Commands, Config Commands +@comment node-name, next, previous, up +@subsection Basic Config Commands + +@deffn Command {hostname @var{hostname}} {} +Set hostname of the router. +@end deffn + +@deffn Command {password @var{password}} {} +Set password for vty interface. If there is no password, a vty won't +accept connections. +@end deffn + +@deffn Command {enable password @var{password}} {} +Set enable password. +@end deffn + +@deffn Command {log stdout} {} +@deffnx Command {no log stdout} {} +Set logging output to stdout. +@end deffn + +@deffn Command {log file @var{filename}} {} +If you want to log into a file please specify @code{filename} as +follows. +@example +log file /usr/local/etc/bgpd.log +@end example +@end deffn + +@deffn Command {log syslog} {} +@deffnx Command {no log syslog} {} +Set logging output to syslog. +@end deffn + +@deffn Command {write terminal} {} +Displays the current configuration to the vty interface. +@end deffn + +@deffn Command {write file} {} +Write current configuration to configuration file. +@end deffn + +@deffn Command {configure terminal} {} +Change to configuration mode. This command is the first step to +configuration. +@end deffn + +@deffn Command {terminal length @var{<0-512>}} {} +Set terminal display length to @var{<0-512>}. If length is 0, no +display control is performed. +@end deffn + +@deffn Command {who} {} +@end deffn + +@deffn Command {list} {} +List commands. +@end deffn + +@deffn Command {service password-encryption} {} +Encrypt password. +@end deffn + +@deffn Command {service advanced-vty} {} +Enable advanced mode VTY. +@end deffn + +@deffn Command {service terminal-length @var{<0-512>}} {} +Set system wide line configuration. This configuration command applies +to all VTY interfaces. +@end deffn + +@deffn Command {show version} {} +Show the current version of the Zebra and its build host information. +@end deffn + +@deffn Command {line vty} {} +Enter vty configuration mode. +@end deffn + +@deffn Command {banner motd default} {} +Set default motd string. +@end deffn + +@deffn Command {no banner motd} {} +No motd banner string will be printed. +@end deffn + +@deffn {Line Command} {exec-timeout @var{minute}} {} +@deffnx {Line Command} {exec-timeout @var{minute} @var{second}} {} +Set VTY connection timeout value. When only one argument is specified +it is used for timeout value in minutes. Optional second argument is +used for timeout value in seconds. Default timeout value is 10 minutes. +When timeout value is zero, it means no timeout. +@end deffn + +@deffn {Line Command} {no exec-timeout} {} +Do not perform timeout at all. This command is as same as +@command{exec-timeout 0 0}. +@end deffn + +@deffn {Line Command} {access-class @var{access-list}} {} +Restrict vty connections with an access list. +@end deffn + + + +@node Sample Config File, , Basic Config Commands, Config Commands +@comment node-name, next, previous, up +@subsection Sample Config File + + +Below is a sample configuration file for the zebra daemon. + +@example +@group +! +! Zebra configuration file +! +hostname Router +password zebra +enable password zebra +! +log stdout +! +! +@end group +@end example + +'!' and '#' are comment characters. If the first character of the word +is one of the comment characters then from the rest of the line forward +will be ignored as a comment. + +@example +password zebra!password +@end example + +If a comment character is not the first character of the word, it's a +normal character. So in the above example '!' will not be regarded as a +comment and the password is set to 'zebra!password'. + + + +@node Common Invocation Options, Virtual Terminal Interfaces, Config Commands, Basic commands +@comment node-name, next, previous, up +@section Common Invocation Options +@c COMMON_OPTIONS +@c OPTIONS section of the man page + +These options apply to all Zebra daemons. + +@table @samp + +@item -d +@itemx --daemon +Runs in daemon mode. + +@item -f @var{file} +@itemx --config_file=@var{file} +Set configuration file name. + +@item -h +@itemx --help +Display this help and exit. + +@item -i @var{file} +@itemx --pid_file=@var{file} + +Upon startup the process identifier of the daemon is written to a file, +typically in @file{/var/run}. This file can be used by the init system +to implement commands such as @command{@dots{}/init.d/zebra status}, +@command{@dots{}/init.d/zebra restart} or @command{@dots{}/init.d/zebra +stop}. + +The file name is an run-time option rather than a configure-time option +so that multiple routing daemons can be run simultaneously. This is +useful when using Zebra to implement a routing looking glass. One +machine can be used to collect differing routing views from differing +points in the network. + +@item -P @var{port} +@itemx --vty_port=@var{port} +Set the VTY port number. + +@item -v +@itemx --version +Print program version. + +@end table + + + +@node Virtual Terminal Interfaces, , Common Invocation Options, Basic commands +@comment node-name, next, previous, up +@section Virtual Terminal Interfaces + +VTY -- Virtual Terminal [aka TeletYpe] Interface is a command line +interface (CLI) for user interaction with the routing daemon. + +@menu +* VTY Overview:: Basics about VTYs +* VTY Modes:: View, Enable, and Other VTY modes +* VTY CLI Commands:: Commands for movement, edition, and management +@end menu + + + +@node VTY Overview, VTY Modes, Virtual Terminal Interfaces, Virtual Terminal Interfaces +@comment node-name, next, previous, up +@subsection VTY Overview + + +VTY stands for Virtual TeletYpe interface. It means you can connect to +the daemon via the telnet protocol. + +To enable a VTY interface, you have to setup a VTY password. If there +is no VTY password, one cannot connect to the VTY interface at all. + +@example +@group +% telnet localhost 2601 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + +Hello, this is zebra (version @value{VERSION}) +Copyright 1997-2000 Kunihiro Ishiguro + + +User Access Verification + +Password: XXXXX +Router> ? + enable Turn on privileged commands + exit Exit current mode and down to previous mode + help Description of the interactive help system + list Print command list + show Show running system information + who Display who is on a vty +Router> enable +Password: XXXXX +Router# configure terminal +Router(config)# interface eth0 +Router(config-if)# ip address 10.0.0.1/8 +Router(config-if)# ^Z +Router# +@end group +@end example + +'?' is very useful for looking up commands. + + + +@node VTY Modes, VTY CLI Commands, VTY Overview, Virtual Terminal Interfaces +@comment node-name, next, previous, up +@subsection VTY Modes + + +There are three basic VTY modes: + +@menu +* VTY View Mode:: Mode for read-only interaction +* VTY Enable Mode:: Mode for read-write interaction +* VTY Other Modes:: Special modes (tftp, etc) +@end menu + +There are commands that may be restricted to specific VTY modes. + + + +@node VTY View Mode, VTY Enable Mode, VTY Modes, VTY Modes +@comment node-name, next, previous, up +@subsubsection VTY View Mode +@c to be written (gpoul) + + +This mode is for read-only access to the CLI. One may exit the mode by +leaving the system, or by entering @code{enable} mode. + + + +@node VTY Enable Mode, VTY Other Modes, VTY View Mode, VTY Modes +@comment node-name, next, previous, up +@subsubsection VTY Enable Mode + + +@c to be written (gpoul) +This mode is for read-write access to the CLI. One may exit the mode by +leaving the system, or by escaping to view mode. + + + +@node VTY Other Modes, , VTY Enable Mode, VTY Modes +@comment node-name, next, previous, up +@subsubsection VTY Other Modes + + +@c to be written (gpoul) +This page is for describing other modes. + +@node VTY CLI Commands, , VTY Modes, Virtual Terminal Interfaces +@comment node-name, next, previous, up +@subsection VTY CLI Commands + + +Commands that you may use at the command-line are described in the following three subsubsections. + +@menu +* CLI Movement Commands:: Commands for moving the cursor about +* CLI Editing Commands:: Commands for changing text +* CLI Advanced Commands:: Other commands, session management and so on +@end menu + + + +@node CLI Movement Commands, CLI Editing Commands, VTY CLI Commands, VTY CLI Commands +@comment node-name, next, previous, up +@subsubsection CLI Movement Commands + + +These commands are used for moving the CLI cursor. The @key{C} character +means press the Control Key. + +@table @kbd + +@item C-f +@itemx @key{RIGHT} +@kindex C-f +@kindex @key{RIGHT} +Move forward one character. + +@item C-b +@itemx @key{LEFT} +@kindex C-b +@kindex @key{LEFT} +Move backward one character. + +@item M-f +@kindex M-f +Move forward one word. + +@item M-b +@kindex M-b +Move backward one word. + +@item C-a +@kindex C-a +Move to the beginning of the line. + +@item C-e +@kindex C-e +Move to the end of the line. + +@end table + + + +@node CLI Editing Commands, CLI Advanced Commands, CLI Movement Commands, VTY CLI Commands +@comment node-name, next, previous, up +@subsubsection CLI Editing Commands + + +These commands are used for editing text on a line. The @key{C} +character means press the Control Key. + +@table @kbd + +@item C-h +@itemx @key{DEL} +@kindex C-h +@kindex @key{DEL} +Delete the character before point. + +@item C-d +@kindex C-d +Delete the character after point. + +@item M-d +@kindex M-d +Forward kill word. + +@item C-w +@kindex C-w +Backward kill word. + +@item C-k +@kindex C-k +Kill to the end of the line. + +@item C-u +@kindex C-u +Kill line from the beginning, erasing input. + +@item C-t +@kindex C-t +Transpose character. + +@end table + + + +@node CLI Advanced Commands, , CLI Editing Commands, VTY CLI Commands +@comment node-name, next, previous, up +@subsubsection CLI Advanced Commands + + +There are several additional CLI commands for command line completions, +insta-help, and VTY session management. + +@table @kbd + +@item C-c +@kindex C-c +Interrupt current input and moves to the next line. + +@item C-z +@kindex C-z +End current configuration session and move to top node. + + +@item C-n +@itemx @key{DOWN} +@kindex C-n +@kindex @key{DOWN} +Move down to next line in the history buffer. + +@item C-p +@itemx @key{UP} +@kindex C-p +@kindex @key{UP} +Move up to previous line in the history buffer. + +@item TAB +@kindex @key{TAB} +Use command line completion by typing @key{TAB}. + +@item +@kindex ? +You can use command line help by typing @code{help} at the beginning of +the line. Typing @kbd{?} at any point in the line will show possible +completions. + +@end table diff --git a/doc/bgpd.8 b/doc/bgpd.8 new file mode 100644 index 0000000..cba3bda --- /dev/null +++ b/doc/bgpd.8 @@ -0,0 +1,169 @@ +.TH BGPD 8 "July 2000" "Zebra Beast - BGPD" "Version 0.88" + +.SH NAME +bgpd \- a BGPv4, BGPv4+, BGPv4- routing engine for use with Zebra + +.SH SYNOPSIS +.B bgpd +[ +.B \-dhpPv +] +[ +.B \-f config-file +] +[ +.B \-i pid-file +] +[ +.B \-p bgp-port-number +] +[ +.B \--bgp_port=port-number +] +[ +.B \-P vty-port-number +] + +.SH DESCRIPTION +.B bgpd +is a routing component that works with the +.B zebra +routing engine. + + +.SH OPTIONS + +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. + +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this +option will likely default to \fB\fI/usr/local/etc/bgpd.conf\fR. + +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. + +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When bgpd starts its process idenifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart bgpd. The likely default is \fB\fI/var/run/bgpd.pid\fR. + +.TP +\fB\-p\fR, \fB\-\-bgp_port=\fR\fIport\fR +Set the port that bgpd will listen to for bgp data. + +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the bgpd VTY will listen on. This defaults to +2605, as specified in \fI/etc/services\fR. + +.TP +\fB\-r\fR, \fB\-\-retain\fR +When the program terminates, retain routes added by \fBbgpd\fR. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. + + +.SH COMMANDS + +\fB router zebra \fR -- (Move routes into kernel table) +\fB router bgp [AS-NUMBER] \fR + +\fB bgp router-id [BGP-ROUTER-ID] \fR + +\fB network [NETWORK] area [BGP-AREA-ID] \fR +\fB no network [NETWORK] \fR + +\fB aggregate-address [NETWORK] \fR + +\fB neighbor [PEER-IP-ADDRESS] remote-as [REMOTE-AS] \fR +\fB neighbor [PEER-IP-ADDRESS] version [ 4 | 4+ | 4- ] \fR + +\fB neighbor [PEER-IP-ADDRESS] description \fR +\fB no neighbor [PEER-IP-ADDRESS] description \fR + +\fB neighbor [PEER-IP-ADDRESS] route-map [in | out] \fR +\fB neighbor [PEER-IP-ADDRESS] distribute-list [in | out] \fR +\fB neighbor [PEER-IP-ADDRESS] next-hop-self \fR +\fB neighbor [PEER-IP-ADDRESS] weight [WEIGHT] \fR +\fB neighbor [PEER-IP-ADDRESS] default-originate \fR +\fB neighbor [PEER-IP-ADDRESS] ebgp-multihop \fR + +\fB neighbor [PEER-IP-ADDRESS] shutdown \fR +\fB no neighbor [PEER-IP-ADDRESS] shutdown \fR + +\fB clear ip bgp [PEER-IP-ADDRESS] \fR + +\fB show ip bgp [NETWORK] \fR +\fB show ip bgp reg-exp [AS-REGEXP] \fR +\fB show ip bgp summary \fR +\fB show ip bgp neighbor [PEER-IP-ADDRESS] \fR +\fB show ip bgp route \fR + +\fB show debug \fR + +\fB debug bgp \fR +\fB debug event \fR +\fB debug update \fR +\fB debug keepalive \fR + +\fB no debug event \fR +\fB no debug update \fR +\fB no debug keepalive \fR + + +.SH FILES + +.TP +.BI /usr/local/sbin/bgpd +The default location of the +.B bgpd +binary. + +.TP +.BI /usr/local/etc/bgpd.conf +The default location of the +.B bgpd +config file. + +.TP +.BI $(PWD)/bgpd.log +If the +.B bgpd +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBbgpd\fR. + + +.SH WARNING +This man page is intended as a quick reference for command line +options, and for config file commands. The definitive document is the +Info file \fBzebra\fR. + + +.SH DIAGNOSTICS +The bgpd process may log to standard output, to a VTY, to a log +file, or through syslog to the system logs. \fBbgpd\fR supports many +debugging options, see the Info file, or the source for details. + + +.SH "SEE ALSO" +References to other related man pages: + +ripd(8), ripngd(8), ospfd(8), ospf6d(8), zebra(8), vtysh(1) + + +.SH BUGS +.B bgpd +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. + diff --git a/doc/bgpd.texi b/doc/bgpd.texi new file mode 100644 index 0000000..c10fba9 --- /dev/null +++ b/doc/bgpd.texi @@ -0,0 +1,1288 @@ +@c -*-texinfo-*- +@c This is part of the GNU Zebra Manual. +@c Copyright (C) 1999, 2000, 2001 2002 Kunihiro Ishiguro +@c See file zebra.texi for copying conditions. +@node BGP +@comment node-name, next, previous, up +@chapter BGP + + BGP stands for a Border Gateway Protocol. The lastest BGP version +is 4. It is referred as BGP-4. BGP-4 is one of the Exterior Gateway +Protocols and de-fact standard of Inter Domain routing protocol. +BGP-4 is described in @code{RFC1771} - @cite{A Border Gateway Protocol +4 (BGP-4)}. + + Many extentions are added to @code{RFC1771}. @code{RFC2858} - +@cite{Multiprotocol Extensions for BGP-4} provide multiprotocol +support to BGP-4. + +@menu +* Starting BGP:: +* BGP router:: +* BGP network:: +* BGP Peer:: +* BGP Peer Group:: +* BGP Address Family:: +* Autonomous System:: +* BGP Communities Attribute:: +* BGP Extended Communities Attribute:: +* Displaying BGP routes:: +* Capability Negotiation:: +* Route Reflector:: +* Route Server:: +* How to set up a 6-Bone connection:: +* Dump BGP packets and table:: +@end menu + +@node Starting BGP, BGP router, BGP, BGP +@comment node-name, next, previous, up +@section Starting BGP + +Default configuration file of @command{bgpd} is @file{bgpd.conf}. +@command{bgpd} searches the current directory first then +@value{INSTALL_PREFIX_ETC}/bgpd.conf. All of bgpd's command must be +configured in @file{bgpd.conf}. + +@command{bgpd} specific invocation options are described below. Common +options may also be specified (@pxref{Common Invocation Options}). + +@table @samp +@item -p @var{PORT} +@itemx --bgp_port=@var{PORT} +Set the bgp protocol's port number. + +@item -r +@itemx --retain +When program terminates, retain BGP routes added by zebra. +@end table + +@node BGP router, BGP network, Starting BGP, BGP +@comment node-name, next, previous, up +@section BGP router + + First of all you must configure BGP router with @command{router bgp} +command. To configure BGP router, you need AS number. AS number is an +identification of autonomous system. BGP protocol uses the AS number +for detecting whether the BGP connection is internal one or external one. + +@deffn Command {router bgp @var{asn}} {} +Enable a BGP protocol process with the specified @var{asn}. After +this statement you can input any @code{BGP Commands}. You can not +create different BGP process under different @var{asn} without +specifying @code{multiple-instance} (@pxref{Multiple instance}). +@end deffn + +@deffn Command {no router bgp @var{asn}} {} +Destroy a BGP protocol process with the specified @var{asn}. +@end deffn + +@deffn {BGP} {bgp router-id @var{A.B.C.D}} {} +This command specifies the router-ID. If @command{bgpd} connects to @command{zebra} it gets +interface and address information. In that case default router ID value +is selected as the largest IP Address of the interfaces. When +@code{router zebra} is not enabled @command{bgpd} can't get interface information +so @code{router-id} is set to 0.0.0.0. So please set router-id by hand. +@end deffn + +@menu +* BGP distance:: +* BGP decision process:: +@end menu + +@node BGP distance, BGP decision process, BGP router, BGP router +@comment node-name, next, previous, up +@subsection BGP distance + +@deffn {BGP} {distance bgp <1-255> <1-255> <1-255>} {} +This command change distance value of BGP. Each argument is distance +value for external routes, internal routes and local routes. +@end deffn + +@deffn {BGP} {distance <1-255> @var{A.B.C.D/M}} {} +@deffnx {BGP} {distance <1-255> @var{A.B.C.D/M} @var{word}} {} +This command set distance value to +@end deffn + +@node BGP decision process, , BGP distance, BGP router +@comment node-name, next, previous, up +@subsection BGP decision process + +@table @asis +@item 1. Weight check + +@item 2. Local preference check. + +@item 3. Local route check. + +@item 4. AS path length check. + +@item 5. Origin check. + +@item 6. MED check. +@end table + +@node BGP network, BGP Peer, BGP router, BGP +@comment node-name, next, previous, up +@section BGP network + +@menu +* BGP route:: +* Route Aggregation:: +* Redistribute to BGP:: +@end menu + +@node BGP route, Route Aggregation, BGP network, BGP network +@comment node-name, next, previous, up +@subsection BGP route + +@deffn {BGP} {network @var{A.B.C.D/M}} {} +This command adds the announcement network. +@example +@group +router bgp 1 + network 10.0.0.0/8 +@end group +@end example +This configuration example says that network 10.0.0.0/8 will be +announced to all neighbors. Some vendors' routers don't advertise +routes if they aren't present in their IGP routing tables; @code{bgp} +doesn't care about IGP routes when announcing its routes. +@end deffn + +@deffn {BGP} {no network @var{A.B.C.D/M}} {} +@end deffn + +@node Route Aggregation, Redistribute to BGP, BGP route, BGP network +@comment node-name, next, previous, up +@subsection Route Aggregation + +@deffn {BGP} {aggregate-address @var{A.B.C.D/M}} {} +This command specifies an aggregate address. +@end deffn + +@deffn {BGP} {aggregate-address @var{A.B.C.D/M} as-set} {} +This command specifies an aggregate address. Resulting routes inlucde +AS set. +@end deffn + +@deffn {BGP} {aggregate-address @var{A.B.C.D/M} summary-only} {} +This command specifies an aggregate address. Aggreated routes will +not be announce. +@end deffn + +@deffn {BGP} {no aggregate-address @var{A.B.C.D/M}} {} +@end deffn + +@node Redistribute to BGP, , Route Aggregation, BGP network +@comment node-name, next, previous, up +@subsection Redistribute to BGP + +@deffn {BGP} {redistribute kernel} {} +Redistribute kernel route to BGP process. +@end deffn + +@deffn {BGP} {redistribute static} {} +Redistribute static route to BGP process. +@end deffn + +@deffn {BGP} {redistribute connected} {} +Redistribute connected route to BGP process. +@end deffn + +@deffn {BGP} {redistribute rip} {} +Redistribute RIP route to BGP process. +@end deffn + +@deffn {BGP} {redistribute ospf} {} +Redistribute OSPF route to BGP process. +@end deffn + +@node BGP Peer, BGP Peer Group, BGP network, BGP +@comment node-name, next, previous, up +@section BGP Peer + +@menu +* Defining Peer:: +* BGP Peer commands:: +* Peer filtering:: +@end menu + +@node Defining Peer, BGP Peer commands, BGP Peer, BGP Peer +@comment node-name, next, previous, up +@subsection Defining Peer + +@deffn {BGP} {neighbor @var{peer} remote-as @var{asn}} {} +Creates a new neighbor whose remote-as is @var{asn}. @var{peer} +can be an IPv4 address or an IPv6 address. +@example +@group +router bgp 1 + neighbor 10.0.0.1 remote-as 2 +@end group +@end example +In this case my router, in AS-1, is trying to peer with AS-2 at +10.0.0.1. + +This command must be the first command used when configuring a neighbor. +If the remote-as is not specified, @command{bgpd} will complain like this: +@example +can't find neighbor 10.0.0.1 +@end example +@end deffn + +@node BGP Peer commands, Peer filtering, Defining Peer, BGP Peer +@comment node-name, next, previous, up +@subsection BGP Peer commands + +In a @code{router bgp} clause there are neighbor specific configurations +required. + +@deffn {BGP} {neighbor @var{peer} shutdown} {} +@deffnx {BGP} {no neighbor @var{peer} shutdown} {} +Shutdown the peer. We can delete the neighbor's configuration by +@code{no neighbor @var{peer} remote-as @var{as-number}} but all +configuration of the neighbor will be deleted. When you want to +preserve the configuration, but want to drop the BGP peer, use this +syntax. +@end deffn + +@deffn {BGP} {neighbor @var{peer} ebgp-multihop} {} +@deffnx {BGP} {no neighbor @var{peer} ebgp-multihop} {} +@end deffn + +@deffn {BGP} {neighbor @var{peer} description ...} {} +@deffnx {BGP} {no neighbor @var{peer} description ...} {} +Set description of the peer. +@end deffn + +@deffn {BGP} {neighbor @var{peer} version @var{version}} {} +Set up the neighbor's BGP version. @var{version} can be @var{4}, +@var{4+} or @var{4-}. BGP version @var{4} is the default value used for +BGP peering. BGP version @var{4+} means that the neighbor supports +Multiprotocol Extensions for BGP-4. BGP version @var{4-} is similar but +the neighbor speaks the old Internet-Draft revision 00's Multiprotocol +Extensions for BGP-4. Some routing software is still using this +version. +@end deffn + +@deffn {BGP} {neighbor @var{peer} interface @var{ifname}} {} +@deffnx {BGP} {no neighbor @var{peer} interface @var{ifname}} {} +When you connect to a BGP peer over an IPv6 link-local address, you have +to specify the @var{ifname} of the interface used for the connection. +@end deffn + +@deffn {BGP} {neighbor @var{peer} next-hop-self} {} +@deffnx {BGP} {no neighbor @var{peer} next-hop-self} {} +This command specifies an announced route's nexthop as being equivalent +to the address of the bgp router. +@end deffn + +@deffn {BGP} {neighbor @var{peer} update-source} {} +@deffnx {BGP} {no neighbor @var{peer} update-source} {} +@end deffn + +@deffn {BGP} {neighbor @var{peer} default-originate} {} +@deffnx {BGP} {no neighbor @var{peer} default-originate} {} +@command{bgpd}'s default is to not announce the default route (0.0.0.0/0) even it +is in routing table. When you want to announce default routes to the +peer, use this command. +@end deffn + +@deffn {BGP} {neighbor @var{peer} port @var{port}} {} +@deffnx {BGP} {neighbor @var{peer} port @var{port}} {} +@end deffn + +@deffn {BGP} {neighbor @var{peer} send-community} {} +@deffnx {BGP} {neighbor @var{peer} send-community} {} +@end deffn + +@deffn {BGP} {neighbor @var{peer} weight @var{weight}} {} +@deffnx {BGP} {no neighbor @var{peer} weight @var{weight}} {} +This command specifies a default @var{weight} value for the neighbor's +routes. +@end deffn + +@deffn {BGP} {neighbor @var{peer} maximum-prefix @var{number}} {} +@deffnx {BGP} {no neighbor @var{peer} maximum-prefix @var{number}} {} +@end deffn + +@node Peer filtering, , BGP Peer commands, BGP Peer +@comment node-name, next, previous, up +@subsection Peer filtering + +@deffn {BGP} {neighbor @var{peer} distribute-list @var{name} [in|out]} {} +This command specifies a distribute-list for the peer. @var{direct} is +@samp{in} or @samp{out}. +@end deffn + +@deffn {BGP command} {neighbor @var{peer} prefix-list @var{name} [in|out]} {} +@end deffn + +@deffn {BGP command} {neighbor @var{peer} filter-list @var{name} [in|out]} {} +@end deffn + +@deffn {BGP} {neighbor @var{peer} route-map @var{name} [in|out]} {} +Apply a route-map on the neighbor. @var{direct} must be @code{in} or +@code{out}. +@end deffn + +@c ----------------------------------------------------------------------- +@node BGP Peer Group, BGP Address Family, BGP Peer, BGP +@comment node-name, next, previous, up +@section BGP Peer Group + +@deffn {BGP} {neighbor @var{word} peer-group} {} +This command defines a new peer group. +@end deffn + +@deffn {BGP} {neighbor @var{peer} peer-group @var{word}} {} +This command bind specific peer to peer group @var{word}. +@end deffn + +@node BGP Address Family, Autonomous System, BGP Peer Group, BGP +@comment node-name, next, previous, up +@section BGP Address Family + + + +@page +@c ----------------------------------------------------------------------- +@node Autonomous System, BGP Communities Attribute, BGP Address Family, BGP +@comment node-name, next, previous, up +@section Autonomous System + + AS (Autonomous System) is one of the essential element of BGP. BGP +is a distance vector routing protocol. AS framework provides distance +vector metric and loop detection to BGP. @code{RFC1930} - +@cite{Guidelines for creation, selection, and registration of an +Autonomous System (AS)} describes how to use AS. + + AS number is tow octet digita value. So the value range is from 1 +to 65535. AS numbers 64512 through 65535 are defined as private AS +numbers. Private AS numbers must not to be advertised in the global +Internet. + +@menu +* AS Path Regular Expression:: +* Display BGP Routes by AS Path:: +* AS Path Access List:: +* Using AS Path in Route Map:: +* Private AS Numbers:: +@end menu + +@node AS Path Regular Expression, Display BGP Routes by AS Path, Autonomous System, Autonomous System +@comment node-name, next, previous, up +@subsection AS Path Regular Expression + + AS path regular expression can be used for displaying BGP routes and +AS path access list. AS path regular expression is based on +@code{POSIX 1003.2} regular expressions. Following description is +just a subset of @code{POSIX} regular expression. User can use full +@code{POSIX} regular expression. Adding to that special character '_' +is added for AS path regular expression. + +@table @code +@item . +Matches any single character. +@item * +Matches 0 or more occurrences of pattern. +@item + +Matches 1 or more occurrences of pattern. +@item ? +Match 0 or 1 occurrences of pattern. +@item ^ +Matches the beginning of the line. +@item $ +Matches the end of the line. +@item _ +Character @code{_} has special meanings in AS path regular expression. +It matches to space and comma , and AS set delimiter @{ and @} and AS +confederation delimiter @code{(} and @code{)}. And it also matches to +the beginning of the line and the end of the line. So @code{_} can be +used for AS value boundaries match. @code{show ip bgp regexp _7675_} +matches to all of BGP routes which as AS number include @var{7675}. +@end table + +@node Display BGP Routes by AS Path, AS Path Access List, AS Path Regular Expression, Autonomous System +@comment node-name, next, previous, up +@subsection Display BGP Routes by AS Path + + To show BGP routes which has specific AS path information @code{show +ip bgp} command can be used. + +@deffn Command {show ip bgp regexp @var{line}} {} +This commands display BGP routes that matches AS path regular +expression @var{line}. +@end deffn + +@node AS Path Access List, Using AS Path in Route Map, Display BGP Routes by AS Path, Autonomous System +@comment node-name, next, previous, up +@subsection AS Path Access List + + AS path access list is user defined AS path. + +@deffn {Command} {ip as-path access-list @var{word} @{permit|deny@} @var{line}} {} +This command defines a new AS path access list. +@end deffn + +@deffn {Command} {no ip as-path access-list @var{word}} {} +@deffnx {Command} {no ip as-path access-list @var{word} @{permit|deny@} @var{line}} {} +@end deffn + +@node Using AS Path in Route Map, Private AS Numbers, AS Path Access List, Autonomous System +@comment node-name, next, previous, up +@subsection Using AS Path in Route Map + +@deffn {Route Map} {match as-path @var{word}} {} +@end deffn + +@deffn {Route Map} {set as-path prepend @var{as-path}} {} +@end deffn + +@node Private AS Numbers, , Using AS Path in Route Map, Autonomous System +@comment node-name, next, previous, up +@subsection Private AS Numbers + +@page +@c ----------------------------------------------------------------------- +@node BGP Communities Attribute, BGP Extended Communities Attribute, Autonomous System, BGP +@comment node-name, next, previous, up +@section BGP Communities Attribute + + BGP communities attribute is widely used for implementing policy +routing. Network operators can manipulate BGP communities attribute +based on their network policy. BGP communities attribute is defined +in @code{RFC1997} - @cite{BGP Communities Attribute} and +@code{RFC1998} - @cite{An Application of the BGP Community Attribute +in Multi-home Routing}. It is an optional transitive attribute, +therefore local policy can travel through different autonomous system. + + Communities attribute is a set of communities values. Each +communities value is 4 octet long. The following format is used to +define communities value. + +@table @code +@item AS:VAL +This format represents 4 octet communities value. @code{AS} is high +order 2 octet in digit format. @code{VAL} is low order 2 octet in +digit format. This format is useful to define AS oriented policy +value. For example, @code{7675:80} can be used when AS 7675 wants to +pass local policy value 80 to neighboring peer. +@item internet +@code{internet} represents well-known communities value 0. +@item no-export +@code{no-export} represents well-known communities value @code{NO_EXPORT}@* +@r{(0xFFFFFF01)}. All routes carry this value must not be advertised +to outside a BGP confederation boundary. If neighboring BGP peer is +part of BGP confederation, the peer is considered as inside a BGP +confederation boundary, so the route will be announced to the peer. +@item no-advertise +@code{no-advertise} represents well-known communities value +@code{NO_ADVERTISE}@*@r{(0xFFFFFF02)}. All routes carry this value +must not be advertise to other BGP peers. +@item local-AS +@code{local-AS} represents well-known communities value +@code{NO_EXPORT_SUBCONFED} @r{(0xFFFFFF03)}. All routes carry this +value must not be advertised to external BGP peers. Even if the +neighboring router is part of confederation, it is considered as +external BGP peer, so the route will not be announced to the peer. +@end table + + When BGP communities attribute is received, duplicated communities +value in the communities attribute is ignored and each communities +values are sorted in numerical order. + +@menu +* BGP Community Lists:: +* Numbered BGP Community Lists:: +* BGP Community in Route Map:: +* Display BGP Routes by Community:: +* Using BGP Communities Attribute:: +@end menu + +@node BGP Community Lists, Numbered BGP Community Lists, BGP Communities Attribute, BGP Communities Attribute +@comment node-name, next, previous, up +@subsection BGP Community Lists + + BGP community list is a user defined BGP communites attribute list. +BGP community list can be used for matching or manipulating BGP +communities attribute in updates. + + There are two types of community list. One is standard community +list and another is expanded community list. Standard community list +defines communities attribute. Expanded community list defines +communities attribute string with regular expression. Standard +community list is compiled into binary format when user define it. +Standard community list will be directly compared to BGP communities +attribute in BGP updates. Therefore the comparison is faster than +expanded community list. + +@deffn Command {ip community-list standard @var{name} @{permit|deny@} @var{community}} {} +This command defines a new standard community list. @var{community} +is communities value. The @var{community} is compiled into community +structure. We can define multiple community list under same name. In +that case match will happen user defined order. Once the +community list matches to communities attribute in BGP updates it +return permit or deny by the community list definition. When there is +no matched entry, deny will be returned. When @var{community} is +empty it matches to any routes. +@end deffn + +@deffn Command {ip community-list expanded @var{name} @{permit|deny@} @var{line}} {} +This command defines a new expanded community list. @var{line} is a +string expression of communities attribute. @var{line} can include +regular expression to match communities attribute in BGP updates. +@end deffn + +@deffn Command {no ip community-list @var{name}} {} +@deffnx Command {no ip community-list standard @var{name}} {} +@deffnx Command {no ip community-list expanded @var{name}} {} +These commands delete community lists specified by @var{name}. All of +community lists shares a single name space. So community lists can be +removed simpley specifying community lists name. +@end deffn + +@deffn {Command} {show ip community-list} {} +@deffnx {Command} {show ip community-list @var{name}} {} +This command display current community list information. When +@var{name} is specified the specified community list's information is +shown. + +@example +# show ip community-list +Named Community standard list CLIST + permit 7675:80 7675:100 no-export + deny internet +Named Community expanded list EXPAND + permit : + +# show ip community-list CLIST +Named Community standard list CLIST + permit 7675:80 7675:100 no-export + deny internet +@end example +@end deffn + +@node Numbered BGP Community Lists, BGP Community in Route Map, BGP Community Lists, BGP Communities Attribute +@comment node-name, next, previous, up +@subsection Numbered BGP Community Lists + + When number is used for BGP community list name, the number has +special meanings. Community list number in the range from 1 and 99 is +standard community list. Community list number in the range from 100 +to 199 is expanded community list. These community lists are called +as numbered community lists. On the other hand normal community lists +is called as named community lists. + +@deffn Command {ip community-list <1-99> @{permit|deny@} @var{community}} {} +This command defines a new community list. <1-99> is standard +community list number. Community list name within this range defines +standard community list. When @var{community} is empty it matches to +any routes. +@end deffn + +@deffn Command {ip community-list <100-199> @{permit|deny@} @var{community}} {} +This command defines a new community list. <100-199> is expanded +community list number. Community list name within this range defines +expanded community list. +@end deffn + +@deffn Command {ip community-list @var{name} @{permit|deny@} @var{community}} {} +When community list type is not specifed, the community list type is +automatically detected. If @var{community} can be compiled into +communities attribute, the community list is defined as a standard +community list. Otherwise it is defined as an expanded community +list. This feature is left for backward compability. Use of this +feature is not recommended. +@end deffn + +@node BGP Community in Route Map, Display BGP Routes by Community, Numbered BGP Community Lists, BGP Communities Attribute +@comment node-name, next, previous, up +@subsection BGP Community in Route Map + + In Route Map (@pxref{Route Map}), we can match or set BGP +communities attribute. Using this feature network operator can +implement their network policy based on BGP communities attribute. + + Following commands can be used in Route Map. + +@deffn {Route Map} {match community @var{word}} {} +@deffnx {Route Map} {match community @var{word} exact-match} {} +This command perform match to BGP updates using community list +@var{word}. When the one of BGP communities value match to the one of +communities value in community list, it is match. When +@code{exact-match} keyword is spcified, match happen only when BGP +updates have completely same communities value specified in the +community list. +@end deffn + +@deffn {Route Map} {set community none} {} +@deffnx {Route Map} {set community @var{community}} {} +@deffnx {Route Map} {set community @var{community} additive} {} +This command manipulate communities value in BGP updates. When +@code{none} is specified as communities value, it removes entire +communities attribute from BGP updates. When @var{community} is not +@code{none}, specified communities value is set to BGP updates. If +BGP updates already has BGP communities value, the existing BGP +communities value is replaced with specified @var{community} value. +When @code{additive} keyword is specified, @var{community} is appended +to the existing communities value. +@end deffn + +@deffn {Route Map} {set comm-list @var{word} delete} {} +This command remove communities value from BGP communities attribute. +The @var{word} is community list name. When BGP route's communities +value matches to the community list @var{word}, the communities value +is removed. When all of communities value is removed eventually, the +BGP update's communities attribute is completely removed. +@end deffn + +@node Display BGP Routes by Community, Using BGP Communities Attribute, BGP Community in Route Map, BGP Communities Attribute +@comment node-name, next, previous, up +@subsection Display BGP Routes by Community + + To show BGP routes which has specific BGP communities attribute, +@code{show ip bgp} command can be used. The @var{community} value and +community list can be used for @code{show ip bgp} command. + +@deffn Command {show ip bgp community} {} +@deffnx Command {show ip bgp community @var{community}} {} +@deffnx Command {show ip bgp community @var{community} exact-match} {} +@code{show ip bgp community} displays BGP routes which has communities +attribute. When @var{community} is specified, BGP routes that matches +@var{community} value is displayed. For this command, @code{internet} +keyword can't be used for @var{community} value. When +@code{exact-match} is specified, it display only routes that have an +exact match. +@end deffn + +@deffn Command {show ip bgp community-list @var{word}} {} +@deffnx Command {show ip bgp community-list @var{word} exact-match} {} +This commands display BGP routes that matches community list +@var{word}. When @code{exact-match} is specified, display only routes +that have an exact match. +@end deffn + +@node Using BGP Communities Attribute, , Display BGP Routes by Community, BGP Communities Attribute +@comment node-name, next, previous, up +@subsection Using BGP Communities Attribute + + Following configuration is the most typical usage of BGP communities +attribute. AS 7675 provides upstream Internet connection to AS 100. +When following configuration exists in AS 7675, AS 100 networks +operator can set local preference in AS 7675 network by setting BGP +communities attribute to the updates. + +@example +router bgp 7675 + neighbor 192.168.0.1 remote-as 100 + neighbor 192.168.0.1 route-map RMAP in +! +ip community-list 70 permit 7675:70 +ip community-list 70 deny +ip community-list 80 permit 7675:80 +ip community-list 80 deny +ip community-list 90 permit 7675:90 +ip community-list 90 deny +! +route-map RMAP permit 10 + match community 70 + set local-preference 70 +! +route-map RMAP permit 20 + match community 80 + set local-preference 80 +! +route-map RMAP permit 30 + match community 90 + set local-preference 90 +@end example + + Following configuration announce 10.0.0.0/8 from AS 100 to AS 7675. +The route has communities value 7675:80 so when above configuration +exists in AS 7675, announced route's local preference will be set to +value 80. + +@example +router bgp 100 + network 10.0.0.0/8 + neighbor 192.168.0.2 remote-as 7675 + neighbor 192.168.0.2 route-map RMAP out +! +ip prefix-list PLIST permit 10.0.0.0/8 +! +route-map RMAP permit 10 + match ip address prefix-list PLIST + set community 7675:80 +@end example + + Following configuration is an example of BGP route filtering using +communities attribute. This configuration only permit BGP routes +which has BGP communities value 0:80 or 0:90. Network operator can +put special internal communities value at BGP border router, then +limit the BGP routes announcement into the internal network. + +@example +router bgp 7675 + neighbor 192.168.0.1 remote-as 100 + neighbor 192.168.0.1 route-map RMAP in +! +ip community-list 1 permit 0:80 0:90 +! +route-map RMAP permit in + match community 1 +@end example + + Following exmaple filter BGP routes which has communities value 1:1. +When there is no match community-list returns deny. To avoid +filtering all of routes, we need to define permit any at last. + +@example +router bgp 7675 + neighbor 192.168.0.1 remote-as 100 + neighbor 192.168.0.1 route-map RMAP in +! +ip community-list standard FILTER deny 1:1 +ip community-list standard FILTER permit +! +route-map RMAP permit 10 + match community FILTER +@end example + + Communities value keyword @code{internet} has special meanings in +standard community lists. In below example @code{internet} act as +match any. It matches all of BGP routes even if the route does not +have communities attribute at all. So community list @code{INTERNET} +is same as above example's @code{FILTER}. + +@example +ip community-list standard INTERNET deny 1:1 +ip community-list standard INTERNET permit internet +@end example + + Following configuration is an example of communities value deletion. +With this configuration communities value 100:1 and 100:2 is removed +from BGP updates. For communities value deletion, only @code{permit} +community-list is used. @code{deny} community-list is ignored. + +@example +router bgp 7675 + neighbor 192.168.0.1 remote-as 100 + neighbor 192.168.0.1 route-map RMAP in +! +ip community-list standard DEL permit 100:1 100:2 +! +route-map RMAP permit 10 + set comm-list DEL delete +@end example + +@c ----------------------------------------------------------------------- +@node BGP Extended Communities Attribute, Displaying BGP routes, BGP Communities Attribute, BGP +@comment node-name, next, previous, up +@section BGP Extended Communities Attribute + + BGP extended communities attribute is introduced with MPLS VPN/BGP +technology. MPLS VPN/BGP expands capability of network infrastructure +to provide VPN functionality. At the same time it requires a new +framework for policy routing. With BGP Extended Communities Attribute +we can use Route Target or Site of Origin for implementing network +policy for MPLS VPN/BGP. + + BGP Extended Communities Attribute is similar to BGP Communities +Attribute. It is an optional transitive attribute. BGP Extended +Communities Attribute can carry multiple Extended Community value. +Each Extended Community value is eight octet length. + + BGP Extended Communities Attribute provides an extended range +compared with BGP Communities Attribute. Adding to that there is a +type field in each value to provides community space structure. + + There are two format to define Extended Community value. One is AS +based format the other is IP address based format. + +@table @code +@item AS:VAL +This is a format to define AS based Extended Community value. +@code{AS} part is 2 octets Global Administrator subfield in Extended +Community value. @code{VAL} part is 4 octets Local Administrator +subfield. @code{7675:100} represents AS 7675 policy value 100. +@item IP-Address:VAL +This is a format to define IP address based Extended Community value. +@code{IP-Address} part is 4 octets Global Administrator subfield. +@code{VAL} part is 2 octets Local Administrator subfield. +@code{10.0.0.1:100} represents +@end table + +@menu +* BGP Extended Community Lists:: +* BGP Extended Communities in Route Map:: +@end menu + +@node BGP Extended Community Lists, BGP Extended Communities in Route Map, BGP Extended Communities Attribute, BGP Extended Communities Attribute +@comment node-name, next, previous, up +@subsection BGP Extended Community Lists + + Expanded Community Lists is a user defined BGP Expanded Community +Lists. + +@deffn Command {ip extcommunity-list standard @var{name} @{permit|deny@} @var{extcommunity}} {} +This command defines a new standard extcommunity-list. +@var{extcommunity} is extended communities value. The +@var{extcommunity} is compiled into extended community structure. We +can define multiple extcommunity-list under same name. In that case +match will happen user defined order. Once the extcommunity-list +matches to extended communities attribute in BGP updates it return +permit or deny based upon the extcommunity-list definition. When +there is no matched entry, deny will be returned. When +@var{extcommunity} is empty it matches to any routes. +@end deffn + +@deffn Command {ip extcommunity-list expanded @var{name} @{permit|deny@} @var{line}} {} +This command defines a new expanded extcommunity-list. @var{line} is +a string expression of extended communities attribute. @var{line} can +include regular expression to match extended communities attribute in +BGP updates. +@end deffn + +@deffn Command {no ip extcommunity-list @var{name}} {} +@deffnx Command {no ip extcommunity-list standard @var{name}} {} +@deffnx Command {no ip extcommunity-list expanded @var{name}} {} +These commands delete extended community lists specified by +@var{name}. All of extended community lists shares a single name +space. So extended community lists can be removed simpley specifying +the name. +@end deffn + +@deffn {Command} {show ip extcommunity-list} {} +@deffnx {Command} {show ip extcommunity-list @var{name}} {} +This command display current extcommunity-list information. When +@var{name} is specified the community list's information is shown. + +@example +# show ip extcommunity-list +@end example +@end deffn + +@node BGP Extended Communities in Route Map, , BGP Extended Community Lists, BGP Extended Communities Attribute +@comment node-name, next, previous, up +@subsection BGP Extended Communities in Route Map + +@deffn {Route Map} {match extcommunity @var{word}} {} +@end deffn + +@deffn {Route Map} {set extcommunity rt @var{extcommunity}} {} +This command set Route Target value. +@end deffn + +@deffn {Route Map} {set extcommunity soo @var{extcommunity}} {} +This command set Site of Origin value. +@end deffn + +@c ----------------------------------------------------------------------- +@node Displaying BGP routes, Capability Negotiation, BGP Extended Communities Attribute, BGP +@comment node-name, next, previous, up +@section Displaying BGP Routes + +@menu +* Show IP BGP:: +* More Show IP BGP:: +@end menu + +@node Show IP BGP, More Show IP BGP, Displaying BGP routes, Displaying BGP routes +@comment node-name, next, previous, up +@subsection Show IP BGP + +@deffn {Command} {show ip bgp} {} +@deffnx {Command} {show ip bgp @var{A.B.C.D}} {} +@deffnx {Command} {show ip bgp @var{X:X::X:X}} {} +This command displays BGP routes. When no route is specified it +display all of IPv4 BGP routes. +@end deffn + +@example +BGP table version is 0, local router ID is 10.1.1.1 +Status codes: s suppressed, d damped, h history, * valid, > best, i - internal +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +*> 1.1.1.1/32 0.0.0.0 0 32768 i + +Total number of prefixes 1 +@end example + +@node More Show IP BGP, , Show IP BGP, Displaying BGP routes +@comment node-name, next, previous, up +@subsection More Show IP BGP + +@deffn {Command} {show ip bgp regexp @var{line}} {} +This command display BGP routes using AS path regular expression (@pxref{Display BGP Routes by AS Path}). +@end deffn + +@deffn Command {show ip bgp community @var{community}} {} +@deffnx Command {show ip bgp community @var{community} exact-match} {} +This command display BGP routes using @var{community} (@pxref{Display +BGP Routes by Community}). +@end deffn + +@deffn Command {show ip bgp community-list @var{word}} {} +@deffnx Command {show ip bgp community-list @var{word} exact-match} {} +This command display BGP routes using community list (@pxref{Display +BGP Routes by Community}). +@end deffn + +@deffn {Command} {show ip bgp summary} {} +@end deffn + +@deffn {Command} {show ip bgp neighbor [@var{peer}]} {} +@end deffn + +@deffn {Command} {clear ip bgp @var{peer}} {} +Clear peers which have addresses of X.X.X.X +@end deffn + +@deffn {Command} {clear ip bgp @var{peer} soft in} {} +Clear peer using soft reconfiguration. +@end deffn + +@deffn {Command} {show debug} {} +@end deffn + +@deffn {Command} {debug event} {} +@end deffn + +@deffn {Command} {debug update} {} +@end deffn + +@deffn {Command} {debug keepalive} {} +@end deffn + +@deffn {Command} {no debug event} {} +@end deffn + +@deffn {Command} {no debug update} {} +@end deffn + +@deffn {Command} {no debug keepalive} {} +@end deffn + +@node Capability Negotiation, Route Reflector, Displaying BGP routes, BGP +@comment node-name, next, previous, up +@section Capability Negotiation + + When adding IPv6 routing information exchange feature to BGP. There +were some proposals. @acronym{IETF} @acronym{IDR} working group finally +take a proposal called Multiprotocol Extension for BGP. The +specification is described in RFC2283. The protocol does not define new +protocols. It defines new attributes to existing BGP. When it is used +exchanging IPv6 routing information it is called BGP-4+. When it is +used for exchanging multicast routing information it is called MBGP. + + @command{bgpd} supports Multiprotocol Extension for BGP. So if remote peer +supports the protocol, @command{bgpd} can exchange IPv6 and/or multicast routing +information. + + Traditional BGP does not have the feature to detect remote peer's +capability whether it can handle other than IPv4 unicast routes. This +is a big problem using Multiprotocol Extension for BGP to operational +network. @cite{draft-ietf-idr-bgp4-cap-neg-04.txt} is proposing a +feature called Capability Negotiation. @command{bgpd} use this Capability +Negotiation to detect remote peer's capabilities. If the peer is only +configured as IPv4 unicast neighbor, @command{bgpd} does not send these Capability +Negotiation packets. + + By default, Zebra will bring up peering with minimal common capability +for the both sides. For example, local router has unicast and multicast +capabilitie and remote router has unicast capability. In this case, +the local router will establish the connection with unicast only capability. +When there are no common capabilities, Zebra sends Unsupported Capability +error and then resets the connection. + + If you want to completely match capabilities with remote peer. Please +use @command{strict-capability-match} command. + +@deffn {BGP} {neighbor @var{peer} strict-capability-match} {} +@deffnx {BGP} {no neighbor @var{peer} strict-capability-match} {} +Strictly compares remote capabilities and local capabilities. If capabilities +are different, send Unsupported Capability error then reset connection. +@end deffn + + You may want to disable sending Capability Negotiation OPEN message +optional parameter to the peer when remote peer does not implement +Capability Negotiation. Please use @command{dont-capability-negotiate} +command to disable the feature. + +@deffn {BGP} {neighbor @var{peer} dont-capability-negotiate} {} +@deffnx {BGP} {no neighbor @var{peer} dont-capability-negotiate} {} +Suppress sending Capability Negotiation as OPEN message optional +parameter to the peer. This command only affects the peer is configured +other than IPv4 unicast configuration. +@end deffn + + When remote peer does not have capability negotiation feature, remote +peer will not send any capabilities at all. In that case, bgp configures +the peer with configured capabilities. + + You may prefer locally configured capabilities more than the negotiated +capabilities even though remote peer sends capabilities. If the peer is +configured by @command{override-capability}, @command{bgpd} ignores received +capabilities then override negotiated capabilities with configured values. + +@deffn {BGP} {neighbor @var{peer} override-capability} {} +@deffnx {BGP} {no neighbor @var{peer} override-capability} {} +Override the result of Capability Negotiation with local configuration. +Ignore remote peer's capability value. +@end deffn + +@node Route Reflector, Route Server, Capability Negotiation, BGP +@comment node-name, next, previous, up +@section Route Reflector + +@deffn {BGP} {bgp cluster-id @var{a.b.c.d}} {} +@end deffn + +@deffn {BGP} {neighbor @var{peer} route-reflector-client} {} +@deffnx {BGP} {no neighbor @var{peer} route-reflector-client} {} +@end deffn + +@node Route Server, How to set up a 6-Bone connection, Route Reflector, BGP +@comment node-name, next, previous, up +@section Route Server + +At an Internet Exchange point, many ISPs are connected to each other by +external BGP peering. Normally these external BGP connection are done by +@code{full mesh} method. As with internal BGP full mesh formation, +this method has a scaling problem. + +This scaling problem is well known. Route Server is a method to resolve +the problem. Each ISP's BGP router only peers to Route Server. Route +Server serves as BGP information exchange to other BGP routers. By +applying this method, numbers of BGP connections is reduced from +O(n*(n-1)/2) to O(n). + +Unlike normal BGP router, Route Server must have several routing tables +for managing different routing policies for each BGP speaker. We call the +routing tables as different @code{view}s. @command{bgpd} can work as +normal BGP router or Route Server or both at the same time. + +@menu +* Multiple instance:: +* BGP instance and view:: +* Routing policy:: +* Viewing the view:: +@end menu + +@node Multiple instance, BGP instance and view, Route Server, Route Server +@comment node-name, next, previous, up +@subsection Multiple instance + +To enable multiple view function of @code{bgpd}, you must turn on +multiple instance feature beforehand. + +@deffn {Command} {bgp multiple-instance} {} +Enable BGP multiple instance feature. After this feature is enabled, +you can make multiple BGP instances or multiple BGP views. +@end deffn + +@deffn {Command} {no bgp multiple-instance} {} +Disable BGP multiple instance feature. You can not disable this feature +when BGP multiple instances or views exist. +@end deffn + +When you want to make configuration more Cisco like one, + +@deffn {Command} {bgp config-type cisco} {} +Cisco compatible BGP configuration output. +@end deffn + +When bgp config-type cisco is specified, + +``no synchronization'' is displayed. +``no auto-summary'' is desplayed. + +``network'' and ``aggregate-address'' argument is displayed as +``A.B.C.D M.M.M.M'' + +Zebra: network 10.0.0.0/8 +Cisco: network 10.0.0.0 + +Zebra: aggregate-address 192.168.0.0/24 +Cisco: aggregate-address 192.168.0.0 255.255.255.0 + +Community attribute handling is also different. If there is no +configuration is specified community attribute and extended community +attribute are sent to neighbor. When user manually disable the +feature community attribute is not sent to the neighbor. In case of +``bgp config-type cisco'' is specified, community attribute is not +sent to the neighbor by default. To send community attribute user has +to specify ``neighbor A.B.C.D send-community'' command. + +! +router bgp 1 + neighbor 10.0.0.1 remote-as 1 + no neighbor 10.0.0.1 send-community +! + +! +router bgp 1 + neighbor 10.0.0.1 remote-as 1 + neighbor 10.0.0.1 send-community +! + +@deffn {Command} {bgp config-type zebra} {} +Zebra style BGP configuration. This is default. +@end deffn + +@node BGP instance and view, Routing policy, Multiple instance, Route Server +@comment node-name, next, previous, up +@subsection BGP instance and view + +BGP instance is a normal BGP process. The result of route selection +goes to the kernel routing table. You can setup different AS at the +same time when BGP multiple instance feature is enabled. + +@deffn {Command} {router bgp @var{as-number}} {} +Make a new BGP instance. You can use arbitrary word for the @var{name}. +@end deffn + +@example +@group +bgp multiple-instance +! +router bgp 1 + neighbor 10.0.0.1 remote-as 2 + neighbor 10.0.0.2 remote-as 3 +! +router bgp 2 + neighbor 10.0.0.3 remote-as 4 + neighbor 10.0.0.4 remote-as 5 +@end group +@end example + +BGP view is almost same as normal BGP process. The result of +route selection does not go to the kernel routing table. BGP view is +only for exchanging BGP routing information. + +@deffn {Command} {router bgp @var{as-number} view @var{name}} {} +Make a new BGP view. You can use arbitrary word for the @var{name}. This +view's route selection result does not go to the kernel routing table. +@end deffn + +With this command, you can setup Route Server like below. + +@example +@group +bgp multiple-instance +! +router bgp 1 view 1 + neighbor 10.0.0.1 remote-as 2 + neighbor 10.0.0.2 remote-as 3 +! +router bgp 2 view 2 + neighbor 10.0.0.3 remote-as 4 + neighbor 10.0.0.4 remote-as 5 +@end group +@end example + +@node Routing policy, Viewing the view, BGP instance and view, Route Server +@comment node-name, next, previous, up +@subsection Routing policy + +You can set different routing policy for a peer. For example, you can +set different filter for a peer. + +@example +@group +bgp multiple-instance +! +router bgp 1 view 1 + neighbor 10.0.0.1 remote-as 2 + neighbor 10.0.0.1 distribute-list 1 in +! +router bgp 1 view 2 + neighbor 10.0.0.1 remote-as 2 + neighbor 10.0.0.1 distribute-list 2 in +@end group +@end example + +This means BGP update from a peer 10.0.0.1 goes to both BGP view 1 and view +2. When the update is inserted into view 1, distribute-list 1 is +applied. On the other hand, when the update is inserted into view 2, +distribute-list 2 is applied. + +@node Viewing the view, , Routing policy, Route Server +@comment node-name, next, previous, up +@subsection Viewing the view + +To display routing table of BGP view, you must specify view name. + +@deffn {Command} {show ip bgp view @var{name}} {} +Display routing table of BGP view @var{name}. +@end deffn + +@node How to set up a 6-Bone connection, Dump BGP packets and table, Route Server, BGP +@comment node-name, next, previous, up +@section How to set up a 6-Bone connection + +@example +@group +zebra configuration +=================== +! +! Actually there is no need to configure zebra +! + +bgpd configuration +================== +! +! This means that routes go through zebra and into the kernel. +! +router zebra +! +! MP-BGP configuration +! +router bgp 7675 + bgp router-id 10.0.0.1 + neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 remote-as @var{as-number} +! + address-family ipv6 + network 3ffe:506::/32 + neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 activate + neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 route-map set-nexthop out + neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 remote-as @var{as-number} + neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 route-map set-nexthop out + exit-address-family +! +ipv6 access-list all permit any +! +! Set output nexthop address. +! +route-map set-nexthop permit 10 + match ipv6 address all + set ipv6 nexthop global 3ffe:1cfa:0:2:2c0:4fff:fe68:a225 + set ipv6 nexthop local fe80::2c0:4fff:fe68:a225 +! +! logfile FILENAME is obsolete. Please use log file FILENAME +! +log file bgpd.log +! +@end group +@end example + +@node Dump BGP packets and table, , How to set up a 6-Bone connection, BGP +@comment node-name, next, previous, up +@section Dump BGP packets and table + +@deffn Command {dump bgp all @var{path}} {} +@deffnx Command {dump bgp all @var{path} @var{interval}} {} +Dump all BGP packet and events to @var{path} file. +@end deffn + +@deffn Command {dump bgp updates @var{path}} {} +@deffnx Command {dump bgp updates @var{path} @var{interval}} {} +Dump BGP updates to @var{path} file. +@end deffn + +@deffn Command {dump bgp routes @var{path}} {} +@deffnx Command {dump bgp routes @var{path}} {} +Dump whole BGP routing table to @var{path}. This is heavy process. +@end deffn diff --git a/doc/draft-zebra-00.ms b/doc/draft-zebra-00.ms new file mode 100644 index 0000000..2599472 --- /dev/null +++ b/doc/draft-zebra-00.ms @@ -0,0 +1,209 @@ +.pl 10.0i +.po 0 +.ll 7.2i +.lt 7.2i +.nr LL 7.2i +.nr LT 7.2i +.ds LF Ishiguro +.ds RF FORMFEED[Page %] +.ds CF +.ds LH RFC DRAFT +.ds RH March 1998 +.ds CH +.hy 0 +.ad l +Network Working Group K. Ishiguro +Request for Comments: DRAFT Digital Magic Labs, Inc. + March 1998 +.sp 2 +.ce +Zebra Protocol Draft +.sp 2 +.fi +.ne 4 +Status of this Memo +.sp +.in 3 +This draft is very eary beta version. +.sp +.in 0 +.ne 4 +Introduction +.sp +.in 3 +The zebra protocol is a communication protocol between kernel +routing table manager and routing protocol daemon. It is built over +TCP/IP protocol suite. +.sp +.in 0 +.ne 4 +Request message formats +.sp +.in 3 +zebra is TCP-based protocol. +.sp +Below is request packet format. +.sp +.in 0 +.DS +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Length (2) | Command (1) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.DE +.sp +.in 3 +Length is total packet length. +.sp +Here is summary of command list. +.sp +.in 0 +.DS +1 - ZEBRA_IPV4_ROUTE_ADD +2 - ZEBRA_IPV4_ROUTE_DELETE +3 - ZEBRA_IPV6_ROUTE_ADD +4 - ZEBRA_IPV6_ROUTE_DELETE +5 - ZEBRA_GET_ONE_INTERFACE +6 - ZEBRA_GET_ALL_INTERFACE +7 - ZEBRA_GET_HOSTINFO +.DE +.sp +.in 0 +.ne 4 +IPv4 reply message formats +.sp +.in 0 +.DS +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+ +| Type (1) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Gateway (4) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.DE +.sp +.in 3 +Type field specify route's origin type. +.sp +.in 0 +.DS +1 - ZEBRA_ROUTE_RESERVE +2 - ZEBRA_ROUTE_CONNECT +3 - ZEBRA_ROUTE_STATIC +4 - ZEBRA_ROUTE_RIP +5 - ZEBRA_ROUTE_RIPNG +6 - ZEBRA_ROUTE_BGP +7 - ZEBRA_ROUTE_RADIX +.DE +.sp +.in 3 +After above message there can be variale length IPv4 prefix data. +Each IPv4 prefix is encoded as a two tuple of the form +.sp +.in 0 +.DS ++----------------------+ +|Subnet mask (1 octet) | ++----------------------+ +|IPv4 prefix (variable)| ++----------------------+ +.DE +.sp +.in 0 +.ne 4 +IPv6 reply message formats +.sp +.in 0 +.DS +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+ +| Type (1) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Gateway (16) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.DE +.sp +.in 3 +Type field specify route's origin type. +.sp +.in 0 +.DS +1 - ZEBRA_ROUTE_RESERVE +2 - ZEBRA_ROUTE_CONNECT +3 - ZEBRA_ROUTE_STATIC +4 - ZEBRA_ROUTE_RIP +5 - ZEBRA_ROUTE_RIPNG +6 - ZEBRA_ROUTE_BGP +7 - ZEBRA_ROUTE_RADIX +.DE +.sp +.in 0 +.DS ++----------------------+ +| ifindex (4 octet) | ++----------------------+ +| prefixlen (1 octet)| ++----------------------+ +|IPv6 prefix (variable)| ++----------------------+ +.DE +.sp +.in 3 +I am not sure but it seems some operation systems IPv6 +implementation may need interface index when add and delete +linklocal routes. +.sp +I have added ifindex field to specify IPv6 routes interface +index. If this index is value zero, it will ignored. +.sp +.in 0 +.ne 4 +Interface information message format. +.sp +.in 0 +.DS +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Interface name (20) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Index (1) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Inteface flag (4) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Inteface metric (4) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Inteface MTU (4) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Inteface Address count (4) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.DE +.sp +.in 3 +Address message format. +.sp +.in 0 +.ne 4 +Host inforamtion message format. +.sp +.in 0 +.DS +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +|IPv4 forwarding|IPv6 forwarding| ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.DE +.sp +.in 3 +Host information contain IPv4/IPv6 forwarding information. diff --git a/doc/draft-zebra-00.txt b/doc/draft-zebra-00.txt new file mode 100644 index 0000000..d7fbe8c --- /dev/null +++ b/doc/draft-zebra-00.txt @@ -0,0 +1,240 @@ + + + + + + +Network Working Group K. Ishiguro +Request for Comments: DRAFT Digital Magic Labs, Inc. + March 1998 + + + Zebra Protocol Draft + + +Status of this Memo + + This draft is very eary beta version. + +Introduction + + The zebra protocol is a communication protocol between kernel routing + table manager and routing protocol daemon. It is built over TCP/IP + protocol suite. + +Request message formats + + zebra is TCP-based protocol. + + Below is request packet format. + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Length (2) | Command (1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Length is total packet length. + + Here is summary of command list. + + + 1 - ZEBRA_IPV4_ROUTE_ADD + 2 - ZEBRA_IPV4_ROUTE_DELETE + 3 - ZEBRA_IPV6_ROUTE_ADD + 4 - ZEBRA_IPV6_ROUTE_DELETE + 5 - ZEBRA_GET_ONE_INTERFACE + 6 - ZEBRA_GET_ALL_INTERFACE + 7 - ZEBRA_GET_HOSTINFO + + + + + + + +Ishiguro FORMFEED[Page 1] + + + + + +RFC DRAFT March 1998 + + +IPv4 reply message formats + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+ + | Type (1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Gateway (4) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Type field specify route's origin type. + + + 1 - ZEBRA_ROUTE_RESERVE + 2 - ZEBRA_ROUTE_CONNECT + 3 - ZEBRA_ROUTE_STATIC + 4 - ZEBRA_ROUTE_RIP + 5 - ZEBRA_ROUTE_RIPNG + 6 - ZEBRA_ROUTE_BGP + 7 - ZEBRA_ROUTE_RADIX + + + After above message there can be variale length IPv4 prefix data. + Each IPv4 prefix is encoded as a two tuple of the form + + + +----------------------+ + |Subnet mask (1 octet) | + +----------------------+ + |IPv4 prefix (variable)| + +----------------------+ + + +IPv6 reply message formats + + + + + + + + + + + + + + +Ishiguro FORMFEED[Page 2] + + + + + +RFC DRAFT March 1998 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+ + | Type (1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Gateway (16) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Type field specify route's origin type. + + + 1 - ZEBRA_ROUTE_RESERVE + 2 - ZEBRA_ROUTE_CONNECT + 3 - ZEBRA_ROUTE_STATIC + 4 - ZEBRA_ROUTE_RIP + 5 - ZEBRA_ROUTE_RIPNG + 6 - ZEBRA_ROUTE_BGP + 7 - ZEBRA_ROUTE_RADIX + + + + +----------------------+ + | ifindex (4 octet) | + +----------------------+ + | prefixlen (1 octet)| + +----------------------+ + |IPv6 prefix (variable)| + +----------------------+ + + + I am not sure but it seems some operation systems IPv6 implementation + may need interface index when add and delete linklocal routes. + + I have added ifindex field to specify IPv6 routes interface index. If + this index is value zero, it will ignored. + +Interface information message format. + + + + + + + +Ishiguro FORMFEED[Page 3] + + + + + +RFC DRAFT March 1998 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Interface name (20) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Index (1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Inteface flag (4) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Inteface metric (4) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Inteface MTU (4) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Inteface Address count (4) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Address message format. + +Host inforamtion message format. + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |IPv4 forwarding|IPv6 forwarding| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Host information contain IPv4/IPv6 forwarding information. + + + + + + + + + + + + + + + + + + + + + +Ishiguro FORMFEED[Page 4] + + diff --git a/doc/filter.texi b/doc/filter.texi new file mode 100644 index 0000000..1bc70cd --- /dev/null +++ b/doc/filter.texi @@ -0,0 +1,192 @@ +@node Filtering +@comment node-name, next, previous, up +@chapter Filtering + +Zebra provides many very flexible filtering features. Filtering is used +for both input and output of the routing information. Once filtering is +defined, it can be applied in any direction. + +@menu +* IP Access List:: +* IP Prefix List:: +@end menu + +@node IP Access List, IP Prefix List, Filtering, Filtering +@comment node-name, next, previous, up +@subsection IP Access List + +@deffn {Command} {access-list @var{name} permit @var{ipv4-network}} {} +@deffnx {Command} {access-list @var{name} deny @var{ipv4-network}} {} +@end deffn + +Basic filtering is done by @code{access-list} as shown in the +following example. + +@example +access-list filter deny 10.0.0.0/9 +access-list filter permit 10.0.0.0/8 +@end example + +@node IP Prefix List, , IP Access List, Filtering +@comment node-name, next, previous, up +@subsection IP Prefix List + +@command{ip prefix-list} provides the most powerful prefix based +filtering mechanism. In addition to @command{access-list} functionality, +@command{ip prefix-list} has prefix length range specification and +sequential number specification. You can add or delete prefix based +filters to arbitrary points of prefix-list using sequential number specification. + +If no ip prefix-list is specified, it acts as permit. If @command{ip prefix-list} +is defined, and no match is found, default deny is applied. + +@c @deffn {Command} {ip prefix-list @var{name} [seq @var{number}] permit|deny [le @var{prefixlen}] [ge @var{prefixlen}]} {} +@deffn {Command} {ip prefix-list @var{name} (permit|deny) @var{prefix} [le @var{len}] [ge @var{len}]} {} +@deffnx {Command} {ip prefix-list @var{name} seq @var{number} (permit|deny) @var{prefix} [le @var{len}] [ge @var{len}]} {} + +You can create @command{ip prefix-list} using above commands. + +@table @asis + +@item @asis{seq} +seq @var{number} can be set either automatically or manually. In the +case that sequential numbers are set manually, the user may pick any +number less than 4294967295. In the case that sequential number are set +automatically, the sequential number will increase by a unit of five (5) +per list. If a list with no specified sequential number is created +after a list with a specified sequential number, the list will +automatically pick the next multiple of five (5) as the list number. +For example, if a list with number 2 already exists and a new list with +no specified number is created, the next list will be numbered 5. If +lists 2 and 7 already exist and a new list with no specified number is +created, the new list will be numbered 10. + +@item @asis{le} +@command{le} command specifies prefix length. The prefix list will be +applied if the prefix length is less than or equal to the le prefix length. + +@item @asis{ge} +@command{ge} command specifies prefix length. The prefix list will be +applied if the prefix length is greater than or equal to the ge prefix length. + +@end table + +@end deffn + +Less than or equal to prefix numbers and greater than or equal to +prefix numbers can be used together. The order of the le and ge +commands does not matter. + +If a prefix list with a different sequential number but with the exact +same rules as a previous list is created, an error will result. +However, in the case that the sequential number and the rules are +exactly similar, no error will result. + +If a list with the same sequential number as a previous list is created, +the new list will overwrite the old list. + +Matching of IP Prefix is performed from the smaller sequential number to the +larger. The matching will stop once any rule has been applied. + +In the case of no le or ge command, + +Version 0.85: the matching rule will apply to all prefix lengths that +matched the prefix list. + +Version 0.86 or later: In the case of no le or ge command, the prefix +length must match exactly the length specified in the prefix list. + + +@deffn {Command} {no ip prefix-list @var{name}} {} +@end deffn + +@menu +* ip prefix-list description:: +* ip prefix-list sequential number control:: +* Showing ip prefix-list:: +* Clear counter of ip prefix-list:: +@end menu + +@node ip prefix-list description, ip prefix-list sequential number control, IP Prefix List, IP Prefix List +@comment node-name, next, previous, up +@subsubsection ip prefix-list description + +@deffn {Command} {ip prefix-list @var{name} description @var{desc}} {} +Descriptions may be added to prefix lists. This command adds a +description to the prefix list. +@end deffn + +@deffn {Command} {no ip prefix-list @var{name} description [@var{desc}]} {} +Deletes the description from a prefix list. It is possible to use the +command without the full description. +@end deffn + +@node ip prefix-list sequential number control, Showing ip prefix-list, ip prefix-list description, IP Prefix List +@comment node-name, next, previous, up +@subsubsection ip prefix-list sequential number control + +@deffn {Command} {ip prefix-list sequence-number} {} +With this command, the IP prefix list sequential number is displayed. +This is the default behavior. +@end deffn + +@deffn {Command} {no ip prefix-list sequence-number} {} +With this command, the IP prefix list sequential number is not +displayed. +@end deffn + +@node Showing ip prefix-list, Clear counter of ip prefix-list, ip prefix-list sequential number control, IP Prefix List +@comment node-name, next, previous, up +@subsubsection Showing ip prefix-list + +@deffn {Command} {show ip prefix-list} {} +Display all IP prefix lists. +@end deffn + +@deffn {Command} {show ip prefix-list @var{name}} {} +Show IP prefix list can be used with a prefix list name. +@end deffn + +@deffn {Command} {show ip prefix-list @var{name} seq @var{num}} {} +Show IP prefix list can be used with a prefix list name and sequential +number. +@end deffn + +@deffn {Command} {show ip prefix-list @var{name} @var{a.b.c.d/m}} {} +If the command longer is used, all prefix lists with prefix lengths equal to +or longer than the specified length will be displayed. +If the command first match is used, the first prefix length match will be +displayed. +@end deffn + +@deffn {Command} {show ip prefix-list @var{name} @var{a.b.c.d/m} longer} {} +@end deffn + +@deffn {Command} {show ip prefix-list @var{name} @var{a.b.c.d/m} first-match} {} +@end deffn + +@deffn {Command} {show ip prefix-list summary} {} +@end deffn +@deffn {Command} {show ip prefix-list summary @var{name}} {} +@end deffn + +@deffn {Command} {show ip prefix-list detail} {} +@end deffn +@deffn {Command} {show ip prefix-list detail @var{name}} {} +@end deffn + +@node Clear counter of ip prefix-list, , Showing ip prefix-list, IP Prefix List +@comment node-name, next, previous, up +@subsubsection Clear counter of ip prefix-list + +@deffn {Command} {clear ip prefix-list} {} +Clears the counters of all IP prefix lists. Clear IP Prefix List can be +used with a specified name and prefix. +@end deffn + +@deffn {Command} {clear ip prefix-list @var{name}} {} +@end deffn + +@deffn {Command} {clear ip prefix-list @var{name} @var{a.b.c.d/m}} {} +@end deffn + diff --git a/doc/install.texi b/doc/install.texi new file mode 100644 index 0000000..72c826d --- /dev/null +++ b/doc/install.texi @@ -0,0 +1,218 @@ +@node Installation, Basic commands, Overview, Top +@comment node-name, next, previous, up +@chapter Installation + +@cindex How to install Zebra +@cindex Installation +@cindex Installing Zebra +@cindex Building the system +@cindex Making Zebra + + There are three steps for installing the software: configuration, +compilation, and installation. + +@menu +* Configure the Software:: +* Build the Software:: +* Install the Software:: +@end menu + + The easiest way to get Zebra running is to issue the following +commands: + +@example +% configure +% make +% make install +@end example + +@node Configure the Software, Build the Software, Installation, Installation +@comment node-name, next, previous, up +@section Configure the Software + +@cindex Configuration options +@cindex Options for configuring +@cindex Build options +@cindex Distribution configuration +@cindex Options to @code{./configure} + + Zebra has an excellent configure script which +automatically detects most host configurations. There are several +additional configure options you can use to turn off IPv6 support, to +disable the compilation of specific daemons, and to enable SNMP support. + +@table @option +@item --enable-guile +Turn on compilation of the zebra-guile interpreter. You will need the +guile library to make this. zebra-guile implementation is not yet +finished. So this option is only useful for zebra-guile developers. +@item --disable-ipv6 +Turn off IPv6 related features and daemons. Zebra configure script +automatically detects IPv6 stack. But sometimes you might want to +disable IPv6 support of Zebra. +@item --disable-zebra +Do not build zebra daemon. +@item --disable-ripd +Do not build ripd. +@item --disable-ripngd +Do not build ripngd. +@item --disable-ospfd +Do not build ospfd. +@item --disable-ospf6d +Do not build ospf6d. +@item --disable-bgpd +Do not build bgpd. +@item --disable-bgp-announce +Make @command{bgpd} which does not make bgp announcements at all. This +feature is good for using @command{bgpd} as a BGP announcement listener. +@item --enable-netlink +Force to enable @sc{gnu}/Linux netlink interface. Zebra configure +script detects netlink interface by checking a header file. When the header +file does not match to the current running kernel, configure script will +not turn on netlink support. +@item --enable-snmp +Enable SNMP support. By default, SNMP support is disabled. +@end table + +You may specify any combination of the above options to the configure +script. By default, the executables are placed in @file{/usr/local/sbin} +and the configuration files in @file{/usr/local/etc}. The @file{/usr/local/} +installation prefix and other directories may be changed using the following +options to the configuration script. + +@table @option +@item --prefix=@var{prefix} +Install architecture-independent files in @var{prefix} [/usr/local]. +@item --sysconfdir=@var{dir} +Read-only sample configuration file in @var{dir} [@var{prefix}/etc]. +@end table + +@example +% ./configure --disable-ipv6 +@end example + +This command will configure zebra and the routing daemons. + +@cindex Configuring Zebra +@cindex Configuration the software build +@cindex Building on Linux boxes +@cindex Linux configurations + +There are several options available only to @sc{gnu}/Linux systems: +@footnote{GNU/Linux has very flexible kernel configuration features. If +you use GNU/Linux, make sure that the current kernel configuration is +what you want. Zebra will run with any kernel configuration but some +recommendations do exist. + +@table @var + +@item CONFIG_NETLINK +Kernel/User netlink socket. +This is a brand new feature which enables +an advanced interface between the Linux kernel and Zebra (@pxref{Kernel Interface}). + +@item CONFIG_RTNETLINK +Routing messages. +This makes it possible to receive netlink routing messages. If you +specify this option, @command{zebra} can detect routing information +updates directly from the kernel (@pxref{Kernel Interface}). + +@item CONFIG_IP_MULTICAST +IP: multicasting. +This option should be specified when you use @command{ripd} or +@command{ospfd} because these protocols use multicast. + +@end table + +IPv6 support has been added in @sc{gnu}/Linux kernel version 2.2. If you +try to use the Zebra IPv6 feature on a @sc{gnu}/Linux kernel, please +make sure the following libraries have been installed. Please note that +these libraries will not be needed when you uses @sc{gnu} C library 2.1 +or upper. + +@table @code + +@item inet6-apps +The @code{inet6-apps} package includes basic IPv6 related libraries such +as @code{inet_ntop} and @code{inet_pton}. Some basic IPv6 programs such +as @command{ping}, @command{ftp}, and @command{inetd} are also +included. The @code{inet-apps} can be found at +@url{ftp://ftp.inner.net/pub/ipv6/}. + +@item net-tools +The @code{net-tools} package provides an IPv6 enabled interface and +routing utility. It contains @command{ifconfig}, @command{route}, +@command{netstat}, and other tools. @code{net-tools} may be found at +@url{http://www.tazenda.demon.co.uk/phil/net-tools/}. + +@end table +@c A - end of footnote +}. + +@node Build the Software, Install the Software, Configure the Software, Installation +@comment node-name, next, previous, up +@section Build the Software + +After configuring the software, you will need to compile it for your +system. Simply issue the command @command{make} in the root of the source +directory and the software will be compiled. If you have *any* problems +at this stage, be certain to send a bug report @xref{Bug Reports}. + +@example +% ./configure +. +. +. +./configure output +. +. +. +% make +@end example +@c A - End of node, Building the Software + + +@node Install the Software, , Build the Software, Installation +@comment node-name, next, previous, up +@section Install the Software + +Installing the software to your system consists of copying the compiled +programs and supporting files to a standard location. After the +installation process has completed, these files have been copied +from your work directory to @file{/usr/local/bin}, and @file{/usr/local/etc}. + +To install the Zebra suite, issue the following command at your shell +prompt: @command{make install}. + +@example +% +% make install +% +@end example + +@c A - removed this section and placed it with Install the Software +@c @node Additional Notes, , Install the Software, Installation +@comment node-name, next, previous, up +@c @section Additional Notes + +Zebra daemons have their own terminal interface or VTY. After +installation, you have to setup each beast's port number to connect to +them. Please add the following entries to @file{/etc/services}. + +@example +zebrasrv 2600/tcp # zebra service +zebra 2601/tcp # zebra vty +ripd 2602/tcp # RIPd vty +ripngd 2603/tcp # RIPngd vty +ospfd 2604/tcp # OSPFd vty +bgpd 2605/tcp # BGPd vty +ospf6d 2606/tcp # OSPF6d vty +@end example + +If you use a FreeBSD newer than 2.2.8, the above entries are already +added to @file{/etc/services} so there is no need to add it. If you +specify a port number when starting the daemon, these entries may not be +needed. + +You may need to make changes to the config files in +@file{@value{INSTALL_PREFIX_ETC}/*.conf}. @xref{Config Commands}. diff --git a/doc/ipv6.texi b/doc/ipv6.texi new file mode 100644 index 0000000..c24d145 --- /dev/null +++ b/doc/ipv6.texi @@ -0,0 +1,32 @@ +@node IPv6 Support, Kernel Interface, Route Map, Top +@comment node-name, next, previous, up +@chapter IPv6 Support + +Zebra fully supports IPv6 routing. As described so far, Zebra supports +RIPng, OSPFv3 and BGP-4+. You can give IPv6 addresses to an interface +and configure static IPv6 routing information. Zebra-IPv6 also provides +automatic address configuration via a feature called @code{address +auto configuration}. To do it, the router must send router advertisement +messages to the all nodes that exist on the network. + +@menu +* Router Advertisement:: +@end menu + +@node Router Advertisement, , IPv6 Support, IPv6 Support +@comment node-name, next, previous, up +@section Router Advertisement + +@deffn {Interface Command} {ipv6 nd send-ra} {} +@end deffn + +@deffn {Interface Command} {ipv6 nd prefix-advertisement @var{ipv6prefix}} {} +@end deffn + +@example +@group +interface eth0 + ipv6 nd send-ra + ipv6 nd prefix-advertisement 3ffe:506:5009::/64 +@end group +@end example diff --git a/doc/kernel.texi b/doc/kernel.texi new file mode 100644 index 0000000..b863a1f --- /dev/null +++ b/doc/kernel.texi @@ -0,0 +1,48 @@ +@node Kernel Interface, SNMP Support, IPv6 Support, Top +@comment node-name, next, previous, up +@chapter Kernel Interface + +There are several different methods for reading kernel routing table +information, updating kernel routing tables, and for looking up +interfaces. + +@table @samp + +@item ioctl +The @samp{ioctl} method is a very traditional way for reading or writing +kernel information. @samp{ioctl} can be used for looking up interfaces +and for modifying interface addresses, flags, mtu settings and other +types of information. Also, @samp{ioctl} can insert and delete kernel +routing table entries. It will soon be available on almost any platform +which zebra supports, but it is a little bit ugly thus far, so if a +better method is supported by the kernel, zebra will use that. + +@item sysctl +@samp{sysctl} can lookup kernel information using MIB (Management +Information Base) syntax. Normally, it only provides a way of getting +information from the kernel. So one would usually want to change kernel +information using another method such as @samp{ioctl}. + +@item proc filesystem +@samp{proc filesystem} provides an easy way of getting kernel +information. + +@item routing socket + +@item netlink +On recent Linux kernels (2.0.x and 2.2.x), there is a kernel/user +communication support called @code{netlink}. It makes asynchronous +communication between kernel and Zebra possible, similar to a routing +socket on BSD systems. + +Before you use this feature, be sure to select (in kernel configuration) +the kernel/netlink support option 'Kernel/User network link driver' and +'Routing messages'. + +Today, the /dev/route special device file is obsolete. Netlink +communication is done by reading/writing over netlink socket. + +After the kernel configuration, please reconfigure and rebuild Zebra. +You can use netlink as a dynamic routing update channel between Zebra +and the kernel. +@end table diff --git a/doc/main.texi b/doc/main.texi new file mode 100644 index 0000000..7043bf1 --- /dev/null +++ b/doc/main.texi @@ -0,0 +1,186 @@ +@node Zebra +@comment node-name, next, previous, up +@chapter Zebra + +@c SYNOPSIS +@command{zebra} is an IP routing manager. It provides kernel routing +table updates, interface lookups, and redistribution of routes between +different routing protocols. + +@menu +* Invoking zebra:: Running the program +* Interface Commands:: Commands for zebra interfaces +* Static Route Commands:: Commands for adding static routes +* zebra Terminal Mode Commands:: Commands for zebra's VTY +@end menu + + +@node Invoking zebra, Interface Commands, Zebra, Zebra +@comment node-name, next, previous, up +@section Invoking zebra + +Besides the common invocation options (@pxref{Common Invocation Options}), the +@command{zebra} specific invocation options are listed below. + +@table @samp +@item -b +@itemx --batch +Runs in batch mode. @command{zebra} parses configuration file and terminates +immediately. + +@item -k +@itemx --keep_kernel +When zebra starts up, don't delete old self inserted routes. + +@item -l +@itemx --log_mode +Set verbose logging on. + +@item -r +@itemx --retain +When program terminates, retain routes added by zebra. + +@end table + +@node Interface Commands, Static Route Commands, Invoking zebra, Zebra +@comment node-name, next, previous, up +@section Interface Commands + +@deffn Command {interface @var{ifname}} {} +@end deffn + +@deffn {Interface Command} {shutdown} {} +@deffnx {Interface Command} {no shutdown} {} +Up or down the current interface. +@end deffn + +@deffn {Interface Command} {ip address @var{address}} {} +Set ip address for the interface. +@end deffn + +@deffn {Interface Command} {description @var{description} ...} {} +Set description for the interface. +@end deffn + +@deffn {Interface Command} {multicast} {} +@deffnx {Interface Command} {no multicast} {} +Enable or disables multicast flag for the interface. +@end deffn + +@deffn {Interface Command} {bandwidth <1-10000000>} {} +@deffnx {Interface Command} {no bandwidth <1-10000000>} {} +Set bandwidth value to the interface. This is for calculating OSPF +cost. This command does not affect the actual device configuration. +@end deffn + +@node Static Route Commands, zebra Terminal Mode Commands, Interface Commands, Zebra +@comment node-name, next, previous, up +@section Static Route Commands + +Static routing is a very fundamental feature of routing technology. It +defines static prefix and gateway. + +@deffn Command {ip route @var{network} @var{gateway}} {} +@var{network} is destination prefix with format of A.B.C.D/M. +@var{gateway} is gateway for the prefix. When @var{gateway} is +A.B.C.D format. It is taken as a IPv4 address gateway. Otherwise it +is treated as an interface name. + +@example +ip route 10.0.0.0/8 10.0.0.2 +ip route 10.0.0.0/8 ppp0 +@end example + +First example defines 10.0.0.0/8 static route with gateway 10.0.0.2. +Second one defines the same prefix but with gateway to interface ppp0. +@end deffn + +@deffn Command {ip route @var{network} @var{netmask} @var{gateway}} {} +This is alternate version of above command. When @var{network} is +A.B.C.D format, user must define @var{netmask} value with A.B.C.D +format. @var{gateway} is same option as above command + +@example +ip route 10.0.0.0 255.255.255.0 10.0.0.2 +ip route 10.0.0.0 255.255.255.0 ppp0 +@end example + +This is a same setting using this statement. +@end deffn + +@deffn Command {ip route @var{network} @var{gateway} @var{distance}} {} + +@end deffn + +Multiple nexthop static route + +@example +ip route 10.0.0.1/32 10.0.0.2 +ip route 10.0.0.1/32 10.0.0.3 +ip route 10.0.0.1/32 eth0 +@end example + +If there is no route to 10.0.0.2 and 10.0.0.3, and interface eth0 +is reachable, then the last route is installed into the kernel. + +@example +zebra> show ip route +S> 10.0.0.1/32 [1/0] via 10.0.0.2 inactive + via 10.0.0.3 inactive + * is directly connected, eth0 +@end example + +Floating static route + +@deffn Command {ipv6 route @var{network} @var{gateway}} {} + +@end deffn + +@deffn Command {ipv6 route @var{network} @var{gateway} @var{distance}} {} + +@end deffn + + +@deffn Command {table @var{tableno}} {} +Select the primary kernel routing table to be used. This only works +for kernels supporting multiple routing tables (like GNU/Linux 2.2.x +and later). After setting @var{tableno} with this command, +static routes defined after this are added to the specified table. +@end deffn + +@node zebra Terminal Mode Commands, , Static Route Commands, Zebra +@comment node-name, next, previous, up +@section zebra Terminal Mode Commands + +@deffn Command {show ip route} {} +Display current routes which zebra holds in its database. + +@example +@group +Router# show ip route +Codes: K - kernel route, C - connected, S - static, R - RIP, + B - BGP * - FIB route. + +K* 0.0.0.0/0 203.181.89.241 +S 0.0.0.0/0 203.181.89.1 +C* 127.0.0.0/8 lo +C* 203.181.89.240/28 eth0 +@end group +@end example +@end deffn + +@deffn Command {show ipv6 route} {} +@end deffn + +@deffn Command {show interface} {} +@end deffn + +@deffn Command {show ipforward} {} +Display whether the host's IP forwarding function is enabled or not. +Almost any UNIX kernel can be configured with IP forwarding disabled. +If so, the box can't work as a router. +@end deffn + +@deffn Command {show ipv6forward} {} +Display whether the host's IP v6 forwarding is enabled or not. +@end deffn diff --git a/doc/ospf6d.8 b/doc/ospf6d.8 new file mode 100644 index 0000000..1882c10 --- /dev/null +++ b/doc/ospf6d.8 @@ -0,0 +1,127 @@ +.TH OSPF6D 8 "July 2000" "Zebra Beast - OSPF6D" "Version 0.88" + +.SH NAME +ospf6d \- an OSPF routing engine for use with Zebra and IPv6 + +.SH SYNOPSIS +.B ospf6d +[ +.B \-dhv +] +[ +.B \-f config-file +] +[ +.B \-i pid-file +] +[ +.B \-P port-number +] + +.SH DESCRIPTION +.B ospf6d +is a routing component that works with the +.B zebra +routing engine. +\fBospf6d\fR. + + +.SH OPTIONS + +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. + +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this +option will likely default to \fB\fI/usr/local/etc/ospf6d.conf\fR. + +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. + +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When ospf6d starts its process idenifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart ospf6d. The likely default is \fB\fI/var/run/ospf6d.pid\fR. + +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the ospf6d VTY will listen on. This defaults to +2606, as specified in \fB\fI/etc/services\fR. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. + + +.SH COMMANDS + +\fB router ospf6 \fR +\fB router zebra \fR -- (Move routes into kernel table) + +\fB network [NETWORK] area [OSPF6-AREA-ID] \fR +\fB no network [NETWORK] \fR + +\fB show ip ospf6 interface \fR +\fB show ip ospf6 neighbor \fR +\fB show ip ospf6 database \fR +\fB show ip ospf6 route \fR + +\fB debug ospf6 ism \fR +\fB debug ospf6 packet \fR +\fB debug ospf6 nsm \fR + + + +.SH FILES + +.TP +.BI /usr/local/sbin/ospf6d +The default location of the +.B ospf6d +binary. + +.TP +.BI /usr/local/etc/ospf6d.conf +The default location of the +.B ospf6d +config file. + +.TP +.BI $(PWD)/ospf6d.log +If the +.B ospf6d +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBospf6d\fR. + + +.SH WARNING +This man page is intended as a quick reference for command line +options, and for config file commands. The definitive document is the +Info file \fBzebra\fR. + + +.SH DIAGNOSTICS +The ospf6d process may log to standard output, to a VTY, to a log +file, or through syslog to the system logs. \fBospf6d\fR supports many +debugging options, see the Info file, or the source for details. + + +.SH "SEE ALSO" +References to other related man pages: + +ripd(8), ripngd(8), ospfd(8), bgpd(8), zebra(8), vtysh(1) + + +.SH BUGS +.B ospf6d +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. + diff --git a/doc/ospf6d.texi b/doc/ospf6d.texi new file mode 100644 index 0000000..e3ac3d2 --- /dev/null +++ b/doc/ospf6d.texi @@ -0,0 +1,102 @@ +@node OSPFv3, BGP, OSPFv2, Top +@comment node-name, next, previous, up +@chapter OSPFv3 + +@command{ospf6d} is a daemon support OSPF version 3 for IPv6 network. +OSPF for IPv6 is described in RFC2740. + +@menu +* OSPF6 router:: +* OSPF6 area:: +* OSPF6 interface:: +* Redistribute routes to OSPF6:: +* Showing OSPF6 information:: +@end menu + +@node OSPF6 router, OSPF6 area, OSPFv3, OSPFv3 +@comment node-name, next, previous, up +@section OSPF6 router + +@deffn {Command} {router ospf6} {} +@end deffn + +@deffn {OSPF6 Command} {router-id @var{a.b.c.d}} {} +Set router's Router-ID. +@end deffn + +@deffn {OSPF6 Command} {interface @var{ifname} area @var{area}} {} +Bind interface to specified area, and start sending OSPF packets. @var{area} can +be specified as 0. +@end deffn + +@node OSPF6 area, OSPF6 interface, OSPF6 router, OSPFv3 +@comment node-name, next, previous, up +@section OSPF6 area + +Area support for OSPFv3 is not yet implemented. + +@node OSPF6 interface, Redistribute routes to OSPF6, OSPF6 area, OSPFv3 +@comment node-name, next, previous, up +@section OSPF6 interface + +@deffn {Interface Command} {ipv6 ospf6 cost COST} {} +Sets interface's output cost. Default value is 1. +@end deffn + +@deffn {Interface Command} {ipv6 ospf6 hello-interval HELLOINTERVAL} {} +Sets interface's Hello Interval. Default 40 +@end deffn + +@deffn {Interface Command} {ipv6 ospf6 dead-interval DEADINTERVAL} {} +Sets interface's Router Dead Interval. Default value is 40. +@end deffn + +@deffn {Interface Command} {ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL} {} +Sets interface's Rxmt Interval. Default value is 5. +@end deffn + +@deffn {Interface Command} {ipv6 ospf6 priority PRIORITY} {} +Sets interface's Router Priority. Default value is 1. +@end deffn + +@deffn {Interface Command} {ipv6 ospf6 transmit-delay TRANSMITDELAY} {} +Sets interface's Inf-Trans-Delay. Default value is 1. +@end deffn + +@node Redistribute routes to OSPF6, Showing OSPF6 information, OSPF6 interface, OSPFv3 +@comment node-name, next, previous, up +@section Redistribute routes to OSPF6 + +@deffn {OSPF6 Command} {redistribute static} {} +@deffnx {OSPF6 Command} {redistribute connected} {} +@deffnx {OSPF6 Command} {redistribute ripng} {} +@end deffn + +@node Showing OSPF6 information, , Redistribute routes to OSPF6, OSPFv3 +@comment node-name, next, previous, up +@section Showing OSPF6 information + +@deffn {Command} {show ipv6 ospf6 [INSTANCE_ID]} {} +INSTANCE_ID is an optional OSPF instance ID. To see router ID and OSPF +instance ID, simply type "show ipv6 ospf6 ". +@end deffn + +@deffn {Command} {show ipv6 ospf6 database} {} +This command shows LSA database summary. You can specify the type of LSA. +@end deffn + +@deffn {Command} {show ipv6 ospf6 interface} {} +To see OSPF interface configuration like costs. +@end deffn + +@deffn {Command} {show ipv6 ospf6 neighbor} {} +Shows state and chosen (Backup) DR of neighbor. +@end deffn + +@deffn {Command} {show ipv6 ospf6 request-list A.B.C.D} {} +Shows requestlist of neighbor. +@end deffn + +@deffn {Command} {show ipv6 route ospf6} {} +This command shows internal routing table. +@end deffn diff --git a/doc/ospfd.8 b/doc/ospfd.8 new file mode 100644 index 0000000..0fbfce4 --- /dev/null +++ b/doc/ospfd.8 @@ -0,0 +1,131 @@ +.TH OSPFD 8 "July 2000" "Zebra Beast - OSPFD" "Version 0.88" + +.SH NAME +ospfd \- an OSPF v2 routing engine for use with Zebra + +.SH SYNOPSIS +.B ospfd +[ +.B \-dhlv +] +[ +.B \-f config-file +] +[ +.B \-i pid-file +] +[ +.B \-P port-number +] + +.SH DESCRIPTION +.B ospfd +is a routing component that works with the +.B zebra +routing engine. + + +.SH OPTIONS + +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. + +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this +option will likely default to \fB\fI/usr/local/etc/ospfd.conf\fR. + +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. + +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When ospfd starts its process idenifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart ospfd. The likely default is \fB\fI/var/run/ospfd.pid\fR. + +.TP +\fB\-l\fR, \fB\-\-log_mode\fR +Turn verbose logging on. + +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the ospfd VTY will listen on. This defaults to +2604, as specified in \fB\fI/etc/services\fR. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. + + +.SH COMMANDS + +\fB router ospf \fR +\fB router zebra \fR -- (Move routes into kernel table) + +\fB network [NETWORK] area [OSPF-AREA-ID] \fR +\fB no network [NETWORK] \fR + +\fB show ip ospf interface \fR +\fB show ip ospf neighbor \fR +\fB show ip ospf database \fR +\fB show ip ospf route \fR + + +\fB debug ospf ism \fR +\fB debug ospf packet \fR +\fB debug ospf nsm \fR + + + +.SH FILES + +.TP +.BI /usr/local/sbin/ospfd +The default location of the +.B ospfd +binary. + +.TP +.BI /usr/local/etc/ospfd.conf +The default location of the +.B ospfd +config file. + +.TP +.BI $(PWD)/ospfd.log +If the +.B ospfd +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBospfd\fR. + + +.SH WARNING +This man page is intended as a quick reference for command line +options, and for config file commands. The definitive document is the +Info file \fBzebra\fR. + + +.SH DIAGNOSTICS +The ospfd process may log to standard output, to a VTY, to a log +file, or through syslog to the system logs. \fBospfd\fR supports many +debugging options, see the Info file, or the source for details. + + +.SH "SEE ALSO" +References to other related man pages: + +ripd(8), ripngd(8), ospf6d(8), bgpd(8), zebra(8), vtysh(1) + + +.SH BUGS +.B ospfd +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. + diff --git a/doc/ospfd.texi b/doc/ospfd.texi new file mode 100644 index 0000000..adbf45e --- /dev/null +++ b/doc/ospfd.texi @@ -0,0 +1,361 @@ +@node OSPFv2, OSPFv3, RIPng, Top +@comment node-name, next, previous, up +@chapter OSPFv2 + + OSPF version 2 is a routing protocol which described in +@asis{RFC2328} - @cite{OSPF Version 2}. OSPF is IGP (Interior Gateway +Protocols). Compared with RIP, OSPF can provide scalable network +support and faster convergence time. OSPF is widely used in large +networks such as ISP backbone and enterprise networks. + +@menu +* Configuring ospfd:: +* OSPF router:: +* OSPF area:: +* OSPF interface:: +* Redistribute routes to OSPF:: +* Showing OSPF information:: +* Debugging OSPF:: +@end menu + +@node Configuring ospfd, OSPF router, OSPFv2, OSPFv2 +@comment node-name, next, previous, up +@section Configuring ospfd + +There is no @command{ospfd} specific options. Common options can be +specified (@pxref{Common Invocation Options}) to @command{ospfd}. +@command{ospfd} needs interface information from @command{zebra}. So +please make it sure @command{zebra} is running before invoking +@command{ospfd}. + +Like other daemons, @command{ospfd} configuration is done in OSPF +specific configuration file @file{ospfd.conf}. + +@node OSPF router, OSPF area, Configuring ospfd, OSPFv2 +@comment node-name, next, previous, up +@section OSPF router + +To start OSPF process you have to specify the OSPF router. As of this +writing, @command{ospfd} does not support multiple OSPF processes. + +@deffn Command {router ospf} {} +@deffnx Command {no router ospf} {} +Enable or disable the OSPF process. @command{ospfd} does not yet +support multiple OSPF processes. So you can not specify an OSPF process +number. +@end deffn + +@deffn {OSPF Command} {ospf router-id @var{a.b.c.d}} {} +@deffnx {OSPF Command} {no ospf router-id} {} +@end deffn + +@deffn {OSPF Command} {ospf abr-type @var{type}} {} +@deffnx {OSPF Command} {no ospf abr-type @var{type}} {} +@var{type} can be cisco|ibm|shortcut|standard +More information regarding the behaviour controlled by this command can +be found in draft-ietf-ospf-abr-alt-05.txt. +Quote: "Though the definition of the Area Border Router (ABR) +in the OSPF specification does not require a router with multiple +attached areas to have a backbone connection, it is actually +necessary to provide successful routing to the inter-area and +external destinations. If this requirement is not met, all traffic +destined for the areas not connected to such an ABR or out of the +OSPF domain, is dropped. This document describes alternative ABR +behaviors implemented in Cisco and IBM routers." +@end deffn + +@deffn {OSPF Command} {ospf rfc1583compatibility} {} +@deffnx {OSPF Command} {no ospf rfc1583compatibility} {} +This rfc2328, the sucessor to rfc1583, suggests according to section +G.2 (changes) in section 16.4 a change to the path preference +algorithm that prevents possible routing loops that were possible in +the old version of OSPFv2. More specificly it demands that inter-area +paths and intra-area path are now of equal preference but still both +preferred to external paths. +@end deffn + +@deffn {OSPF Command} {passive interface @var{interface}} {} +@deffnx {OSPF Command} {no passive interface @var{interface}} {} +@end deffn + +@deffn {OSPF Command} {timers spf <0-4294967295> <0-4294967295>} {} +@deffnx {OSPF Command} {no timers spf} {} +@end deffn + +@deffn {OSPF Command} {refresh group-limit <0-10000>} {} +@deffnx {OSPF Command} {refresh per-slice <0-10000>} {} +@deffnx {OSPF Command} {refresh age-diff <0-10000>} {} +@end deffn + +@deffn {OSPF Command} {auto-cost refrence-bandwidth <1-4294967>} {} +@deffnx {OSPF Command} {no auto-cost refrence-bandwidth} {} +@end deffn + +@deffn {OSPF Command} {network @var{a.b.c.d/m} area @var{a.b.c.d}} {} +@deffnx {OSPF Command} {network @var{a.b.c.d/m} area @var{<0-4294967295>}} {} +@deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{a.b.c.d}} {} +@deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{<0-4294967295>}} {} +This command specifies the OSPF enabled interface. If the interface has +an address of 10.0.0.1/8 then the command below provides network +information to the ospf routers +@example +@group +router ospf + network 10.0.0.0/8 area 0 +@end group +@end example +the network command's mask length should be the same as the interface +address's mask. +@end deffn + +@node OSPF area, OSPF interface, OSPF router, OSPFv2 +@comment node-name, next, previous, up +@section OSPF area + +@deffn {OSPF Command} {area @var{a.b.c.d} range @var{a.b.c.d/m}} {} +@deffnx {OSPF Command} {area <0-4294967295> range @var{a.b.c.d/m}} {} +@deffnx {OSPF Command} {no area @var{a.b.c.d} range @var{a.b.c.d/m}} {} +@deffnx {OSPF Command} {no area <0-4294967295> range @var{a.b.c.d/m}} {} +@end deffn + +@deffn {OSPF Command} {area @var{a.b.c.d} range IPV4_PREFIX suppress} {} +@deffnx {OSPF Command} {no area @var{a.b.c.d} range IPV4_PREFIX suppress} {} +@deffnx {OSPF Command} {area @var{a.b.c.d} range IPV4_PREFIX substitute IPV4_PREFIX} {} +@deffnx {OSPF Command} {no area @var{a.b.c.d} range IPV4_PREFIX substitute IPV4_PREFIX} {} +@end deffn + +@deffn {OSPF Command} {area @var{a.b.c.d} virtual-link @var{a.b.c.d}} {} +@deffnx {OSPF Command} {area <0-4294967295> virtual-link @var{a.b.c.d}} {} +@deffnx {OSPF Command} {no area @var{a.b.c.d} virtual-link @var{a.b.c.d}} {} +@deffnx {OSPF Command} {no area <0-4294967295> virtual-link @var{a.b.c.d}} {} +@end deffn + +@deffn {OSPF Command} {area @var{a.b.c.d} shortcut} {} +@deffnx {OSPF Command} {area <0-4294967295> shortcut} {} +@deffnx {OSPF Command} {no area @var{a.b.c.d} shortcut} {} +@deffnx {OSPF Command} {no area <0-4294967295> shortcut} {} +@end deffn + +@deffn {OSPF Command} {area @var{a.b.c.d} stub} {} +@deffnx {OSPF Command} {area <0-4294967295> stub} {} +@deffnx {OSPF Command} {no area @var{a.b.c.d} stub} {} +@deffnx {OSPF Command} {no area <0-4294967295> stub} {} +@end deffn + +@deffn {OSPF Command} {area @var{a.b.c.d} stub no-summary} {} +@deffnx {OSPF Command} {area <0-4294967295> stub no-summary} {} +@deffnx {OSPF Command} {no area @var{a.b.c.d} stub no-summary} {} +@deffnx {OSPF Command} {no area <0-4294967295> stub no-summary} {} +@end deffn + +@deffn {OSPF Command} {area @var{a.b.c.d} default-cost <0-16777215>} {} +@deffnx {OSPF Command} {no area @var{a.b.c.d} default-cost <0-16777215>} {} +@end deffn + +@deffn {OSPF Command} {area @var{a.b.c.d} export-list NAME} {} +@deffnx {OSPF Command} {area <0-4294967295> export-list NAME} {} +@deffnx {OSPF Command} {no area @var{a.b.c.d} export-list NAME} {} +@deffnx {OSPF Command} {no area <0-4294967295> export-list NAME} {} +@end deffn + +@deffn {OSPF Command} {area @var{a.b.c.d} import-list NAME} {} +@deffnx {OSPF Command} {area <0-4294967295> import-list NAME} {} +@deffnx {OSPF Command} {no area @var{a.b.c.d} import-list NAME} {} +@deffnx {OSPF Command} {no area <0-4294967295> import-list NAME} {} +@end deffn + +@deffn {OSPF Command} {area @var{a.b.c.d} authentication} {} +@deffnx {OSPF Command} {area <0-4294967295> authentication} {} +@deffnx {OSPF Command} {no area @var{a.b.c.d} authentication} {} +@deffnx {OSPF Command} {no area <0-4294967295> authentication} {} +@end deffn + +@deffn {OSPF Command} {area @var{a.b.c.d} authentication message-digest} {} +@deffnx {OSPF Command} {area <0-4294967295> authentication message-digest} {} +@end deffn + +@node OSPF interface, Redistribute routes to OSPF, OSPF area, OSPFv2 +@comment node-name, next, previous, up +@section OSPF interface + +@deffn {Interface Command} {ip ospf authentication-key AUTH_KEY} {} +@deffnx {Interface Command} {no ip ospf authentication-key} {} +Set OSPF authentication key to a simple password. After setting @var{AUTH_KEY}, +all OSPF packets are authenticated. @var{AUTH_KEY} has length up to 8 chars. +@end deffn + +@deffn {Interface Command} {ip ospf message-digest-key KEYID md5 KEY} {} +@deffnx {Interface Command} {no ip ospf message-digest-key} {} +Set OSPF authentication key to a cryptographic password. The cryptographic +algorithm is MD5. KEYID identifies secret key used to create the message +digest. KEY is the actual message digest key up to 16 chars. +@end deffn + +@deffn {Interface Command} {ip ospf cost <1-65535>} {} +@deffnx {Interface Command} {no ip ospf cost} {} +Set link cost for the specified interface. The cost value is set to router-LSA's +metric field and used for SPF calculation. +@end deffn + +@deffn {Interface Command} {ip ospf dead-interval <1-65535>} {} +@deffnx {Interface Command} {no ip ospf dead-interval} {} +Set number of seconds for RouterDeadInterval timer value used for Wait Timer +and Inactivity Timer. This value must be the same for all routers attached +to a common network. The default value is 40 seconds. +@end deffn + +@deffn {Interface Command} {ip ospf hello-interval <1-65535>} {} +@deffnx {Interface Command} {no ip ospf hello-interval} {} +Set number of seconds for HelloInterval timer value. Setting this value, +Hello packet will be sent every timer value seconds on the specified interface. +This value must be the same for all routers attached to a common network. +The default value is 10 seconds. +@end deffn + +@deffn {Interface Command} {ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)} {} +@deffnx {Interface Command} {no ip ospf network} {} +Set explicitly network type for specifed interface. +@end deffn + +@deffn {Interface Command} {ip ospf priority <0-255>} {} +@deffnx {Interface Command} {no ip ospf priority} {} +Set RouterPriority integer value. Setting higher value, router will be more +eligible to become Designated Router. Setting the value to 0, router is no +longer eligible to Designated Router. +The default value is 1. +@end deffn + +@deffn {Interface Command} {ip ospf retransmit-interval <1-65535>} {} +@deffnx {Interface Command} {no ip ospf retransmit interval} {} +Set number of seconds for RxmtInterval timer value. This value is used +when retransmitting Database Description and Link State Request packets. +The default value is 5 seconds. +@end deffn + +@deffn {Interface Command} {ip ospf transmit-delay} {} +@deffnx {Interface Command} {no ip ospf transmit-delay} {} +Set number of seconds for InfTransDelay value. LSAs' age should be +incremented by this value when transmitting. +The default value is 1 seconds. +@end deffn + +@node Redistribute routes to OSPF, Showing OSPF information, OSPF interface, OSPFv2 +@comment node-name, next, previous, up +@section Redistribute routes to OSPF + +@deffn {OSPF Command} {redistribute (kernel|connected|static|rip|bgp)} {} +@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) @var{route-map}} {} +@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2)} {} +@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map @var{word}} {} +@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>} {} +@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map @var{word}} {} +@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>} {} +@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map @var{word}} {} +@deffnx {OSPF Command} {no redistribute (kernel|connected|static|rip|bgp)} {} +@end deffn + +@deffn {OSPF Command} {default-information originate} {} +@deffnx {OSPF Command} {default-information originate metric <0-16777214>} {} +@deffnx {OSPF Command} {default-information originate metric <0-16777214> metric-type (1|2)} {} +@deffnx {OSPF Command} {default-information originate metric <0-16777214> metric-type (1|2) route-map @var{word}} {} +@deffnx {OSPF Command} {default-information originate always} {} +@deffnx {OSPF Command} {default-information originate always metric <0-16777214>} {} +@deffnx {OSPF Command} {default-information originate always metric <0-16777214> metric-type (1|2)} {} +@deffnx {OSPF Command} {default-information originate always metric <0-16777214> metric-type (1|2) route-map @var{word}} {} +@deffnx {OSPF Command} {no default-information originate} {} +@end deffn + +@deffn {OSPF Command} {distribute-list NAME out (kernel|connected|static|rip|ospf} {} +@deffnx {OSPF Command} {no distribute-list NAME out (kernel|connected|static|rip|ospf} {} +@end deffn + +@deffn {OSPF Command} {default-metric <0-16777214>} {} +@deffnx {OSPF Command} {no default-metric} {} +@end deffn + +@deffn {OSPF Command} {distance <1-255>} {} +@deffnx {OSPF Command} {no distance <1-255>} {} +@end deffn + +@deffn {OSPF Command} {distance ospf (intra-area|inter-area|external) <1-255>} {} +@deffnx {OSPF Command} {no distance ospf} {} +@end deffn + +@deffn {Command} {router zebra} {} +@deffnx {Command} {no router zebra} {} +@end deffn + +@node Showing OSPF information, Debugging OSPF, Redistribute routes to OSPF, OSPFv2 +@comment node-name, next, previous, up +@section Showing OSPF information + +@deffn {Command} {show ip ospf} {} +@end deffn + +@deffn {Command} {show ip ospf interface [INTERFACE]} {} +@end deffn + +@deffn {Command} {show ip ospf neighbor} {} +@deffnx {Command} {show ip ospf neighbor INTERFACE} {} +@deffnx {Command} {show ip ospf neighbor detail} {} +@deffnx {Command} {show ip ospf neighbor INTERFACE detail} {} +@end deffn + +@deffn {Command} {show ip ospf database} {} +@end deffn + +@deffn {Command} {show ip ospf database (asbr-summary|external|network|router|summary)} {} +@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id}} {} +@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} adv-router @var{adv-router}} {} +@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) adv-router @var{adv-router}} {} +@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} self-originate} {} +@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) self-originate} {} +@end deffn + +@deffn {Command} {show ip ospf database max-age} {} +@end deffn + +@deffn {Command} {show ip ospf database self-originate} {} +@end deffn + +@deffn {Command} {show ip ospf refresher} {} +@end deffn + +@deffn {Command} {show ip ospf route} {} +@end deffn + +@node Debugging OSPF, , Showing OSPF information, OSPFv2 +@comment node-name, next, previous, up +@section Debugging OSPF + +@deffn {Command} {debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {} +@deffnx {Command} {no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {} +@end deffn + +@deffn {Command} {debug ospf ism} {} +@deffnx {Command} {debug ospf ism (status|events|timers)} {} +@deffnx {Command} {no debug ospf ism} {} +@deffnx {Command} {no debug ospf ism (status|events|timers)} {} +@end deffn + +@deffn {Command} {debug ospf nsm} {} +@deffnx {Command} {debug ospf nsm (status|events|timers)} {} +@deffnx {Command} {no debug ospf nsm} {} +@deffnx {Command} {no debug ospf nsm (status|events|timers)} {} +@end deffn + +@deffn {Command} {debug ospf lsa} {} +@deffnx {Command} {debug ospf lsa (generate|flooding|refresh)} {} +@deffnx {Command} {no debug ospf lsa} {} +@deffnx {Command} {no debug ospf lsa (generate|flooding|refresh)} {} +@end deffn + +@deffn {Command} {debug ospf zebra} {} +@deffnx {Command} {debug ospf zebra (interface|redistribute)} {} +@deffnx {Command} {no debug ospf zebra} {} +@deffnx {Command} {no debug ospf zebra (interface|redistribute)} {} +@end deffn + +@deffn {Command} {show debugging ospf} {} +@end deffn + diff --git a/doc/overview.texi b/doc/overview.texi new file mode 100644 index 0000000..824946d --- /dev/null +++ b/doc/overview.texi @@ -0,0 +1,353 @@ +@node Overview, Installation, Top, Top +@comment node-name, next, previous, up +@chapter Overview +@cindex Overview + + Zebra is a routing software that provides TCP/IP based routing +protocols support such as RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3, BGP-4, +and BGP-4+ (@pxref{Supported RFC}). Zebra supports both IPv4 and IPv6 +routing protocols. Zebra also supports BGP Route Reflector and BGP +Route Server functionality. With SNMP daemon which has SMUX protocol, +Zebra provides routing protocol MIBs (@pxref{SNMP Support}). + + Zebra has an advanced module based software architecture. It is +built by collection of protocol modules. Due to this design, you can +easily add a new protocol module to Zebra. You can dynamically add or +remove a protocol module even if other modules are up and runing. +Zebra library provides basic functions to implement a routing protocol +module. + + Zebra has advanced CLI (Command Line Interface). User can examine +current routing protocol status, change the configuration, save the +configuration at anytime user want. + + Zebra is a @sc{gnu} software and distributed under the @sc{gnu} +General Public License. + +@menu +* About Zebra:: Basic information about Zebra +* System Architecture:: The Zebra system architecture +* Supported Platforms:: Supported platforms and future plans +* Supported RFC:: Supported RFCs +* How to get Zebra:: +* Mailing List:: Mailing list information +* Bug Reports:: Mail address for bug data +@end menu + +@node About Zebra, System Architecture, Overview, Overview +@comment node-name, next, previous, up +@section About Zebra +@cindex About Zebra + + Today, TCP/IP networks are covering all of the world. The Internet +has been deployed in many countries, companies, and to the home. When +you connect to the Internet your packet will pass many routers which +have TCP/IP routing functionality. + + A system with Zebra installed acts as a dedicated router. With Zebra, +your machine exchanges routing information with other routers using +routing protocols. Zebra uses this information to update the kernel +routing table so that the right data goes to the right place. You can +dynamically change the configuration and you may view routing table +information from the Zebra terminal interface. + + Adding to routing protocol support, Zebra can setup interface's flags, +interface's address, static routes and so on. If you have a small +network, or a stub network, or xDSL connection, configuring the Zebra +routing software is very easy. The only thing you have to do is to set +up the interfaces and put a few commands about static routes and/or +default routes. If the network is rather large, or if the network +structure changes frequently, you will want to take advantage of Zebra's +dynamic routing protocol support for protocols such as RIP, OSPF or BGP. +Zebra is with you. + + Traditionally, UNIX based router configuration is done by +@command{ifconfig} and @command{route} commands. Status of routing +table is displayed by @command{netstat} utility. Almost of these +commands work only if the user has root privileges. Zebra has a different +system administration method. There are two user modes in Zebra. One is +normal mode, the other is enable mode. Normal mode user can only view +system status, enable mode user can change system configuration. This +UNIX account independent feature will be great help to the router +administrator. + + Currently, Zebra supports common unicast routing protocols. Multicast +routing protocols such as BGMP, PIM-SM, PIM-DM will be supported in +Zebra 2.0. MPLS support is going on. In the future, TCP/IP filtering +control, QoS control, diffserv configuration will be added to Zebra. +Zebra project's final goal is making a productive, top-quality free TCP/IP +routing software. + +@node System Architecture, Supported Platforms, About Zebra, Overview +@comment node-name, next, previous, up +@section System Architecture +@cindex System architecture +@cindex Software architecture +@cindex Software internals + + Traditional routing software is made as a one process program which +provides all of the routing protocol functionalities. Zebra takes a +different approach. It is made from a collection of several daemons +that work together to build the routing table. There may be several +protocol-specific routing daemons and zebra the kernel routing manager. + + The @command{ripd} daemon handles the RIP protocol, while +@command{ospfd} is a daemon which supports OSPF version 2. +@command{bgpd} supports the BGP-4 protocol. For changing the kernel +routing table and for redistribution of routes between different routing +protocols, there is a kernel routing table manager @command{zebra} +daemon. It is easy to add a new routing protocol daemons to the entire +routing system without affecting any other software. You need to run only +the protocol daemon associated with routing protocols in use. Thus, +user may run a specific daemon and send routing reports to a central +routing console. + + There is no need for these daemons to be running on the same machine. +You can even run several same protocol daemons on the same machine. This +architecture creates new possibilities for the routing system. + +@example +@group ++----+ +------+ +-----+ +------+ +----+ +|ripd| |ripngd| |ospfd| |ospf6d| |bgpd| ++----+ +------+ +-----+ +------+ +----+ + | | | | | + +-------+-------+--------+--+----+ + | ++------------------------------v------+ +| +-----+ | +| zebra | RIB | | +| +-----+ | ++------------------------------|------+ + | ++------------------------------v------+ +| +-----+ | +| UNIX Kernel | FIB | | +| +-----+ | ++-------------------------------------+ + + Zebra Software Architecture +@end group +@end example + + Multi-process architecture brings extensibility, modularity and +maintainability. At the same time it also brings many configuration +files and terminal interfaces. Each daemon has it's own configuration +file and terminal interface. When you configure a static route, it must +be done in @command{zebra} configuration file. When you configure BGP +network it must be done in @command{bgpd} configuration file. This can be a +very annoying thing. To resolve the problem, Zebra provides integrated +user interface shell called @command{vtysh}. @command{vtysh} connects to +each daemon with UNIX domain socket and then works as a proxy for user input. + + Zebra was planned to use multi-threaded mechanism when it runs with a +kernel that supports multi-threads. But at the moment, the thread +library which comes with @sc{gnu}/Linux or FreeBSD has some problems with +running reliable services such as routing software, so we don't use +threads at all. Instead we use the @command{select(2)} system call for +multiplexing the events. + + When @command{zebra} runs under a @sc{gnu} Hurd kernel it will act as a +kernel routing table itself. Under @sc{gnu} Hurd, all TCP/IP services are +provided by user processes called @command{pfinet}. Zebra will provide +all the routing selection mechanisms for the process. This feature will +be implemented when @sc{gnu} Hurd becomes stable. + +@node Supported Platforms, Supported RFC, System Architecture, Overview +@comment node-name, next, previous, up +@section Supported Platforms + +@cindex Supported platforms +@cindex Zebra on other systems +@cindex Compatibility with other systems +@cindex Operating systems that support Zebra + + Currently Zebra supports @sc{gnu}/Linux, BSD and Solaris. Below is a list +of OS versions on which Zebra runs. Porting Zebra to other platforms is +not so too difficult. Platform dependent codes exist only in +@command{zebra} daemon. Protocol daemons are platform independent. +Please let us know when you find out Zebra runs on a platform which is not +listed below. + +@sp 1 +@itemize @bullet +@item +GNU/Linux 2.2.x +@item +GNU/Linux 2.4.x +@item +FreeBSD 4.x +@item +FreeBSD 5.x +@item +NetBSD 1.6.x +@item +OpenBSD 3.x +@item +Solaris 8 +@end itemize + +@sp 1 + Some IPv6 stacks are in development. Zebra supports following IPv6 +stacks. For BSD, we recommend KAME IPv6 stack. Solaris IPv6 stack is +not yet supported. +@sp 1 +@itemize @bullet +@item +Linux IPv6 stack for GNU/Linux 2.2.x and higher. +@item +KAME BSD IPv6 stack +@end itemize + +@node Supported RFC, How to get Zebra, Supported Platforms, Overview +@comment node-name, next, previous, up +@section Supported RFC + + Below is the list of currently supported RFC's. + +@table @asis +@item @asis{RFC1058} +@cite{Routing Information Protocol. C.L. Hedrick. Jun-01-1988.} + +@item @asis{RF2082} +@cite{RIP-2 MD5 Authentication. F. Baker, R. Atkinson. January 1997.} + +@item @asis{RFC2453} +@cite{RIP Version 2. G. Malkin. November 1998.} + +@item @asis{RFC2080} +@cite{RIPng for IPv6. G. Malkin, R. Minnear. January 1997.} + +@item @asis{RFC2328} +@cite{OSPF Version 2. J. Moy. April 1998.} + +@item @asis{RFC2740} +@cite{OSPF for IPv6. R. Coltun, D. Ferguson, J. Moy. December 1999.} + +@item @asis{RFC1771} +@cite{A Border Gateway Protocol 4 (BGP-4). Y. Rekhter & T. Li. March 1995.} + +@item @asis{RFC1965} +@cite{Autonomous System Confederations for BGP. P. Traina. June 1996.} + +@item @asis{RFC1997} +@cite{BGP Communities Attribute. R. Chandra, P. Traina & T. Li. August 1996.} + +@item @asis{RFC2545} +@cite{Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing. P. Marques, F. Dupont. March 1999.} + +@item @asis{RFC2796} +@cite{BGP Route Reflection An alternative to full mesh IBGP. T. Bates & R. Chandrasekeran. June 1996.} + +@item @asis{RFC2858} +@cite{Multiprotocol Extensions for BGP-4. T. Bates, Y. Rekhter, R. Chandra, D. Katz. June 2000.} + +@item @asis{RFC2842} +@cite{Capabilities Advertisement with BGP-4. R. Chandra, J. Scudder. May 2000.} + +@end table + + When SNMP support is enabled, below RFC is also supported. + +@table @asis + +@item @asis{RFC1227} +@cite{SNMP MUX protocol and MIB. M.T. Rose. May-01-1991.} + +@item @asis{RFC1657} +@cite{Definitions of Managed Objects for the Fourth Version of the +Border Gateway Protocol (BGP-4) using SMIv2. S. Willis, J. Burruss, +J. Chu, Editor. July 1994.} + +@item @asis{RFC1724} +@cite{RIP Version 2 MIB Extension. G. Malkin & F. Baker. November 1994.} + +@item @asis{RFC1850} +@cite{OSPF Version 2 Management Information Base. F. Baker, R. Coltun. +November 1995.} + +@end table + +@node How to get Zebra, Mailing List, Supported RFC, Overview +@comment node-name, next, previous, up +@section How to get Zebra + + Zebra is still beta software and there is no officially +released version. So currently Zebra is distributed from Zebra beta ftp +site located at: + +@url{ftp://ftp.zebra.org/pub/zebra} + + Once Zebra is released you can get it from @sc{gnu} FTP site and +its mirror sites. We are planning Zebra-1.0 as the first released +version. + + Zebra's official web page is located at: + +@url{http://www.gnu.org/software/zebra/zebra.html}. + + There is a Zebra beta tester web page at: + +@url{http://www.zebra.org/}. + + You can get the latest beta software information from this page. + +@node Mailing List, Bug Reports, How to get Zebra, Overview +@comment node-name, next, previous, up +@section Mailing List +@cindex How to get in touch with Zebra +@cindex Mailing Zebra +@cindex Contact information +@cindex Mailing lists + + There is a mailing list for discussions about Zebra. If you have any +comments or suggestions to Zebra, please send mail to +@email{zebra@@zebra.org}. New snapshot announcements, improvement +notes, and patches are sent to the list. + + To subscribe to the @email{zebra@@zebra.org, Zebra mailing list}, +please send a mail to @email{zebra-request@@ml.zebra.org} with a message with a subject: + +@quotation +subscribe +@end quotation + + To unsubscribe from the list, please send a mail to +@email{zebra-request@@ml.zebra.org} with a message body that includes only: + +@quotation +unsubscribe +@end quotation + +@node Bug Reports, , Mailing List, Overview +@comment node-name, next, previous, up +@section Bug Reports + +@cindex Bug Reports +@cindex Bug hunting +@cindex Found a bug? +@cindex Reporting bugs +@cindex Reporting software errors +@cindex Errors in the software + + If you think you have found a bug, please send a bug report to +@email{bug-zebra@@gnu.org}. When you send a bug report, please be +careful about the points below. + +@itemize @bullet +@item +Please note what kind of OS you are using. If you use the IPv6 stack +please note that as well. +@item +Please show us the results of @code{netstat -rn} and @code{ifconfig -a}. +Information from zebra's VTY command @code{show ip route} will also be +helpful. +@item +Please send your configuration file with the report. If you specify +arguments to the configure script please note that too. +@end itemize + + Bug reports are very important for us to improve the quality of Zebra. +Zebra is still in the development stage, but please don't hesitate to +send a bug report to @email{bug-zebra@@gnu.org}. + diff --git a/doc/protocol.texi b/doc/protocol.texi new file mode 100644 index 0000000..7cae9c9 --- /dev/null +++ b/doc/protocol.texi @@ -0,0 +1,52 @@ +@node Zebra Protocol, Packet Binary Dump Format, SNMP Support, Top +@comment node-name, next, previous, up +@appendix Zebra Protocol + +Zebra Protocol is a protocol which is used between protocol daemon and +zebra. Each protocol daemon sends selected routes to zebra daemon. Then +zebra manages which route is installed into the forwarding table. + +Zebra Protocol is a TCP-based protocol. Below is common header of Zebra +Protocol. + +@example +@group +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Length (2) | Command (1) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example + +Length is total packet length including this header length. So minimum +length is three. Command is Zebra Protocol command. + +@example +ZEBRA_INTERFACE_ADD 1 +ZEBRA_INTERFACE_DELETE 2 +ZEBRA_INTERFACE_ADDRESS_ADD 3 +ZEBRA_INTERFACE_ADDRESS_DELETE 4 +ZEBRA_INTERFACE_UP 5 +ZEBRA_INTERFACE_DOWN 6 +ZEBRA_IPV4_ROUTE_ADD 7 +ZEBRA_IPV4_ROUTE_DELETE 8 +ZEBRA_IPV6_ROUTE_ADD 9 +ZEBRA_IPV6_ROUTE_DELETE 10 +ZEBRA_REDISTRIBUTE_ADD 11 +ZEBRA_REDISTRIBUTE_DELETE 12 +ZEBRA_REDISTRIBUTE_DEFAULT_ADD 13 +ZEBRA_REDISTRIBUTE_DEFAULT_DELETE 14 +ZEBRA_IPV4_NEXTHOP_LOOKUP 15 +ZEBRA_IPV6_NEXTHOP_LOOKUP 16 +@end example + +@example +@group +0 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Type | Flags | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +@end group +@end example diff --git a/doc/ripd.8 b/doc/ripd.8 new file mode 100644 index 0000000..e15989f --- /dev/null +++ b/doc/ripd.8 @@ -0,0 +1,212 @@ +.TH RIPD 8 "July 2000" "Zebra" "Version 0.88" + +.SH NAME +ripd \- a RIP routing engine for use with Zebra + +.SH SYNOPSIS +.B ripd +[ +.B \-dhrv +] +[ +.B \-f config-file +] +[ +.B \-i pid-file +] +[ +.B \-P port-number +] + +.SH DESCRIPTION +.B ripd +is a routing component that supports the +.B zebra +route engine. +.B ripd +supports RIPv1, RIPv2, and so forth. + + +.SH OPTIONS + +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. + +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/ripd.conf\fR. + +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. + +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When ripd starts its process idenifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart ripd. The likely default is \fB\fI/var/run/ripd.pid\fR. + +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the ripd VTY will listen on. This defaults to +2602, as specified in \fB\fI/etc/services\fR. + +.TP +\fB\-r\fR, \fB\-\-retain\fR +When the program terminates, retain routes added by \fBripd\fR. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. + + +.SH COMMANDS + +\fB router rip \fR +\fB no router rip \fR + +\fB rip version [1|2] \fR +\fB no rip version [1|2] \fR + +\fB network [A.B.C.D/M] \fR +\fB no network [A.B.C.D/M] \fR + +\fB network [IFNAME] \fR +\fB no network [IFNAME] \fR + +\fB neighbor [A.B.C.D] \fR +\fB no neighbor [A.B.C.D] \fR + +\fB redistribute kernel \fR +\fB redistribute kernel metric [METRIC]\fR +\fB redistribute kernel route-map [ROUTE-MAP]\fR +\fB no redistribute kernel \fR + +\fB redistribute static \fR +\fB redistribute static metric [METRIC]\fR +\fB redistribute static route-map [ROUTE-MAP]\fR +\fB no redistribute static \fR + +\fB redistribute connected \fR +\fB redistribute connected metric [METRIC]\fR +\fB redistribute connected route-map [ROUTE-MAP]\fR +\fB no redistribute connected \fR + +\fB redistribute ospf \fR +\fB redistribute ospf metric [METRIC]\fR +\fB redistribute ospf route-map [ROUTE-MAP]\fR +\fB no redistribute ospf \fR + +\fB redistribute bgp \fR +\fB redistribute bgp metric [METRIC]\fR +\fB redistribute bgp route-map [ROUTE-MAP]\fR +\fB no redistribute bgp \fR + +\fB route [A.B.C.D/M] \fR +\fB no route [A.B.C.D/M] \fR + +\fB default-information originate \fR +\fB no default-information originate \fR + +\fB default-metric [METRIC] \fR +\fB no default-metric [METRIC] \fR + +\fB passive-interface [IFNAME] \fR +\fB no passive-interface [IFNAME] \fR + +\fB offset-list [ACCESS-LIST] [in|out]\fR +\fB offset-list [ACCESS-LIST] [in|out] [IFNAME]\fR +\fB no offset-list [ACCESS-LIST] [in|out]\fR + +\fB timers basic [UPDATE-INTERVAL] [INVALID] [TIMEOUT] [GARBAGE-COLLECT] \fR +\fB no timers basic \fR + +\fB distribute-list [ACCESS-LIST] [in|out] [IFNAME] \fR +\fB no distribute-list [ACCESS-LIST] [in|out] [IFNAME] \fR + +\fB distribute-list prefix [PREFIX-LIST] [in|out] [IFNAME] \fR +\fB no distribute-list prefix [PREFIX-LIST] [in|out] [IFNAME] \fR + +\fB distance [DISTANCE] \fR +\fB no distance [DISTANCE] \fR + +\fB distance [DISTANCE] [A.B.C.D/M] \fR +\fB no distance [DISTANCE] [A.B.C.D/M] \fR + +\fB distance [DISTANCE] [A.B.C.D/M] [ACCESS-LIST]\fR +\fB no distance [DISTANCE] [A.B.C.D/M] [ACCESS-LIST]\fR + +\fB ip rip send version [VERSION] \fR +\fB no ip rip send version [VERSION] \fR +\fB ip rip receive version [VERSION] \fR +\fB no ip rip receive version [VERSION] \fR + +\fB ip rip authentication mode [md5|text]\fR +\fB no ip rip authentication mode [md5|text]\fR + +\fB ip rip authentication key-chain [KEY-CHAIN]\fR +\fB no ip rip authentication key-chain [KEY-CHAIN]\fR + +\fB ip rip authentication string [STRING]\fR +\fB no ip rip authentication string [STRING]\fR + +\fB ip spli-horizon\fR +\fB no ip spli-horizon\fR + +\fB show ip rip \fR +\fB show ip protocols \fR +\fB show debugging rip \fR + +\fB debug rip \fR +\fB debug rip events \fR +\fB debug rip packet \fR +\fB debug rip zebra \fR + +.SH FILES + +.TP +.BI /usr/local/sbin/ripd +The default location of the +.B ripd +binary. + +.TP +.BI /usr/local/etc/ripd.conf +The default location of the +.B ripd +config file. + +.TP +.BI $(PWD)/ripd.log +If the +.B ripd +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBripd\fR. + + +.SH WARNING +This man page is intended as a quick reference for command line options, and for config file commands. The definitive document is the Info file \fBzebra\fR. + + +.SH DIAGNOSTICS +The ripd process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. +.B ripd +supports many debugging options, see the Info file, or the source for details. + + +.SH "SEE ALSO" +References to other related man pages: + +ripngd(8), ospfd(8), ospf6d(8), bgpd(8), zebra(8) + + + +.SH BUGS +.B ripd +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. diff --git a/doc/ripd.texi b/doc/ripd.texi new file mode 100644 index 0000000..d598ca6 --- /dev/null +++ b/doc/ripd.texi @@ -0,0 +1,584 @@ +@c -*-texinfo-*- +@c This is part of the GNU Zebra Manual. +@c Copyright (C) 1999, 2000 Kunihiro Ishiguro +@c See file zebra.texi for copying conditions. +@node RIP +@comment node-name, next, previous, up +@chapter RIP + +RIP -- Routing Information Protocol is widely deployed interior gateway +protocol. RIP was developed in the 1970s at Xerox Labs as part of the +XNS routing protocol. RIP is a @dfn{distance-vector} protocol and is +based on the @dfn{Bellman-Ford} algorithms. As a distance-vector +protocol, RIP router send updates to its neighbors periodically, thus +allowing the convergence to a known topology. In each update, the +distance to any given network will be broadcasted to its neighboring +router. + +@command{ripd} supports RIP version 2 as described in RFC2453 and RIP +version 1 as described in RFC1058. + +@menu +* Starting and Stopping ripd:: +* RIP Configuration:: +* How to Announce RIP route:: +* Filtering RIP Routes:: +* RIP Metric Manipulation:: +* RIP distance:: +* RIP route-map:: +* RIP Authentication:: +* RIP Timers:: +* Show RIP Information:: +* RIP Debug Commands:: +@end menu + +@node Starting and Stopping ripd, RIP Configuration, RIP, RIP +@comment node-name, next, previous, up +@section Starting and Stopping ripd + +The default configuration file name of @command{ripd}'s is +@file{ripd.conf}. When invocation @command{ripd} searches directory +@value{INSTALL_PREFIX_ETC}. If @file{ripd.conf} is not there next +search current directory. + +RIP uses UDP port 521 to send and receive RIP packets. So the user must have +the capability to bind the port, generally this means that the user must +have superuser privileges. RIP protocol requires interface information +maintained by @command{zebra} daemon. So running @command{zebra} +is mandatory to run @command{ripd}. Thus minimum sequence for running +RIP is like below: + +@example +@group +# zebra -d +# ripd -d +@end group +@end example + +Please note that @command{zebra} must be invoked before @command{ripd}. + +To stop @command{ripd}. Please use @command{kill `cat +/var/run/ripd.pid`}. Certain signals have special meaningss to @command{ripd}. + +@table @samp +@item SIGHUP +Reload configuration file @file{ripd.conf}. All configurations are +reseted. All routes learned so far are cleared and removed from routing +table. +@item SIGUSR1 +Rotate @command{ripd} logfile. +@item SIGINT +@itemx SIGTERM +@command{ripd} sweeps all installed RIP routes then terminates properly. +@end table + +@command{ripd} invocation options. Common options that can be specified +(@pxref{Common Invocation Options}). + +@table @samp +@item -r +@itemx --retain +When the program terminates, retain routes added by @command{ripd}. +@end table + +@menu +* RIP netmask:: +@end menu + +@node RIP netmask, , Starting and Stopping ripd, Starting and Stopping ripd +@comment node-name, next, previous, up +@subsection RIP netmask + +The netmask features of @command{ripd} support both version 1 and version 2 of +RIP. Version 1 of RIP originally contained no netmask information. In +RIP version 1, network classes were originally used to determine the +size of the netmask. Class A networks use 8 bits of mask, Class B +networks use 16 bits of masks, while Class C networks use 24 bits of +mask. Today, the most widely used method of a network mask is assigned +to the packet on the basis of the interface that received the packet. +Version 2 of RIP supports a variable length subnet mask (VLSM). By +extending the subnet mask, the mask can be divided and reused. Each +subnet can be used for different purposes such as large to middle size +LANs and WAN links. Zebra @command{ripd} does not support the non-sequential +netmasks that are included in RIP Version 2. + +In a case of similar information with the same prefix and metric, the +old information will be suppressed. Ripd does not currently support +equal cost multipath routing. + + +@node RIP Configuration, How to Announce RIP route, Starting and Stopping ripd, RIP +@comment node-name, next, previous, up +@section RIP Configuration + +@deffn Command {router rip} {} +The @code{router rip} command is necessary to enable RIP. To disable +RIP, use the @code{no router rip} command. RIP must be enabled before +carrying out any of the RIP commands. +@end deffn + +@deffn Command {no rouer rip} {} +Disable RIP. +@end deffn + +RIP can be configured to process either Version 1 or Version 2 packets, +the default mode is Version 2. If no version is specified, then the RIP +daemon will default to Version 2. If RIP is set to Version +1, the setting "Version 1" will be displayed, but the setting "Version +2" will not be displayed whether or not Version 2 is set explicitly as +the version of RIP being used. + +@deffn {RIP Command} {network @var{network}} {} +@deffnx {RIP Command} {no network @var{network}} {} +Set the RIP enable interface by @var{network}. The interfaces which +have addresses matching with @var{network} are enabled. + +This group of commands either enables or disables RIP interfaces between +certain numbers of a specified network address. For example, if the +network for 10.0.0.0/24 is RIP enabled, this would result in all the +addresses from 10.0.0.0 to 10.0.0.255 being enabled for RIP. The @code{no +network} command will disable RIP for the specified network. +@end deffn + +@deffn {RIP Command} {network @var{ifname}} {} +@deffnx {RIP Command} {no network @var{ifname}} {} +Set a RIP enabled interface by @var{ifname}. Both the sending and +receiving of RIP packets will be enabled on the port specified in the +@code{network ifname} command. The @code{no network ifname} command will disable +RIP on the specified interface. +@end deffn + +@deffn {RIP Command} {neighbor @var{a.b.c.d}} {} +@deffnx {RIP Command} {no neighbor @var{a.b.c.d}} {} +Specify RIP neighbor. When a neighbor doesn't understand multicast, +this command is used to specify neighbors. In some cases, not all +routers will be able to understand multicasting, where packets are sent +to a network or a group of addresses. In a situation where a neighbor +cannot process multicast packets, it is necessary to establish a direct +link between routers. The neighbor command allows the network +administrator to specify a router as a RIP neighbor. The @code{no +neighbor a.b.c.d} command will disable the RIP neighbor. +@end deffn + +Below is very simple RIP configuration. Interface @code{eth0} and +interface which address match to @code{10.0.0.0/8} are RIP enabled. + +@example +@group +! +router rip + network 10.0.0.0/8 + network eth0 +! +@end group +@end example + +Passive interface + +@deffn {RIP command} {passive-interface @var{IFNAME}} {} +@deffnx {RIP command} {no passive-interface @var{IFNAME}} {} +This command sets the specified interface to passive mode. On passive mode +interface, all receiving packets are processed as normal and ripd does +not send either multicast or unicast RIP packets except to RIP neighbors +specified with @code{neighbor} command. +@end deffn + +RIP version handling + +@deffn {RIP Command} {version @var{version}} {} +Set RIP process's version. @var{version} can be ``1'' or ``2''. +@end deffn + +@deffn {Interface command} {ip rip send version @var{version}} {} +@var{version} can be `1', `2', `1 2'. This configuration command +overrides the router's rip version setting. The command will enable the +selected interface to send packets with RIP Version 1, RIP Version 2, or +both. In the case of '1 2', packets will be both broadcast and +multicast. +@end deffn + +@deffn {Interface command} {ip rip receive version @var{version}} {} +Version setting for incoming RIP packets. This command will enable the +selected interface to receive packets in RIP Version 1, RIP Version 2, +or both. +@end deffn + +RIP split-horizon + +@deffn {Interface command} {ip split-horizon} {} +@deffnx {Interface command} {no ip split-horizon} {} +Control split-horizon on the interface. Default is @code{ip +split-horizon}. If you don't perform split-horizon on the interface, +please specify @code{no ip split-horizon}. +@end deffn + +@node How to Announce RIP route, Filtering RIP Routes, RIP Configuration, RIP +@comment node-name, next, previous, up +@section How to Announce RIP route + +@deffn {RIP command} {redistribute kernel} {} +@deffnx {RIP command} {redistribute kernel metric <0-16>} {} +@deffnx {RIP command} {redistribute kernel route-map @var{route-map}} {} +@deffnx {RIP command} {no redistribute kernel} {} +@code{redistribute kernel} redistributes routing information from +kernel route entries into the RIP tables. @code{no redistribute kernel} +disables the routes. +@end deffn + +@deffn {RIP command} {redistribute static} {} +@deffnx {RIP command} {redistribute static metric <0-16>} {} +@deffnx {RIP command} {redistribute static route-map @var{route-map}} {} +@deffnx {RIP command} {no redistribute static} {} +@code{redistribute static} redistributes routing information from +static route entries into the RIP tables. @code{no redistribute static} +disables the routes. +@end deffn + +@deffn {RIP command} {redistribute connected} {} +@deffnx {RIP command} {redistribute connected metric <0-16>} {} +@deffnx {RIP command} {redistribute connected route-map @var{route-map}} {} +@deffnx {RIP command} {no redistribute connected} {} +Redistribute connected routes into the RIP tables. @code{no +redistribute connected} disables the connected routes in the RIP tables. +This command redistribute connected of the interface which RIP disabled. +The connected route on RIP enabled interface is announced by default. +@end deffn + +@deffn {RIP command} {redistribute ospf} {} +@deffnx {RIP command} {redistribute ospf metric <0-16>} {} +@deffnx {RIP command} {redistribute ospf route-map @var{route-map}} {} +@deffnx {RIP command} {no redistribute ospf} {} +@code{redistribute ospf} redistributes routing information from +ospf route entries into the RIP tables. @code{no redistribute ospf} +disables the routes. +@end deffn + +@deffn {RIP command} {redistribute bgp} {} +@deffnx {RIP command} {redistribute bgp metric <0-16>} {} +@deffnx {RIP command} {redistribute bgp route-map @var{route-map}} {} +@deffnx {RIP command} {no redistribute bgp} {} +@code{redistribute bgp} redistributes routing information from +bgp route entries into the RIP tables. @code{no redistribute bgp} +disables the routes. +@end deffn + +If you want to specify RIP only static routes: + +@deffn {RIP command} {default-information originate} {} +@end deffn + +@deffn {RIP command} {route @var{a.b.c.d/m}} {} +@deffnx {RIP command} {no route @var{a.b.c.d/m}} {} +This command is specific to Zebra. The @code{route} command makes a static +route only inside RIP. This command should be used only by advanced +users who are particularly knowledgeable about the RIP protocol. In +most cases, we recommend creating a static route in Zebra and +redistributing it in RIP using @code{redistribute static}. +@end deffn + + +@node Filtering RIP Routes, RIP Metric Manipulation, How to Announce RIP route, RIP +@comment node-name, next, previous, up +@section Filtering RIP Routes + +RIP routes can be filtered by a distribute-list. + +@deffn Command {distribute-list @var{access_list} @var{direct} @var{ifname}} {} +You can apply access lists to the interface with a @code{distribute-list} +command. @var{access_list} is the access list name. @var{direct} is +@samp{in} or @samp{out}. If @var{direct} is @samp{in} the access list +is applied to input packets. + +The @code{distribute-list} command can be used to filter the RIP path. +@code{distribute-list} can apply access-lists to a chosen interface. +First, one should specify the access-list. Next, the name of the +access-list is used in the distribute-list command. For example, in the +following configuration @samp{eth0} will permit only the paths that +match the route 10.0.0.0/8 + +@example +@group +! +router rip + distribute-list private in eth0 +! +access-list private permit 10 10.0.0.0/8 +access-list private deny any +! +@end group +@end example +@end deffn + +@code{distribute-list} can be applied to both incoming and outgoing data. + +@deffn Command {distribute-list prefix @var{prefix_list} (in|out) @var{ifname}} {} +You can apply prefix lists to the interface with a +@code{distribute-list} command. @var{prefix_list} is the prefix list +name. Next is the direction of @samp{in} or @samp{out}. If +@var{direct} is @samp{in} the access list is applied to input packets. +@end deffn + +@node RIP Metric Manipulation, RIP distance, Filtering RIP Routes, RIP +@comment node-name, next, previous, up +@section RIP Metric Manipulation + +RIP metric is a value for distance for the network. Usually +@command{ripd} increment the metric when the network information is +received. Redistributed routes' metric is set to 1. + +@deffn {RIP command} {default-metric <1-16>} {} +@deffnx {RIP command} {no default-metric <1-16>} {} +This command modifies the default metric value for redistributed routes. The +default value is 1. This command does not affect connected route +even if it is redistributed by @command{redistribute connected}. To modify +connected route's metric value, please use @command{redistribute +connected metric} or @command{route-map}. @command{offset-list} also +affects connected routes. +@end deffn + +@deffn {RIP command} {offset-list @var{access-list} (in|out)} {} +@deffnx {RIP command} {offset-list @var{access-list} (in|out) @var{ifname}} {} +@end deffn + +@node RIP distance, RIP route-map, RIP Metric Manipulation, RIP +@comment node-name, next, previous, up +@section RIP distance + +Distance value is used in zebra daemon. Default RIP distance is 120. + +@deffn {RIP command} {distance <1-255>} {} +@deffnx {RIP command} {no distance <1-255>} {} +Set default RIP distance to specified value. +@end deffn + +@deffn {RIP command} {distance <1-255> @var{A.B.C.D/M}} {} +@deffnx {RIP command} {no distance <1-255> @var{A.B.C.D/M}} {} +Set default RIP distance to specified value when the route's source IP +address matches the specified prefix. +@end deffn + +@deffn {RIP command} {distance <1-255> @var{A.B.C.D/M} @var{access-list}} {} +@deffnx {RIP command} {no distance <1-255> @var{A.B.C.D/M} @var{access-list}} {} +Set default RIP distance to specified value when the route's source IP +address matches the specified prefix and the specified access-list. +@end deffn + +@node RIP route-map, RIP Authentication, RIP distance, RIP +@comment node-name, next, previous, up +@section RIP route-map + +Usage of @command{ripd}'s route-map support. + +Optional argument route-map MAP_NAME can be added to each @code{redistribute} +statement. + +@example +redistribute static [route-map MAP_NAME] +redistribute connected [route-map MAP_NAME] +..... +@end example + +Cisco applies route-map _before_ routes will exported to rip route +table. In current Zebra's test implementation, @command{ripd} applies route-map +after routes are listed in the route table and before routes will be announced +to an interface (something like output filter). I think it is not so clear, +but it is draft and it may be changed at future. + +Route-map statement (@pxref{Route Map}) is needed to use route-map +functionality. + +@deffn {Route Map} {match interface @var{word}} {} +This command match to incoming interface. Notation of this match is +different from Cisco. Cisco uses a list of interfaces - NAME1 NAME2 +... NAMEN. Ripd allows only one name (maybe will change in the +future). Next - Cisco means interface which includes next-hop of +routes (it is somewhat similar to "ip next-hop" statement). Ripd +means interface where this route will be sent. This difference is +because "next-hop" of same routes which sends to different interfaces +must be different. Maybe it'd be better to made new matches - say +"match interface-out NAME" or something like that. +@end deffn + +@deffn {Route Map} {match ip address @var{word}} {} +@deffnx {Route Map} {match ip address prefix-list @var{word}} {} +Match if route destination is permitted by access-list. +@end deffn + +@deffn {Route Map} {match ip next-hop A.B.C.D} {} +Cisco uses here , @command{ripd} IPv4 address. Match if +route has this next-hop (meaning next-hop listed in the rip route +table - "show ip rip") +@end deffn + +@deffn {Route Map} {match metric <0-4294967295>} {} +This command match to the metric value of RIP updates. For other +protocol compatibility metric range is shown as <0-4294967295>. But +for RIP protocol only the value range <0-16> make sense. +@end deffn + +@deffn {Route Map} {set ip next-hop A.B.C.D} {} +This command set next hop value in RIPv2 protocol. This command does +not affect RIPv1 because there is no next hop field in the packet. +@end deffn + +@deffn {Route Map} {set metric <0-4294967295>} {} +Set a metric for matched route when sending announcement. The metric +value range is very large for compatibility with other protocols. For +RIP, valid metric values are from 1 to 16. +@end deffn + +@node RIP Authentication, RIP Timers, RIP route-map, RIP +@comment node-name, next, previous, up +@section RIP Authentication + +@deffn {Interface command} {ip rip authentication mode md5} {} +@deffnx {Interface command} {no ip rip authentication mode md5} {} +Set the interface with RIPv2 MD5 authentication. +@end deffn + +@deffn {Interface command} {ip rip authentication mode text} {} +@deffnx {Interface command} {no ip rip authentication mode text} {} +Set the interface with RIPv2 simple password authentication. +@end deffn + +@deffn {Interface command} {ip rip authentication string @var{string}} {} +@deffnx {Interface command} {no ip rip authentication string @var{string}} {} +RIP version 2 has simple text authentication. This command sets +authentication string. The string must be shorter than 16 characters. +@end deffn + +@deffn {Interface command} {ip rip authentication key-chain @var{key-chain}} {} +@deffnx {Interface command} {no ip rip authentication key-chain @var{key-chain}} {} +Specifiy Keyed MD5 chain. +@end deffn + +@example +! +key chain test + key 1 + key-string test +! +interface eth1 + ip rip authentication mode md5 + ip rip authentication key-chain test +! +@end example + +@node RIP Timers, Show RIP Information, RIP Authentication, RIP +@comment node-name, next, previous, up +@section RIP Timers + +@deffn {RIP command} {timers basic @var{update} @var{timeout} @var{garbage}} {} + +RIP protocol has several timers. User can configure those timers' values +by @code{timers basic} command. + +The default settings for the timers are as follows: + +@itemize @bullet +@item +The update timer is 30 seconds. Every update timer seconds, the RIP +process is awakened to send an unsolicited Response message containing +the complete routing table to all neighboring RIP routers. + +@item +The timeout timer is 180 seconds. Upon expiration of the timeout, the +route is no longer valid; however, it is retained in the routing table +for a short time so that neighbors can be notified that the route has +been dropped. + +@item +The garbage collect timer is 120 seconds. Upon expiration of the +garbage-collection timer, the route is finally removed from the routing +table. + +@end itemize + +The @code{timers basic} command allows the the default values of the timers +listed above to be changed. +@end deffn + +@deffn {RIP command} {no timers basic} {} +The @code{no timers basic} command will reset the timers to the default +settings listed above. +@end deffn + +@node Show RIP Information, RIP Debug Commands, RIP Timers, RIP +@comment node-name, next, previous, up +@section Show RIP Information + +To display RIP routes. + +@deffn Command {show ip rip} {} +Show RIP routes. +@end deffn + +The command displays all RIP routes. For routes that are received +through RIP, this command will display the time the packet was sent and +the tag information. This command will also display this information +for routes redistributed into RIP. + +@c Exmaple here. + +@deffn Command {show ip protocols} {} +The command displays current RIP status. It includes RIP timer, +filtering, version, RIP enabled interface and RIP peer inforation. +@end deffn + +@example +@group +ripd> @b{show ip protocols} +Routing Protocol is "rip" + Sending updates every 30 seconds with +/-50%, next due in 35 seconds + Timeout after 180 seconds, garbage collect after 120 seconds + Outgoing update filter list for all interface is not set + Incoming update filter list for all interface is not set + Default redistribution metric is 1 + Redistributing: kernel connected + Default version control: send version 2, receive version 2 + Interface Send Recv + Routing for Networks: + eth0 + eth1 + 1.1.1.1 + 203.181.89.241 + Routing Information Sources: + Gateway BadPackets BadRoutes Distance Last Update +@end group +@end example + +@node RIP Debug Commands, , Show RIP Information, RIP +@comment node-name, next, previous, up +@section RIP Debug Commands + +Debug for RIP protocol. + +@deffn Command {debug rip events} {} +Debug rip events. +@end deffn + +@code{debug rip} will show RIP events. Sending and receiving +packets, timers, and changes in interfaces are events shown with @command{ripd}. + +@deffn Command {debug rip packet} {} +Debug rip packet. +@end deffn + +@code{debug rip packet} will display detailed information about the RIP +packets. The origin and port number of the packet as well as a packet +dump is shown. + +@deffn Command {debug rip zebra} {} +Debug rip between zebra communication. +@end deffn + +This command will show the communication between @command{ripd} and @command{zebra}. The +main information will include addition and deletion of paths to the +kernel and the sending and receiving of interface information. + +@deffn Command {show debugging rip} {} +Display @command{ripd}'s debugging option. +@end deffn + +@code{show debugging rip} will show all information currently set for ripd +debug. diff --git a/doc/ripngd.8 b/doc/ripngd.8 new file mode 100644 index 0000000..cff8abe --- /dev/null +++ b/doc/ripngd.8 @@ -0,0 +1,143 @@ +.TH RIPNGD 8 "July 2000" "Zebra Beast - RIPNGD" "Version 0.88" + +.SH NAME +ripngd \- a RIP routing engine for use with Zebra and IPv6 + +.SH SYNOPSIS +.B ripngd +[ +.B \-dhlrv +] +[ +.B \-f config-file +] +[ +.B \-i pid-file +] +[ +.B \-P port-number +] + +.SH DESCRIPTION +.B ripngd +is a routing component that works with the +.B zebra +routing engine. + + + +.SH OPTIONS + +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. + +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this +option will likely default to \fB\fI/usr/local/etc/ripngd.conf\fR. + +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. + +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When ripngd starts its process idenifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart ripngd. The likely default is \fB\fI/var/run/ripngd.pid\fR. + +.TP +\fB\-l\fR, \fB\-\-log_mode\fR +Turn verbose logging on. + +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the ripngd VTY will listen on. This defaults to +2603, as specified in \fB\fI/etc/services\fR. + +.TP +\fB\-r\fR, \fB\-\-retain\fR +When the program terminates, retain routes added by \fBripd\fR. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. + + +.SH COMMANDS + +\fB router ripng \fR +\fB router zebra \fR -- (Move routes into kernel table) + +\fB network [NETWORK] \fR +\fB no network [NETWORK] \fR + +\fB network [IFNAME] \fR +\fB no network [IFNAME] \fR + +\fB route [NETWORK] \fR +\fB no route [NETWORK] \fR + +\fB flush_timer [FLUSH] \fR + +\fB distribute-list [ACCESS-LIST] [in|out] [IFNAME] \fR + +\fB show ip ripng \fR +\fB show debugging ripng \fR + +\fB debug ripng \fR +\fB debug ripng events \fR +\fB debug ripng packet \fR +\fB debug ripng zebra \fR + + + +.SH FILES + +.TP +.BI /usr/local/sbin/ripngd +The default location of the +.B ripngd +binary. + +.TP +.BI /usr/local/etc/ripngd.conf +The default location of the +.B ripngd +config file. + +.TP +.BI $(PWD)/ripngd.log +If the +.B ripngd +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBripngd\fR. + + +.SH WARNING +This man page is intended as a quick reference for command line +options, and for config file commands. The definitive document is the +Info file \fBzebra\fR. + + +.SH DIAGNOSTICS +The ripngd process may log to standard output, to a VTY, to a log +file, or through syslog to the system logs. \fBripngd\fR supports many +debugging options, see the Info file, or the source for details. + + +.SH "SEE ALSO" +References to other related man pages: + +ripd(8), ospfd(8), ospf6d(8), bgpd(8), zebra(8), vtysh(1) + +.SH BUGS +.B ripngd +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. + diff --git a/doc/ripngd.texi b/doc/ripngd.texi new file mode 100644 index 0000000..b49f0bf --- /dev/null +++ b/doc/ripngd.texi @@ -0,0 +1,85 @@ +@node RIPng, OSPFv2, RIP, Top +@comment node-name, next, previous, up +@chapter RIPng + +@command{ripngd} supports the RIPng protocol as described in RFC2080. It's an +IPv6 reincarnation of the RIP protocol. + +@menu +* Invoking ripngd:: +* ripngd Configuration:: +* ripngd Terminal Mode Commands:: +* ripngd Filtering Commands:: +@end menu + +@node Invoking ripngd, ripngd Configuration, RIPng, RIPng +@comment node-name, next, previous, up +@section Invoking ripngd + +There are no @code{ripngd} specific invocation options. Common options +can be specified (@pxref{Common Invocation Options}). + +@node ripngd Configuration, ripngd Terminal Mode Commands, Invoking ripngd, RIPng +@comment node-name, next, previous, up +@section ripngd Configuration + +Currently ripngd supports the following commands: + +@deffn Command {router ripng} {} +Enable RIPng. +@end deffn + +@deffn {RIPng Command} {flush_timer @var{time}} {} +Set flush timer. +@end deffn + +@deffn {RIPng Command} {network @var{network}} {} +Set RIPng enabled interface by @var{network} +@end deffn + +@deffn {RIPng Command} {network @var{ifname}} {} +Set RIPng enabled interface by @var{ifname} +@end deffn + +@deffn {RIPng Command} {route @var{network}} {} +Set RIPng static routing announcement of @var{network}. +@end deffn + +@deffn Command {router zebra} {} +This command is the default and does not appear in the configuration. +With this statement, RIPng routes go to the @command{zebra} daemon. +@end deffn + +@node ripngd Terminal Mode Commands, ripngd Filtering Commands, ripngd Configuration, RIPng +@comment node-name, next, previous, up +@section ripngd Terminal Mode Commands + +@deffn Command {show ip ripng} {} +@end deffn + +@deffn Command {show debugging ripng} {} +@end deffn + +@deffn Command {debug ripng events} {} +@end deffn + +@deffn Command {debug ripng packet} {} +@end deffn + +@deffn Command {debug ripng zebra} {} +@end deffn + +@node ripngd Filtering Commands, , ripngd Terminal Mode Commands, RIPng +@comment node-name, next, previous, up +@section ripngd Filtering Commands + +@deffn Command {distribute-list @var{access_list} (in|out) @var{ifname}} {} +You can apply an access-list to the interface using the +@code{distribute-list} command. @var{access_list} is an access-list +name. @var{direct} is @samp{in} or @samp{out}. If @var{direct} is +@samp{in}, the access-list is applied only to incoming packets. + +@example +distribute-list local-only out sit1 +@end example +@end deffn diff --git a/doc/routemap.texi b/doc/routemap.texi new file mode 100644 index 0000000..478f462 --- /dev/null +++ b/doc/routemap.texi @@ -0,0 +1,91 @@ +@node Route Map, IPv6 Support, Filtering, Top +@comment node-name, next, previous, up +@chapter Route Map + +Route map is a very useful function in zebra. There is a match and set +statement permitted in a route map. + +@example +@group +route-map test permit 10 + match ip address 10 + set local-preference 200 +@end group +@end example + +This means that if a route matches ip access-list number 10 it's +local-preference value is set to 200. + +@menu +* Route Map Command:: +* Route Map Match Command:: +* Route Map Set Command:: +@end menu + +@node Route Map Command, Route Map Match Command, Route Map, Route Map +@comment node-name, next, previous, up +@subsection Route Map Command + +@deffn {Command} {route-map @var{route-map-name} permit @var{priority}} {} +@end deffn + +@node Route Map Match Command, Route Map Set Command, Route Map Command, Route Map +@comment node-name, next, previous, up +@subsection Route Map Match Command + +@deffn {Route-map Command} {match ip address @var{access_list}} {} +Matches the specified @var{access_list} +@end deffn + +@deffn {Route-map Command} {match ip next-hop @var{ipv4_addr}} {} +Matches the specified @var{ipv4_addr}. +@end deffn + +@deffn {Route-map Command} {match aspath @var{as_path}} {} +Matches the specified @var{as_path}. +@end deffn + +@deffn {Route-map Command} {match metric @var{metric}} {} +Matches the specified @var{metric}. +@end deffn + +@deffn {Route-map Command} {match community @var{community_list}} {} +Matches the specified @var{community_list} +@end deffn + +@node Route Map Set Command, , Route Map Match Command, Route Map +@comment node-name, next, previous, up +@subsection Route Map Set Command + +@deffn {Route-map Command} {set ip next-hop @var{ipv4_address}} {} +Set the BGP nexthop address. +@end deffn + +@deffn {Route-map Command} {set local-preference @var{local_pref}} {} +Set the BGP local preference. +@end deffn + +@deffn {Route-map Command} {set weight @var{weight}} {} +Set the route's weight. +@end deffn + +@deffn {Route-map Command} {set metric @var{metric}} {} +Set the BGP attribute MED. +@end deffn + +@deffn {Route-map Command} {set as-path prepend @var{as_path}} {} +Set the BGP AS path to prepend. +@end deffn + +@deffn {Route-map Command} {set community @var{community}} {} +Set the BGP community attribute. +@end deffn + +@deffn {Route-map Command} {set ipv6 next-hop global @var{ipv6_address}} {} +Set the BGP-4+ global IPv6 nexthop address. +@end deffn + +@deffn {Route-map Command} {set ipv6 next-hop local @var{ipv6_address}} {} +Set the BGP-4+ link local IPv6 nexthop address. +@end deffn + diff --git a/doc/snmp.texi b/doc/snmp.texi new file mode 100644 index 0000000..b4b6bf2 --- /dev/null +++ b/doc/snmp.texi @@ -0,0 +1,67 @@ +@node SNMP Support, Zebra Protocol, Kernel Interface, Top +@comment node-name, next, previous, up +@chapter SNMP Support + +SNMP (Simple Network Managing Protocol) is widely implemented feature +for collecting network information from router and/or host. Zebra +itself does not support SNMP agent functionality. But conjuction with +SNMP agent, Zebra provides routing protocol MIBs. + +Zebra uses SMUX protocol (RFC1227) for making communication with SNMP +agent. There are several SNMP agent which support SMUX. We recommend +to use the latest @command{net-snmp} software. + +@menu +* How to get net-snmp:: +* SMUX configuration:: +@end menu + +@node How to get net-snmp, SMUX configuration, SNMP Support, SNMP Support +@comment node-name, next, previous, up +@section How to get net-snmp + +net-snmp is a free software which distributed so called "as is" software +license. Please check the license which comes with distribution of +@command{net-snmp}. The authors of net-snmp are the University of +California, the University of California at Davis, and the Electrical +Engineering department at the University of California at Davis. + +You can get net-snmp from @url{http://www.net-snmp.org/}. + +To enable SMUX protocol support, please configure @command{net-snmp} +like below. + +@example +% configure --with-mib-modules=smux +@end example + +After compile and install @command{net-snmp}, you will need to configure +smuxpeer. I'm now using configuration shown below. This means SMUX client +connects to MIB 1.3.6.1.6.3.1 with password test. + +@example +/usr/local/share/snmp/snmpd.conf +================================ +smuxpeer 1.3.6.1.6.3.1 test +@end example + +@node SMUX configuration, , How to get net-snmp, SNMP Support +@comment node-name, next, previous, up +@section SMUX configuration + +To enable SNMP support of Zebra, you have to configure Zebra with +@command{--enable-snmp} (@pxref{Configure the Software}). + +@deffn {Command} {smux peer @var{oid}} {} +@deffnx {Command} {no smux peer @var{oid}} {} +@end deffn + +@deffn {Command} {smux peer @var{oid} @var{password}} {} +@deffnx {Command} {no smux peer @var{oid} @var{password}} {} +@end deffn + +@example +! +smux peer .1.3.6.1.6.3.1 test +! +@end example diff --git a/doc/texinfo.tex b/doc/texinfo.tex new file mode 100644 index 0000000..332e392 --- /dev/null +++ b/doc/texinfo.tex @@ -0,0 +1,5625 @@ +% texinfo.tex -- TeX macros to handle Texinfo files. +% +% Load plain if necessary, i.e., if running under initex. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi +% +\def\texinfoversion{1999-02-14.16}% +% +% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 +% Free Software Foundation, Inc. +% +% This texinfo.tex file 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, or (at +% your option) any later version. +% +% This texinfo.tex file 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 texinfo.tex file; see the file COPYING. If not, write +% to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +% Boston, MA 02111-1307, USA. +% +% In other words, you are welcome to use, share and improve this program. +% You are forbidden to forbid anyone else to use, share and improve +% what you give them. Help stamp out software-hoarding! +% +% Please try the latest version of texinfo.tex before submitting bug +% reports; you can get the latest version from: +% ftp://ftp.gnu.org/pub/gnu/texinfo.tex +% (and all GNU mirrors, see http://www.gnu.org/order/ftp.html) +% ftp://tug.org/tex/texinfo.tex +% ftp://ctan.org/macros/texinfo/texinfo.tex +% (and all CTAN mirrors, finger ctan@ctan.org for a list). +% /home/gd/gnu/doc/texinfo.tex on the GNU machines. +% The texinfo.tex in any given Texinfo distribution could well be out +% of date, so if that's what you're using, please check. +% There is a small home page for Texinfo at http://texinfo.org/. +% +% Send bug reports to bug-texinfo@gnu.org. Please include including a +% complete document in each bug report with which we can reproduce the +% problem. Patches are, of course, greatly appreciated. +% +% To process a Texinfo manual with TeX, it's most reliable to use the +% texi2dvi shell script that comes with the distribution. For a simple +% manual foo.texi, however, you can get away with this: +% tex foo.texi +% texindex foo.?? +% tex foo.texi +% tex foo.texi +% dvips foo.dvi -o # or whatever, to process the dvi file; this makes foo.ps. +% The extra runs of TeX get the cross-reference information correct. +% Sometimes one run after texindex suffices, and sometimes you need more +% than two; texi2dvi does it as many times as necessary. +% +% It is possible to adapt texinfo.tex for other languages. You can get +% the existing language-specific files from ftp://ftp.gnu.org/gnu/texinfo/. + +\message{Loading texinfo [version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}% + \catcode`+=\active \catcode`\_=\active} + +% Save some parts of plain tex whose names we will redefine. + +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv=\equiv +\let\ptexexclam=\! +\let\ptexi=\i +\let\ptexlbrace=\{ +\let\ptexrbrace=\} +\let\ptexstar=\* +\let\ptext=\t + +% We never want plain's outer \+ definition in Texinfo. +% For @tex, we can use \tabalign. +\let\+ = \relax + + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Set up fixed words for English if not already set. +\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi +\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi +\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi +\ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi +\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi +\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi +\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi +\ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi +\ifx\putwordof\undefined \gdef\putwordof{of}\fi +\ifx\putwordon\undefined \gdef\putwordon{on}\fi +\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi +\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi +\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi +\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi +\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi +\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi +\ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi +% +\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi +\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi +\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi +\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi +\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi +\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi +\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi +\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi +\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi +\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi +\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi +\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi +% +\ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi +\ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi +\ifx\putwordDefivar\undefined \gdef\putwordDefivar{Instance Variable}\fi +\ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi +\ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi +\ifx\putwordDeftypevar\undefined\gdef\putwordDeftypevar{Variable}\fi +\ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi +\ifx\putwordDeftypefun\undefined\gdef\putwordDeftypefun{Function}\fi + +% Ignore a token. +% +\def\gobble#1{} + +\hyphenation{ap-pen-dix} +\hyphenation{mini-buf-fer mini-buf-fers} +\hyphenation{eshell} +\hyphenation{white-space} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen \bindingoffset +\newdimen \normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\ifx\eTeXversion\undefined +\def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% +\else +\def\loggingall{\tracingcommands3 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \tracingscantokens1 \tracingassigns1 \tracingifs1 + \tracinggroups1 \tracingnesting2 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% +\fi + +% For @cropmarks command. +% Do @cropmarks to get crop marks. +% +\newif\ifcropmarks +\let\cropmarks = \cropmarkstrue +% +% Dimensions to add cropmarks at corners. +% Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines +\newdimen\cornerlong \cornerlong=1pc +\newdimen\cornerthick \cornerthick=.3pt +\newdimen\topandbottommargin \topandbottommargin=.75in + +% Main output routine. +\chardef\PAGE = 255 +\output = {\onepageout{\pagecontents\PAGE}} + +\newbox\headlinebox +\newbox\footlinebox + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions, but you have to call it yourself. +\def\onepageout#1{% + \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi + % + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + % + % Do this outside of the \shipout so @code etc. will be expanded in + % the headline as they should be, not taken literally (outputting ''code). + \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% + \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% + % + {% + % Have to do this stuff outside the \shipout because we want it to + % take effect in \write's, yet the group defined by the \vbox ends + % before the \shipout runs. + % + \escapechar = `\\ % use backslash in output files. + \indexdummies % don't expand commands in the output. + \normalturnoffactive % \ in index entries must not stay \, e.g., if + % the page break happens to be in the middle of an example. + \shipout\vbox{% + \ifcropmarks \vbox to \outervsize\bgroup + \hsize = \outerhsize + \vskip-\topandbottommargin + \vtop to0pt{% + \line{\ewtop\hfil\ewtop}% + \nointerlineskip + \line{% + \vbox{\moveleft\cornerthick\nstop}% + \hfill + \vbox{\moveright\cornerthick\nstop}% + }% + \vss}% + \vskip\topandbottommargin + \line\bgroup + \hfil % center the page within the outer (page) hsize. + \ifodd\pageno\hskip\bindingoffset\fi + \vbox\bgroup + \fi + % + \unvbox\headlinebox + \pagebody{#1}% + \ifdim\ht\footlinebox > 0pt + % Only leave this space if the footline is nonempty. + % (We lessened \vsize for it in \oddfootingxxx.) + % The \baselineskip=24pt in plain's \makefootline has no effect. + \vskip 2\baselineskip + \unvbox\footlinebox + \fi + % + \ifcropmarks + \egroup % end of \vbox\bgroup + \hfil\egroup % end of (centering) \line\bgroup + \vskip\topandbottommargin plus1fill minus1fill + \boxmaxdepth = \cornerthick + \vbox to0pt{\vss + \line{% + \vbox{\moveleft\cornerthick\nsbot}% + \hfill + \vbox{\moveright\cornerthick\nsbot}% + }% + \nointerlineskip + \line{\ewbot\hfil\ewbot}% + }% + \egroup % \vbox from first cropmarks clause + \fi + }% end of \shipout\vbox + }% end of group with \turnoffactive + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% here.) But this means we cannot call \removeactivespaces as part of +% \argremovec{,omment}, since @c uses \parsearg, and thus the argument +% that \parsearg gets might well have any character at all in it. +% +\def\removeactivespaces#1{% + \begingroup + \ignoreactivespaces + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +%% These are used to keep @begin/@end levels from running away +%% Call \inENV within environments (after a \begingroup) +\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} +\def\ENVcheck{% +\ifENV\errmessage{Still within an environment; press RETURN to continue} +\endgroup\fi} % This is not perfect, but it should reduce lossage + +% @begin foo is the same as @foo, for now. +\newhelp\EMsimple{Press RETURN to continue.} + +\outer\def\begin{\parsearg\beginxxx} + +\def\beginxxx #1{% +\expandafter\ifx\csname #1\endcsname\relax +{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else +\csname #1\endcsname\fi} + +% @end foo executes the definition of \Efoo. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% There is an environment #1, but it hasn't been started. Give an error. +% +\def\unmatchedenderror#1{% + \errhelp = \EMsimple + \errmessage{This `@end #1' doesn't have a matching `@#1'}% +} + +% Define the control sequence \E#1 to give an unmatched @end error. +% +\def\defineunmatchedend#1{% + \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% +} + + +% Single-spacing is done by various environments (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = 12.5pt +\def\singlespace{% + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt\char64}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. +\def\mylbrace {{\tt\char123}} +\def\myrbrace {{\tt\char125}} +\let\{=\mylbrace +\let\}=\myrbrace +\begingroup + % Definitions to produce actual \{ & \} command in an index. + \catcode`\{ = 12 \catcode`\} = 12 + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\@ = 0 \catcode`\\ = 12 + @gdef@lbracecmd[\{]% + @gdef@rbracecmd[\}]% +@endgroup + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @v @H. +\let\, = \c +\let\dotaccent = \. +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \t +\let\ubaraccent = \b +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown +% Plain TeX defines: @AA @AE @O @OE @L (and lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ptexi + \else\ifx\temp\jmacro \j + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=3000 } + +% @! is an end-of-sentence bang. +\def\!{!\spacefactor=3000 } + +% @? is an end-of-sentence query. +\def\?{?\spacefactor=3000 } + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +\def\group{\begingroup + \ifnum\catcode13=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % The \vtop we start below produces a box with normal height and large + % depth; thus, TeX puts \baselineskip glue before it, and (when the + % next line of text is done) \lineskip glue after it. (See p.82 of + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\def\need{\parsearg\needx} + +% Old definition--didn't work. +%\def\needx #1{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak +%\prevdepth=-1000pt +%}} + +\def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \allowbreak + \nointerlineskip + \vtop to #1\mil{\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak +} + +% @br forces paragraph break + +\let\br = \par + +% @dots{} output an ellipsis using the current font. +% We do .5em per period so that it has the same spacing in a typewriter +% font as three actual period characters. +% +\def\dots{% + \leavevmode + \hbox to 1.5em{% + \hskip 0pt plus 0.25fil minus 0.25fil + .\hss.\hss.% + \hskip 0pt plus 0.5fil minus 0.5fil + }% +} + +% @enddots{} is an end-of-sentence ellipsis. +% +\def\enddots{% + \leavevmode + \hbox to 2em{% + \hskip 0pt plus 0.25fil minus 0.25fil + .\hss.\hss.\hss.% + \hskip 0pt plus 0.5fil minus 0.5fil + }% + \spacefactor=3000 +} + + +% @page forces the start of a new page +% +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{TEXT} puts TEXT in the margin next to the current paragraph. + +\def\inmargin#1{% +\strut\vadjust{\nobreak\kern-\strutdepth + \vtop to \strutdepth{\baselineskip\strutdepth\vss + \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}} +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. +% Allow normal characters that we make active in the argument (a file name). +\def\include{\begingroup + \catcode`\\=12 + \catcode`~=12 + \catcode`^=12 + \catcode`_=12 + \catcode`|=12 + \catcode`<=12 + \catcode`>=12 + \catcode`+=12 + \parsearg\includezzz} +% Restore active chars for included file. +\def\includezzz#1{\endgroup\begingroup + % Read the included file in a group so nested @include's work. + \def\thisfile{#1}% + \input\thisfile +\endgroup} + +\def\thisfile{} + +% @center line outputs that line, centered + +\def\center{\parsearg\centerzzz} +\def\centerzzz #1{{\advance\hsize by -\leftskip +\advance\hsize by -\rightskip +\centerline{#1}}} + +% @sp n outputs n lines of vertical space + +\def\sp{\parsearg\spxxx} +\def\spxxx #1{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\begingroup \catcode`\^^M=\other% +\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% +\commentxxx} +{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} + +\let\c=\comment + +% @paragraphindent NCHARS +% We'll use ems for NCHARS, close enough. +% We cannot implement @paragraphindent asis, though. +% +\def\asisword{asis} % no translation, these are keywords +\def\noneword{none} +% +\def\paragraphindent{\parsearg\doparagraphindent} +\def\doparagraphindent#1{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \defaultparindent = 0pt + \else + \defaultparindent = #1em + \fi + \fi + \parindent = \defaultparindent +} + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math means output in math mode. +% We don't use $'s directly in the definition of \math because control +% sequences like \math are expanded when the toc file is written. Then, +% we read the toc file back, the $'s will be normal characters (as they +% should be, according to the definition of Texinfo). So we must use a +% control sequence to switch into and out of math mode. +% +% This isn't quite enough for @math to work properly in indices, but it +% seems unlikely it will ever be needed there. +% +\let\implicitmath = $ +\def\math#1{\implicitmath #1\implicitmath} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +% @refill is a no-op. +\let\refill=\relax + +% If working on a large document in chapters, it is convenient to +% be able to disable indexing, cross-referencing, and contents, for test runs. +% This is done with @novalidate (before @setfilename). +% +\newif\iflinks \linkstrue % by default we want the aux files. +\let\novalidate = \linksfalse + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \iflinks + \readauxfile + \fi % \openindices needs to do some work in any case. + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + % + % If texinfo.cnf is present on the system, read it. + % Useful for site-wide @afourpaper, etc. + % Just to be on the safe side, close the input stream before the \input. + \openin 1 texinfo.cnf + \ifeof1 \let\temp=\relax \else \def\temp{\input texinfo.cnf }\fi + \closein1 + \temp + % + \comment % Ignore the actual filename. +} + +% Called from \setfilename. +% +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + + +\message{fonts,} +% Font-change commands. + +% Texinfo sort of supports the sans serif font style, which plain TeX does not. +% So we set up a \sf analogous to plain's \rm, etc. +\newfam\sffam +\def\sf{\fam=\sffam \tensf} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this one. +\def\ttsl{\tenttsl} + +% Use Computer Modern fonts at \magstephalf (11pt). +\newcount\mainmagstep +\mainmagstep=\magstephalf + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor +\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\setfont\textrm\rmshape{12}{1000} +\setfont\texttt\ttshape{12}{1000} +\else +\setfont\textrm\rmshape{10}{\mainmagstep} +\setfont\texttt\ttshape{10}{\mainmagstep} +\fi +% Instead of cmb10, you many want to use cmbx10. +% cmbx10 is a prettier font on its own, but cmb10 +% looks better when embedded in a line with cmr10. +\setfont\textbf\bfshape{10}{\mainmagstep} +\setfont\textit\itshape{10}{\mainmagstep} +\setfont\textsl\slshape{10}{\mainmagstep} +\setfont\textsf\sfshape{10}{\mainmagstep} +\setfont\textsc\scshape{10}{\mainmagstep} +\setfont\textttsl\ttslshape{10}{\mainmagstep} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun, etc. +\setfont\defbf\bxshape{10}{\magstep1} %was 1314 +\setfont\deftt\ttshape{10}{\magstep1} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} + +% Fonts for indices and small examples (9pt). +% We actually use the slanted font rather than the italic, +% because texinfo normally uses the slanted fonts for that. +% Do not make many font distinctions in general in the index, since they +% aren't very useful. +\setfont\ninett\ttshape{9}{1000} +\setfont\ninettsl\ttslshape{10}{900} +\setfont\indrm\rmshape{9}{1000} +\setfont\indit\itshape{9}{1000} +\setfont\indsl\slshape{9}{1000} +\let\indtt=\ninett +\let\indttsl=\ninettsl +\let\indsf=\indrm +\let\indbf=\indrm +\setfont\indsc\scshape{10}{900} +\font\indi=cmmi9 +\font\indsy=cmsy9 + +% Fonts for title page: +\setfont\titlerm\rmbshape{12}{\magstep3} +\setfont\titleit\itbshape{10}{\magstep4} +\setfont\titlesl\slbshape{10}{\magstep4} +\setfont\titlett\ttbshape{12}{\magstep3} +\setfont\titlettsl\ttslshape{10}{\magstep4} +\setfont\titlesf\sfbshape{17}{\magstep1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\authorrm{\secrm} + +% Chapter (and unnumbered) fonts (17.28pt). +\setfont\chaprm\rmbshape{12}{\magstep2} +\setfont\chapit\itbshape{10}{\magstep3} +\setfont\chapsl\slbshape{10}{\magstep3} +\setfont\chaptt\ttbshape{12}{\magstep2} +\setfont\chapttsl\ttslshape{10}{\magstep3} +\setfont\chapsf\sfbshape{17}{1000} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +% Section fonts (14.4pt). +\setfont\secrm\rmbshape{12}{\magstep1} +\setfont\secit\itbshape{10}{\magstep2} +\setfont\secsl\slbshape{10}{\magstep2} +\setfont\sectt\ttbshape{12}{\magstep1} +\setfont\secttsl\ttslshape{10}{\magstep2} +\setfont\secsf\sfbshape{12}{\magstep1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% \setfont\ssecrm\bxshape{10}{\magstep1} % This size an font looked bad. +% \setfont\ssecit\itshape{10}{\magstep1} % The letters were too crowded. +% \setfont\ssecsl\slshape{10}{\magstep1} +% \setfont\ssectt\ttshape{10}{\magstep1} +% \setfont\ssecsf\sfshape{10}{\magstep1} + +%\setfont\ssecrm\bfshape{10}{1315} % Note the use of cmb rather than cmbx. +%\setfont\ssecit\itshape{10}{1315} % Also, the size is a little larger than +%\setfont\ssecsl\slshape{10}{1315} % being scaled magstep1. +%\setfont\ssectt\ttshape{10}{1315} +%\setfont\ssecsf\sfshape{10}{1315} + +%\let\ssecbf=\ssecrm + +% Subsection fonts (13.15pt). +\setfont\ssecrm\rmbshape{12}{\magstephalf} +\setfont\ssecit\itbshape{10}{1315} +\setfont\ssecsl\slbshape{10}{1315} +\setfont\ssectt\ttbshape{12}{\magstephalf} +\setfont\ssecttsl\ttslshape{10}{1315} +\setfont\ssecsf\sfbshape{12}{\magstephalf} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{\magstep1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled 1315 +% The smallcaps and symbol fonts should actually be scaled \magstep1.5, +% but that is not a standard magnification. + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts, we +% don't bother to reset \scriptfont and \scriptscriptfont (which would +% also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy + \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf + \textfont\ttfam = \tentt \textfont\sffam = \tensf +} + + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this so that font changes will continue to work +% in math mode, where it is the current \fam that is relevant in most +% cases, not the current font. Plain TeX does \def\bf{\fam=\bffam +% \tenbf}, for example. By redefining \tenbf, we obviate the need to +% redefine \bf itself. +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl + \resetmathfonts} +\def\titlefonts{% + \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl + \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc + \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy + \let\tenttsl=\titlettsl + \resetmathfonts \setleading{25pt}} +\def\titlefont#1{{\titlefonts\rm #1}} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl + \resetmathfonts \setleading{16pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts % Maybe make sssec fonts scaled magstephalf? +\def\indexfonts{% + \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl + \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc + \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy \let\tenttsl=\indttsl + \resetmathfonts \setleading{12pt}} + +% Set up the default fonts, so we can use them for creating boxes. +% +\textfonts + +% Define these so they can be easily changed for other fonts. +\def\angleleft{$\langle$} +\def\angleright{$\rangle$} + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000} +\setfont\shortcontbf\bxshape{12}{1000} +\setfont\shortcontsl\slshape{12}{1000} + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} +\def\smartslanted#1{{\sl #1}\futurelet\next\smartitalicx} +\def\smartitalic#1{{\it #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\var=\smartslanted +\let\dfn=\smartslanted +\let\emph=\smartitalic +\let\cite=\smartslanted + +\def\b#1{{\bf #1}} +\let\strong=\b + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +\def\t#1{% + {\tt \rawbackslash \frenchspacing #1}% + \null +} +\let\ttfont=\t +\def\samp#1{`\tclose{#1}'\null} +\setfont\smallrm\rmshape{8}{1000} +\font\smallsy=cmsy9 +\def\key#1{{\smallrm\textfont2=\smallsy \leavevmode\hbox{% + \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% + \vbox{\hrule\kern-0.4pt + \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% + \kern-0.4pt\hrule}% + \kern-.06em\raise0.4pt\hbox{\angleright}}}} +% The old definition, with no lozenge: +%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +% @file, @option are the same as @samp. +\let\file=\samp +\let\option=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in \code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. +% -- rms. +{ + \catcode`\-=\active + \catcode`\_=\active + % + \global\def\code{\begingroup + \catcode`\-=\active \let-\codedash + \catcode`\_=\active \let_\codeunder + \codex + } + % + % If we end up with any active - characters when handling the index, + % just treat them as a normal -. + \global\def\indexbreaks{\catcode`\-=\active \let-\realdash} +} + +\def\realdash{-} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{\ifusingtt{\normalunderscore\discretionary{}{}{}}{\_}} +\def\codex #1{\tclose{#1}\endgroup} + +%\let\exp=\tclose %Was temporary + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. + +% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), +% `example' (@kbd uses ttsl only inside of @example and friends), +% or `code' (@kbd uses normal tty font always). +\def\kbdinputstyle{\parsearg\kbdinputstylexxx} +\def\kbdinputstylexxx#1{% + \def\arg{#1}% + \ifx\arg\worddistinct + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% + \else\ifx\arg\wordexample + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% + \else\ifx\arg\wordcode + \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% + \fi\fi\fi +} +\def\worddistinct{distinct} +\def\wordexample{example} +\def\wordcode{code} + +% Default is kbdinputdistinct. (Too much of a hassle to call the macro, +% the catcodes are wrong for parsearg to work.) +\gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl} + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\kbdfont\look}}\fi +\else{\tclose{\kbdfont\look}}\fi} + +% For @url, @env, @command quotes seem unnecessary, so use \code. +\let\url=\code +\let\env=\code +\let\command=\code + +% @uref (abbreviation for `urlref') takes an optional (comma-separated) +% second argument specifying the text to display and an optional third +% arg as text to display instead of (rather than in addition to) the url +% itself. First (mandatory) arg is the url. Perhaps eventually put in +% a hypertex \special here. +% +\def\uref#1{\douref #1,,,\finish} +\def\douref#1,#2,#3,#4\finish{% + \setbox0 = \hbox{\ignorespaces #3}% + \ifdim\wd0 > 0pt + \unhbox0 % third arg given, show only that + \else + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \unhbox0\ (\code{#1})% second arg given, show both it and url + \else + \code{#1}% only url given, so show it + \fi + \fi +} + +% rms does not like the angle brackets --karl, 17may97. +% So now @email is just like @uref. +%\def\email#1{\angleleft{\tt #1}\angleright} +\let\email=\uref + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +% @l was never documented to mean ``switch to the Lisp font'', +% and it is not used as such in any manual I can find. We need it for +% Polish suppressed-l. --karl, 22sep96. +%\def\l#1{{\li #1}\null} + +% Explicit font changes: @r, @sc, undocumented @ii. +\def\r#1{{\rm #1}} % roman font +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @acronym downcases the argument and prints in smallcaps. +\def\acronym#1{{\smallcaps \lowercase{#1}}} + +% @pounds{} is a sterling sign. +\def\pounds{{\it\$}} + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\newif\ifseenauthor +\newif\iffinishedtitlepage + +% Do an implicit @contents or @shortcontents after @end titlepage if the +% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. +% +\newif\ifsetcontentsaftertitlepage + \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue +\newif\ifsetshortcontentsaftertitlepage + \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefonts\rm ##1} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \def\author{\parsearg\authorzzz}% + \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi + {\authorfont \leftline{##1}}}% + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% +% \def\page{\oldpage \hbox{}} +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + % + % If they want short, they certainly want long too. + \ifsetshortcontentsaftertitlepage + \shortcontents + \contents + \global\let\shortcontents = \relax + \global\let\contents = \relax + \fi + % + \ifsetcontentsaftertitlepage + \contents + \global\let\contents = \relax + \global\let\shortcontents = \relax + \fi + % + \HEADINGSon +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks\evenheadline % headline on even pages +\newtoks\oddheadline % headline on odd pages +\newtoks\evenfootline % footline on even pages +\newtoks\oddfootline % footline on odd pages + +% Now make Tex use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + +\def\evenheading{\parsearg\evenheadingxxx} +\def\oddheading{\parsearg\oddheadingxxx} +\def\everyheading{\parsearg\everyheadingxxx} + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\oddfooting{\parsearg\oddfootingxxx} +\def\everyfooting{\parsearg\everyfootingxxx} + +{\catcode`\@=0 % + +\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} +\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} +\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyheadingxxx#1{\oddheadingxxx{#1}\evenheadingxxx{#1}}% + +\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} +\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} +\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% + \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% + % + % Leave some space for the footline. Hopefully ok to assume + % @evenfooting will not be used by itself. + \global\advance\pageheight by -\baselineskip + \global\advance\vsize by -\baselineskip +} + +\gdef\everyfootingxxx#1{\oddfootingxxx{#1}\evenfootingxxx{#1}} +% +}% unbind the catcode of @. + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{ +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% Produces Day Month Year style of output. +\def\today{% + \number\day\space + \ifcase\month + \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr + \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug + \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec + \fi + \space\number\year} + +% @settitle line... specifies the title of the document, for headings. +% It generates no output of its own. +\def\thistitle{\putwordNoTitle} +\def\settitle{\parsearg\settitlezzz} +\def\settitlezzz #1{\gdef\thistitle{#1}} + + +\message{tables,} +% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\itemxpar \parsearg\kitemzzz} + +\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + +\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. + \nobreak + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. + \noindent + % Do this with kerns and \unhbox so that if there is a footnote in + % the item text, it can migrate to the main vertical list and + % eventually be printed. + \nobreak\kern-\tableindent + \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 + \unhbox0 + \nobreak\kern\dimen0 + \endgroup + \itemxneedsnegativevskiptrue + \fi +} + +\def\item{\errmessage{@item while not in a table}} +\def\itemx{\errmessage{@itemx while not in a table}} +\def\kitem{\errmessage{@kitem while not in a table}} +\def\kitemx{\errmessage{@kitemx while not in a table}} +\def\xitem{\errmessage{@xitem while not in a table}} +\def\xitemx{\errmessage{@xitemx while not in a table}} + +% Contains a kludge to get @end[description] to work. +\def\description{\tablez{\dontindex}{1}{}{}{}{}} + +% @table, @ftable, @vtable. +\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} +{\obeylines\obeyspaces% +\gdef\tablex #1^^M{% +\tabley\dontindex#1 \endtabley}} + +\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} +{\obeylines\obeyspaces% +\gdef\ftablex #1^^M{% +\tabley\fnitemindex#1 \endtabley +\def\Eftable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} +{\obeylines\obeyspaces% +\gdef\vtablex #1^^M{% +\tabley\vritemindex#1 \endtabley +\def\Evtable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\code{#1}}}% + +{\obeyspaces % +\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% +\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\tablez #1#2#3#4#5#6{% +\aboveenvbreak % +\begingroup % +\def\Edescription{\Etable}% Necessary kludge. +\let\itemindex=#1% +\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % +\ifnum 0#4>0 \tableindent=#4\mil \fi % +\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % +\def\itemfont{#2}% +\itemmax=\tableindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \tableindent % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\afterenvbreak\endgroup}% +\let\item = \internalBitem % +\let\itemx = \internalBitemx % +\let\kitem = \internalBkitem % +\let\kitemx = \internalBkitemx % +\let\xitem = \internalBxitem % +\let\xitemx = \internalBxitemx % +} + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\def\itemize{\parsearg\itemizezzz} + +\def\itemizezzz #1{% + \begingroup % ended by the @end itemize + \itemizey {#1}{\Eitemize} +} + +\def\itemizey #1#2{% +\aboveenvbreak % +\itemmax=\itemindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \itemindent % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\afterenvbreak\endgroup}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% Set sfcode to normal for the chars that usually have another value. +% These are `.?!:;,' +\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\def\enumerate{\parsearg\enumeratezzz} +\def\enumeratezzz #1{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a . + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call itemizey, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \itemizey{#1.}\Eenumerate\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + +% Definition of @item while inside @itemize. + +\def\itemizeitem{% +\advance\itemno by 1 +{\let\par=\endgraf \smallbreak}% +\ifhmode \errmessage{In hmode at itemizeitem}\fi +{\parskip=0in \hskip 0pt +\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% +\vadjust{\penalty 1200}}% +\flushcr} + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. +% +% For those who want to use more than one line's worth of words in +% the preamble, break the line within one argument and it +% will parse correctly, i.e., +% +% @multitable {Column 1 template} {Column 2 template} {Column 3 +% template} +% Not: +% @multitable {Column 1 template} {Column 2 template} +% {Column 3 template} + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab, @multitable or @end multitable do not need to be on their +% own lines, but it will not hurt if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. +% +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +% Macros used to set up halign preamble: +% +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +% #1 is the part of the @columnfraction before the decimal point, which +% is presumably either 0 or the empty string (but we don't check, we +% just throw it away). #2 is the decimal part, which we use as the +% percent of \hsize for this column. +\def\pickupwholefraction#1.#2 {% + \global\advance\colcount by 1 + \expandafter\xdef\csname col\the\colcount\endcsname{.#2\hsize}% + \setuptable +} + +\newcount\colcount +\def\setuptable#1{% + \def\firstarg{#1}% + \ifx\firstarg\xendsetuptable + \let\go = \relax + \else + \ifx\firstarg\xcolumnfractions + \global\setpercenttrue + \else + \ifsetpercent + \let\go\pickupwholefraction + \else + \global\advance\colcount by 1 + \setbox0=\hbox{#1\unskip }% Add a normal word space as a separator; + % typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi + \fi + \ifx\go\pickupwholefraction + % Put the argument back for the \pickupwholefraction call, so + % we'll always have a period there to be parsed. + \def\go{\pickupwholefraction#1}% + \else + \let\go = \setuptable + \fi% + \fi + \go +} + +% multitable syntax +\def\tab{&\hskip1sp\relax} % 2/2/96 + % tiny skip here makes sure this column space is + % maintained, even if it is never used. + +% @multitable ... @end multitable definitions: +% +\def\multitable{\parsearg\dotable} +\def\dotable#1{\bgroup + \vskip\parskip + \let\item\crcr + \tolerance=9500 + \hbadness=9500 + \setmultitablespacing + \parskip=\multitableparskip + \parindent=\multitableparindent + \overfullrule=0pt + \global\colcount=0 + \def\Emultitable{\global\setpercentfalse\cr\egroup\egroup}% + % + % To parse everything between @multitable and @item: + \setuptable#1 \endsetuptable + % + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. + \everycr{\noalign{% + % + % \filbreak%% keeps underfull box messages off when table breaks over pages. + % Maybe so, but it also creates really weird page breaks when the table + % breaks over pages. Wouldn't \vfil be better? Wait until the problem + % manifests itself, so it can be fixed for real --karl. + \global\colcount=0\relax}}% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. + \halign\bgroup&\global\advance\colcount by 1\relax + \multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % + % If the user has set preamble in terms of percent of \hsize we will + % use that dimension as the width of the column, and the \leftskip + % will keep entries from bumping into each other. Table will start at + % left margin and final column will justify at right margin. + % + % Make sure we don't inherit \rightskip from the outer environment. + \rightskip=0pt + \ifnum\colcount=1 + % The first column will be indented with the surrounding text. + \advance\hsize by\leftskip + \else + \ifsetpercent \else + % If user has not set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace. + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: + \leftskip=\multitablecolspace + \fi + % Ignoring space at the beginning and end avoids an occasional spurious + % blank line, when TeX decides to break the line at the space before the + % box from the multistrut, so the strut ends up on a line by itself. + % For example: + % @multitable @columnfractions .11 .89 + % @item @code{#} + % @tab Legal holiday which is valid in major parts of the whole country. + % Is automatically provided with highlighting sequences respectively marking + % characters. + \noindent\ignorespaces##\unskip\multistrut}\cr +} + +\def\setmultitablespacing{% test to see if user has set \multitablelinespace. +% If so, do nothing. If not, give it an appropriate dimension based on +% current baselineskip. +\ifdim\multitablelinespace=0pt +%% strut to put in table in case some entry doesn't have descenders, +%% to keep lines equally spaced +\let\multistrut = \strut +%% Test to see if parskip is larger than space between lines of +%% table. If not, do nothing. +%% If so, set to same dimension as multitablelinespace. +\else +\gdef\multistrut{\vrule height\multitablelinespace depth\dp0 +width0pt\relax} \fi +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi} + + +\message{conditionals,} +% Prevent errors for section commands. +% Used in @ignore and in failing conditionals. +\def\ignoresections{% + \let\chapter=\relax + \let\unnumbered=\relax + \let\top=\relax + \let\unnumberedsec=\relax + \let\unnumberedsection=\relax + \let\unnumberedsubsec=\relax + \let\unnumberedsubsection=\relax + \let\unnumberedsubsubsec=\relax + \let\unnumberedsubsubsection=\relax + \let\section=\relax + \let\subsec=\relax + \let\subsubsec=\relax + \let\subsection=\relax + \let\subsubsection=\relax + \let\appendix=\relax + \let\appendixsec=\relax + \let\appendixsection=\relax + \let\appendixsubsec=\relax + \let\appendixsubsection=\relax + \let\appendixsubsubsec=\relax + \let\appendixsubsubsection=\relax + \let\contents=\relax + \let\smallbook=\relax + \let\titlepage=\relax +} + +% Used in nested conditionals, where we have to parse the Texinfo source +% and so want to turn off most commands, in case they are used +% incorrectly. +% +\def\ignoremorecommands{% + \let\defcodeindex = \relax + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\setchapternewpage = \relax + \let\setchapterstyle = \relax + \let\everyheading = \relax + \let\evenheading = \relax + \let\oddheading = \relax + \let\everyfooting = \relax + \let\evenfooting = \relax + \let\oddfooting = \relax + \let\headings = \relax + \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax + \let\item = \relax +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Ignore @ifinfo, @ifhtml, @ifnottex, @html, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\def\ifhtml{\doignore{ifhtml}} +\def\ifnottex{\doignore{ifnottex}} +\def\html{\doignore{html}} +\def\menu{\doignore{menu}} +\def\direntry{\doignore{direntry}} + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory = \comment + +% Ignore text until a line `@end #1'. +% +\def\doignore#1{\begingroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define a command to swallow text until we reach `@end #1'. + % This @ is a catcode 12 token (that is the normal catcode of @ in + % this texinfo.tex file). We change the catcode of @ below to match. + \long\def\doignoretext##1@end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % Ignore braces, too, so mismatched braces don't cause trouble. + \catcode`\{ = 9 + \catcode`\} = 9 + % + % We must not have @c interpreted as a control sequence. + \catcode`\@ = 12 + % + % Make the letter c a comment character so that the rest of the line + % will be ignored. This way, the document can have (for example) + % @c @end ifinfo + % and the @end ifinfo will be properly ignored. + % (We've just changed @ to catcode 12.) + \catcode`\c = 14 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{WARNING: for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{ (See ftp://ftp.gnu.org/pub/gnu/TeX.README.)} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \global\warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% Ignore text, except that we keep track of conditional commands for +% purposes of nesting, up to an `@end #1' command. +% +\def\nestedignore#1{% + \obstexwarn + % We must actually expand the ignored text to look for the @end + % command, so that nested ignore constructs work. Thus, we put the + % text into a \vbox and then do nothing with the result. To minimize + % the change of memory overflow, we follow the approach outlined on + % page 401 of the TeXbook: make the current font be a dummy font. + % + \setbox0 = \vbox\bgroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % We can't do anything about stray @-signs, unfortunately; + % they'll produce `undefined control sequence' errors. + \ignoremorecommands + % + % Set the current font to be \nullfont, a TeX primitive, and define + % all the font commands to also use \nullfont. We don't use + % dummy.tfm, as suggested in the TeXbook, because not all sites + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % Similarly for index fonts (mostly for their use in + % smallexample) + \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont + \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont + \let\indsf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}}% + % Do not execute macro definitions. + % `c' is a comment character, so the word `macro' will get cut off. + \def\macro{\doignore{ma}}% +} + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. Make sure the catcode of space is correct to avoid +% losing inside @example, for instance. +% +\def\set{\begingroup\catcode` =10 + \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR. + \parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi + \endgroup +} +% Can't use \xdef to pre-expand #2 and save some time, since \temp or +% \next or other control sequences that we've defined might get us into +% an infinite loop. Consider `@set foo @cite{bar}'. +\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +{ + \catcode`\_ = \active + % + % We might end up with active _ or - characters in the argument if + % we're called from @code, as @code{@value{foo-bar_}}. So \let any + % such active characters to their normal equivalents. + \gdef\value{\begingroup + \catcode`\-=12 \catcode`\_=12 + \indexbreaks \let_\normalunderscore + \valuexxx} +} +\def\valuexxx#1{\expandablevalue{#1}\endgroup} + +% We have this subroutine so that we can handle at least some @value's +% properly in indexes (we \let\value to this in \indexdummies). Ones +% whose names contain - or _ still won't work, but we can't do anything +% about that. The command has to be fully expandable, since the result +% winds up in the index file. This means that if the variable's value +% contains other Texinfo commands, it's almost certain it will fail +% (although perhaps we could fix that with sufficient work to do a +% one-level expansion on the result, instead of complete). +% +\def\expandablevalue#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + {[No value for ``#1'']}% + \else + \csname SET#1\endcsname + \fi +} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +\def\ifset{\parsearg\ifsetxxx} +\def\ifsetxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +\def\ifclear{\parsearg\ifclearxxx} +\def\ifclearxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @iftex, @ifnothtml, @ifnotinfo always succeed; we read the text +% following, through the first @end iftex (etc.). Make `@end iftex' +% (etc.) valid only after an @iftex. +% +\def\iftex{\conditionalsucceed{iftex}} +\def\ifnothtml{\conditionalsucceed{ifnothtml}} +\def\ifnotinfo{\conditionalsucceed{ifnotinfo}} +\defineunmatchedend{iftex} +\defineunmatchedend{ifnothtml} +\defineunmatchedend{ifnotinfo} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% define \Eiftex to redefine itself to be its previous value. (We can't +% just define it to fail again with an ``unmatched end'' error, since +% the @ifset might be nested.) +% +\def\conditionalsucceed#1{% + \edef\temp{% + % Remember the current value of \E#1. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\def\nece#1{\expandafter\noexpand\csname#1\endcsname} + +% @defininfoenclose. +\let\definfoenclose=\comment + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within \newindex. +{\catcode`\@=11 +\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. +% +\def\newindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 % Open the file + \fi + \expandafter\xdef\csname#1index\endcsname{% % Define @#1index + \noexpand\doindex{#1}} +} + +% @defindex foo == \newindex{foo} + +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. + +\def\newcodeindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 + \fi + \expandafter\xdef\csname#1index\endcsname{% + \noexpand\docodeindex{#1}} +} + +\def\defcodeindex{\parsearg\newcodeindex} + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +% The \closeout helps reduce unnecessary open files; the limit on the +% Acorn RISC OS is a mere 16 files. +\def\synindex#1 #2 {% + \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname + \expandafter\closeout\csname#1indfile\endcsname + \expandafter\let\csname#1indfile\endcsname=\synindexfoo + \expandafter\xdef\csname#1index\endcsname{% define \xxxindex + \noexpand\doindex{#2}}% +} + +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +\def\syncodeindex#1 #2 {% + \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname + \expandafter\closeout\csname#1indfile\endcsname + \expandafter\let\csname#1indfile\endcsname=\synindexfoo + \expandafter\xdef\csname#1index\endcsname{% define \xxxindex + \noexpand\docodeindex{#2}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +\def\indexdummies{% +\def\ { }% +% Take care of the plain tex accent commands. +\def\"{\realbackslash "}% +\def\`{\realbackslash `}% +\def\'{\realbackslash '}% +\def\^{\realbackslash ^}% +\def\~{\realbackslash ~}% +\def\={\realbackslash =}% +\def\b{\realbackslash b}% +\def\c{\realbackslash c}% +\def\d{\realbackslash d}% +\def\u{\realbackslash u}% +\def\v{\realbackslash v}% +\def\H{\realbackslash H}% +% Take care of the plain tex special European modified letters. +\def\oe{\realbackslash oe}% +\def\ae{\realbackslash ae}% +\def\aa{\realbackslash aa}% +\def\OE{\realbackslash OE}% +\def\AE{\realbackslash AE}% +\def\AA{\realbackslash AA}% +\def\o{\realbackslash o}% +\def\O{\realbackslash O}% +\def\l{\realbackslash l}% +\def\L{\realbackslash L}% +\def\ss{\realbackslash ss}% +% Take care of texinfo commands likely to appear in an index entry. +% (Must be a way to avoid doing expansion at all, and thus not have to +% laboriously list every single command here.) +\def\@{@}% will be @@ when we switch to @ as escape char. +% Need these in case \tex is in effect and \{ is a \delimiter again. +% But can't use \lbracecmd and \rbracecmd because texindex assumes +% braces and backslashes are used only as delimiters. +\let\{ = \mylbrace +\let\} = \myrbrace +\def\_{{\realbackslash _}}% +\def\w{\realbackslash w }% +\def\bf{\realbackslash bf }% +%\def\rm{\realbackslash rm }% +\def\sl{\realbackslash sl }% +\def\sf{\realbackslash sf}% +\def\tt{\realbackslash tt}% +\def\gtr{\realbackslash gtr}% +\def\less{\realbackslash less}% +\def\hat{\realbackslash hat}% +\def\TeX{\realbackslash TeX}% +\def\dots{\realbackslash dots }% +\def\result{\realbackslash result}% +\def\equiv{\realbackslash equiv}% +\def\expansion{\realbackslash expansion}% +\def\print{\realbackslash print}% +\def\error{\realbackslash error}% +\def\point{\realbackslash point}% +\def\copyright{\realbackslash copyright}% +\def\tclose##1{\realbackslash tclose {##1}}% +\def\code##1{\realbackslash code {##1}}% +\def\uref##1{\realbackslash uref {##1}}% +\def\url##1{\realbackslash url {##1}}% +\def\env##1{\realbackslash env {##1}}% +\def\command##1{\realbackslash command {##1}}% +\def\option##1{\realbackslash option {##1}}% +\def\dotless##1{\realbackslash dotless {##1}}% +\def\samp##1{\realbackslash samp {##1}}% +\def\,##1{\realbackslash ,{##1}}% +\def\t##1{\realbackslash t {##1}}% +\def\r##1{\realbackslash r {##1}}% +\def\i##1{\realbackslash i {##1}}% +\def\b##1{\realbackslash b {##1}}% +\def\sc##1{\realbackslash sc {##1}}% +\def\cite##1{\realbackslash cite {##1}}% +\def\key##1{\realbackslash key {##1}}% +\def\file##1{\realbackslash file {##1}}% +\def\var##1{\realbackslash var {##1}}% +\def\kbd##1{\realbackslash kbd {##1}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##1}}% +\def\acronym##1{\realbackslash acronym {##1}}% +% +% Handle some cases of @value -- where the variable name does not +% contain - or _, and the value does not contain any +% (non-fully-expandable) commands. +\let\value = \expandablevalue +% +\unsepspaces +% Turn off macro expansion +\turnoffmacros +} + +% If an index command is used in an @example environment, any spaces +% therein should become regular spaces in the raw index file, not the +% expansion of \tie (\\leavevmode \penalty \@M \ ). +{\obeyspaces + \gdef\unsepspaces{\obeyspaces\let =\space}} + +% \indexnofonts no-ops all font-change commands. +% This is used when outputting the strings to sort the index by. +\def\indexdummyfont#1{#1} +\def\indexdummytex{TeX} +\def\indexdummydots{...} + +\def\indexnofonts{% +% Just ignore accents. +\let\,=\indexdummyfont +\let\"=\indexdummyfont +\let\`=\indexdummyfont +\let\'=\indexdummyfont +\let\^=\indexdummyfont +\let\~=\indexdummyfont +\let\==\indexdummyfont +\let\b=\indexdummyfont +\let\c=\indexdummyfont +\let\d=\indexdummyfont +\let\u=\indexdummyfont +\let\v=\indexdummyfont +\let\H=\indexdummyfont +\let\dotless=\indexdummyfont +% Take care of the plain tex special European modified letters. +\def\oe{oe}% +\def\ae{ae}% +\def\aa{aa}% +\def\OE{OE}% +\def\AE{AE}% +\def\AA{AA}% +\def\o{o}% +\def\O{O}% +\def\l{l}% +\def\L{L}% +\def\ss{ss}% +\let\w=\indexdummyfont +\let\t=\indexdummyfont +\let\r=\indexdummyfont +\let\i=\indexdummyfont +\let\b=\indexdummyfont +\let\emph=\indexdummyfont +\let\strong=\indexdummyfont +\let\cite=\indexdummyfont +\let\sc=\indexdummyfont +%Don't no-op \tt, since it isn't a user-level command +% and is used in the definitions of the active chars like <, >, |... +%\let\tt=\indexdummyfont +\let\tclose=\indexdummyfont +\let\code=\indexdummyfont +\let\url=\indexdummyfont +\let\uref=\indexdummyfont +\let\env=\indexdummyfont +\let\command=\indexdummyfont +\let\option=\indexdummyfont +\let\file=\indexdummyfont +\let\samp=\indexdummyfont +\let\kbd=\indexdummyfont +\let\key=\indexdummyfont +\let\var=\indexdummyfont +\let\TeX=\indexdummytex +\let\dots=\indexdummydots +\def\@{@}% +} + +% To define \realbackslash, we must make \ not be an escape. +% We must first make another character (@) an escape +% so we do not become unable to do a definition. + +{\catcode`\@=0 \catcode`\\=\other + @gdef@realbackslash{\}} + +\let\indexbackslash=0 %overridden during \printindex. +\let\SETmarginindex=\relax % put index entries in margin (undocumented)? + +% For \ifx comparisons. +\def\emptymacro{\empty} + +% Most index entries go through here, but \dosubind is the general case. +% +\def\doind#1#2{\dosubind{#1}{#2}\empty} + +% Workhorse for all \fooindexes. +% #1 is name of index, #2 is stuff to put there, #3 is subentry -- +% \empty if called from \doind, as we usually are. The main exception +% is with defuns, which call us directly. +% +\def\dosubind#1#2#3{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% + \fi + {% + \count255=\lastpenalty + {% + \indexdummies % Must do this here, since \bf, etc expand at this stage + \escapechar=`\\ + {% + \let\folio = 0% We will expand all macros now EXCEPT \folio. + \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + \def\thirdarg{#3}% + % + % If third arg is present, precede it with space in sort key. + \ifx\thirdarg\emptymacro + \let\subentry = \empty + \else + \def\subentry{ #3}% + \fi + % + % First process the index entry with all font commands turned + % off to get the string to sort by. + {\indexnofonts \xdef\indexsorttmp{#2\subentry}}% + % + % Now the real index entry with the fonts. + \toks0 = {#2}% + % + % If third (subentry) arg is present, add it to the index + % string. And include a space. + \ifx\thirdarg\emptymacro \else + \toks0 = \expandafter{\the\toks0 \space #3}% + \fi + % + % Set up the complete index entry, with both the sort key + % and the original text, including any font commands. We write + % three arguments to \entry to the .?? file, texindex reduces to + % two when writing the .??s sorted result. + \edef\temp{% + \write\csname#1indfile\endcsname{% + \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}% + }% + % + % If a skip is the last thing on the list now, preserve it + % by backing up by \lastskip, doing the \write, then inserting + % the skip again. Otherwise, the whatsit generated by the + % \write will make \lastskip zero. The result is that sequences + % like this: + % @end defun + % @tindex whatever + % @defun ... + % will have extra space inserted, because the \medbreak in the + % start of the @defun won't see the skip inserted by the @end of + % the previous defun. + % + % But don't do any of this if we're not in vertical mode. We + % don't want to do a \vskip and prematurely end a paragraph. + % + % Avoid page breaks due to these extra skips, too. + % + \iflinks + \ifvmode + \skip0 = \lastskip + \ifdim\lastskip = 0pt \else \nobreak\vskip-\lastskip \fi + \fi + % + \temp % do the write + % + % + \ifvmode \ifdim\skip0 = 0pt \else \nobreak\vskip\skip0 \fi \fi + \fi + }% + }% + \penalty\count255 + }% +} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% @printindex causes a particular index (the ??s file) to get printed. +% It does not print any chapter heading (usually an @unnumbered). +% +\def\printindex{\parsearg\doprintindex} +\def\doprintindex#1{\begingroup + \dobreak \chapheadingskip{10000}% + % + \indexfonts \rm + \tolerance = 9500 + \indexbreaks + % + % See if the index file exists and is nonempty. + % Change catcode of @ here so that if the index file contains + % \initial {@} + % as its first line, TeX doesn't complain about mismatched braces + % (because it thinks @} is a control sequence). + \catcode`\@ = 11 + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + \putwordIndexNonexistent + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + \putwordIndexIsEmpty + \else + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \def\indexbackslash{\rawbackslashxx}% + \catcode`\\ = 0 + \escapechar = `\\ + \begindoublecolumns + \input \jobname.#1s + \enddoublecolumns + \fi + \fi + \closein 1 +\endgroup} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +\def\initial#1{{% + % Some minor font changes for the special characters. + \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt + % + % Remove any glue we may have, we'll be inserting our own. + \removelastskip + % + % We like breaks before the index initials, so insert a bonus. + \penalty -300 + % + % Typeset the initial. Making this add up to a whole number of + % baselineskips increases the chance of the dots lining up from column + % to column. It still won't often be perfect, because of the stretch + % we need before each entry, but it's better. + % + % No shrink because it confuses \balancecolumns. + \vskip 1.67\baselineskip plus .5\baselineskip + \leftline{\secbf #1}% + \vskip .33\baselineskip plus .1\baselineskip + % + % Do our best not to break after the initial. + \nobreak +}} + +% This typesets a paragraph consisting of #1, dot leaders, and then #2 +% flush to the right margin. It is used for index and table of contents +% entries. The paragraph is indented by \leftskip. +% +\def\entry#1#2{\begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent = 2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % A bit of stretch before each entry for the benefit of balancing columns. + \vskip 0pt plus1pt + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % Insert the text of the index entry. TeX will do line-breaking on it. + #1% + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ #2% The page number ends the paragraph. + \fi% + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm + +\def\secondary #1#2{ +{\parfillskip=0in \parskip=0in +\hangindent =1in \hangafter=1 +\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 + +\newbox\partialpage +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {% + % + % Here is a possibility not foreseen in manmac: if we accumulate a + % whole lot of material, we might end up calling this \output + % routine twice in a row (see the doublecol-lose test, which is + % essentially a couple of indexes with @setchapternewpage off). In + % that case we just ship out what is in \partialpage with the normal + % output routine. Generally, \partialpage will be empty when this + % runs and this will be a no-op. See the indexspread.tex test case. + \ifvoid\partialpage \else + \onepageout{\pagecontents\partialpage}% + \fi + % + \global\setbox\partialpage = \vbox{% + % Unvbox the main output page. + \unvbox\PAGE + \kern-\topskip \kern\baselineskip + }% + }% + \eject % run that output routine to set \partialpage + % + % Use the double-column output routine for subsequent pages. + \output = {\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it in one place. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +-<1pt) + % as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \advance\vsize by -\ht\partialpage + \vsize = 2\vsize +} + +% The double-column output routine for all double-column pages except +% the last. +% +\def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@ = \vsize + \divide\dimen@ by 2 + % + % box0 will be the left-hand column, box2 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 + \penalty\outputpenalty +} +\def\pagesofar{% + % Re-output the contents of the output page -- any previous material, + % followed by the two boxes we just split, in box0 and box2. + \unvbox\partialpage + % + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize + \hbox to\pagewidth{\box0\hfil\box2}% +} +\def\enddoublecolumns{% + \output = {% + % Split the last of the double-column material. Leave it on the + % current page, no automatic page break. + \balancecolumns + % + % If we end up splitting too much material for the current page, + % though, there will be another page break right after this \output + % invocation ends. Having called \balancecolumns once, we do not + % want to call it again. Therefore, reset \output to its normal + % definition right away. (We hope \balancecolumns will never be + % called on to balance too much material, but if it is, this makes + % the output somewhat more palatable.) + \global\output = {\onepageout{\pagecontents\PAGE}}% + }% + \eject + \endgroup % started in \begindoublecolumns + % + % \pagegoal was set to the doubled \vsize above, since we restarted + % the current page. We're now back to normal single-column + % typesetting, so reset \pagegoal to the normal \vsize (after the + % \endgroup where \vsize got restored). + \pagegoal = \vsize +} +\def\balancecolumns{% + % Called at the end of the double column material. + \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 % target to split to + %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {% + \vbadness = 10000 + \loop + \global\setbox3 = \copy0 + \global\setbox1 = \vsplit3 to \dimen@ + \ifdim\ht3>\dimen@ + \global\advance\dimen@ by 1pt + \repeat + }% + %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + % + \pagesofar +} +\catcode`\@ = \other + + +\message{sectioning,} +% Define chapters, sections, etc. + +\newcount\chapno +\newcount\secno \secno=0 +\newcount\subsecno \subsecno=0 +\newcount\subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount\appendixno \appendixno = `\@ +\def\appendixletter{\char\the\appendixno} + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise. +\def\thischapter{} +\def\thissection{} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + +% @chapter, @appendix, @unnumbered. +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \chapno by 1 \message{\putwordChapter\space \the\chapno}% +\chapmacro {#1}{\the\chapno}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +% We don't substitute the actual chapter name into \thischapter +% because we don't want its macros evaluated now. +\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}% + {\the\chapno}}}% +\temp +\donoderef +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec +} + +\outer\def\appendix{\parsearg\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 +\message{\putwordAppendix\space \appendixletter}% +\chapmacro {#1}{\putwordAppendix{} \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}% + {\putwordAppendix{} \appendixletter}}}% +\temp +\appendixnoderef +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\def\centerchap{\parsearg\centerchapyyy} +\def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}} + +% @top is like @unnumbered. +\outer\def\top{\parsearg\unnumberedyyy} + +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% argument to \message. Therefore, if #1 contained @-commands, TeX +% expanded them. For example, in `@unnumbered The @cite{Book}', TeX +% expanded @cite (which turns out to cause errors because \cite is meant +% to be executed, not expanded). +% +% Anyway, we don't want the fully-expanded definition of @cite to appear +% as a result of the \message, we just want `@cite' itself. We use +% \the to achieve this: TeX expands \the only once, +% simply yielding the contents of . (We also do this for +% the toc entries.) +\toks0 = {#1}\message{(\the\toks0)}% +% +\unnumbchapmacro {#1}% +\gdef\thischapter{#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbchapentry{\the\toks0}}}% +\temp +\unnumbnoderef +\global\let\section = \unnumberedsec +\global\let\subsection = \unnumberedsubsec +\global\let\subsubsection = \unnumberedsubsubsec +} + +% Sections. +\outer\def\numberedsec{\parsearg\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls seczzz +\def\seczzz #1{% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}% + {\the\chapno}{\the\secno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz #1{% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}% + {\appendixletter}{\the\secno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz #1{% +\plainsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsecentry{\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% Subsections. +\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz #1{% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}% + {\the\chapno}{\the\secno}{\the\subsecno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz #1{% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}% + {\appendixletter}{\the\secno}{\the\subsecno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz #1{% +\plainsubsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsecentry% + {\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% Subsubsections. +\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz #1{% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}% + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz #1{% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}% + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz #1{% +\plainsubsubsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsubsecentry% + {\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% These are variants which are not "outer", so they can appear in @ifinfo. +% Actually, they should now be obsolete; ordinary section commands should work. +\def\infotop{\parsearg\unnumberedzzz} +\def\infounnumbered{\parsearg\unnumberedzzz} +\def\infounnumberedsec{\parsearg\unnumberedseczzz} +\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} +\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + +\def\infoappendix{\parsearg\appendixzzz} +\def\infoappendixsec{\parsearg\appendixseczzz} +\def\infoappendixsubsec{\parsearg\appendixsubseczzz} +\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + +\def\infochapter{\parsearg\chapterzzz} +\def\infosection{\parsearg\sectionzzz} +\def\infosubsection{\parsearg\subsectionzzz} +\def\infosubsubsection{\parsearg\subsubsectionzzz} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{\parsearg\majorheadingzzz} +\def\majorheadingzzz #1{% +{\advance\chapheadingskip by 10pt \chapbreak }% +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\chapheading{\parsearg\chapheadingzzz} +\def\chapheadingzzz #1{\chapbreak % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +% @heading, @subheading, @subsubheading. +\def\heading{\parsearg\plainsecheading} +\def\subheading{\parsearg\plainsubsecheading} +\def\subsubheading{\parsearg\plainsubsubsecheading} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip\chapheadingskip + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{ +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +\def\CHAPFplain{ +\global\let\chapmacro=\chfplain +\global\let\unnumbchapmacro=\unnchfplain +\global\let\centerchapmacro=\centerchfplain} + +% Plain chapter opening. +% #1 is the text, #2 the chapter number or empty if unnumbered. +\def\chfplain#1#2{% + \pchapsepmacro + {% + \chapfonts \rm + \def\chapnum{#2}% + \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}% + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% Plain opening for unnumbered. +\def\unnchfplain#1{\chfplain{#1}{}} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerchfplain#1{{% + \def\centerparametersmaybe{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt + }% + \chfplain{#1}{}% +}} + +\CHAPFplain % The default + +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\nobreak +} + +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} + +\def\centerchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rm #1}\hfill}}\bigskip \par\nobreak +} + +\def\CHAPFopen{ +\global\let\chapmacro=\chfopen +\global\let\unnumbchapmacro=\unnchfopen +\global\let\centerchapmacro=\centerchfopen} + + +% Section titles. +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip {-1000}} +\def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}} +\def\plainsecheading#1{\sectionheading{sec}{}{#1}} + +% Subsection titles. +\newskip \subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} +\def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}} +\def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}} + +% Subsubsection titles. +\let\subsubsecheadingskip = \subsecheadingskip +\let\subsubsecheadingbreak = \subsecheadingbreak +\def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}} +\def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}} + + +% Print any size section title. +% +% #1 is the section type (sec/subsec/subsubsec), #2 is the section +% number (maybe empty), #3 the text. +\def\sectionheading#1#2#3{% + {% + \expandafter\advance\csname #1headingskip\endcsname by \parskip + \csname #1headingbreak\endcsname + }% + {% + % Switch to the right set of fonts. + \csname #1fonts\endcsname \rm + % + % Only insert the separating space if we have a section number. + \def\secnum{#2}% + \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}% + % + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 % zero if no section number + \unhbox0 #3}% + }% + \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak +} + + +\message{toc,} +\newwrite\tocfile + +% Write an entry to the toc file, opening it if necessary. +% Called from @chapter, etc. We supply {\folio} at the end of the +% argument, which will end up as the last argument to the \...entry macro. +% +% We open the .toc file here instead of at @setfilename or any other +% given time so that @contents can be put in the document anywhere. +% +\newif\iftocfileopened +\def\writetocentry#1{% + \iftocfileopened\else + \immediate\openout\tocfile = \jobname.toc + \global\tocfileopenedtrue + \fi + \iflinks \write\tocfile{#1{\folio}}\fi +} + +\newskip\contentsrightmargin \contentsrightmargin=1in +\newcount\savepageno +\newcount\lastnegativepageno \lastnegativepageno = -1 + +% Finish up the main text and prepare to read what we've written +% to \tocfile. +% +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund + \contentsalignmacro + \immediate\closeout\tocfile + % + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \unnumbchapmacro{#1}\def\thischapter{}% + \savepageno = \pageno + \begingroup % Set up to handle contents files properly. + \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + % We can't do this, because then an actual ^ in a section + % title fails, e.g., @chapter ^ -- exponentiation. --karl, 9jul97. + %\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. + % + % Roman numerals for page numbers. + \ifnum \pageno>0 \pageno = \lastnegativepageno \fi +} + + +% Normal (long) toc. +\def\contents{% + \startcontents{\putwordTOC}% + \openin 1 \jobname.toc + \ifeof 1 \else + \closein 1 + \input \jobname.toc + \fi + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \endgroup + \lastnegativepageno = \pageno + \pageno = \savepageno +} + +% And just the chapters. +\def\summarycontents{% + \startcontents{\putwordShortTOC}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \openin 1 \jobname.toc + \ifeof 1 \else + \closein 1 + \input \jobname.toc + \fi + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \endgroup + \lastnegativepageno = \pageno + \pageno = \savepageno +} +\let\shortcontents = \summarycontents + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapter-level things, for both the long and short contents. +\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + +% See comments in \dochapentry re vbox and related settings +\def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% We could simplify the code here by writing out an \appendixentry +% command in the toc file for appendices, instead of using \chapentry +% for both, but it doesn't seem worth it. +\setbox0 = \hbox{\shortcontrm \putwordAppendix } +\newdimen\shortappendixwidth \shortappendixwidth = \wd0 + +\def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}} + +% Sections. +\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} +\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + +% Subsections. +\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} +\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + +% And subsubsections. +\def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} +\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + +% This parameter controls the indentation of the various levels. +\newdimen\tocindent \tocindent = 3pc + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno{#2}}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% the index entries, but we want to suppress hyphenation here. (We +% can't do that in the \entry macro, since index entries might consist +% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) +\def\tocentry#1#2{\begingroup + \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks + % Do not use \turnoffactive in these arguments. Since the toc is + % typeset in cmr, so characters such as _ would come out wrong; we + % have to do the usual translation tricks. + \entry{#1}{#2}% +\endgroup} + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\let\subsecentryfonts = \textfonts +\let\subsubsecentryfonts = \textfonts + + +\message{environments,} + +% Since these characters are used in examples, it should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% Furthermore, these definitions must come after we define our fonts. +\newbox\dblarrowbox \newbox\longdblarrowbox +\newbox\pushcharbox \newbox\bullbox +\newbox\equivbox \newbox\errorbox + +%{\tentt +%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} +%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} +%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} +%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} +% Adapted from the manmac format (p.420 of TeXbook) +%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex +% depth .1ex\hfil} +%} + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +\def\point{$\star$} +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% Adapted from the TeXbook's \boxit. +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + +\global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + +% The @error{} command. +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\def\tex{\begingroup + \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 + \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 + \catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie + \catcode `\%=14 + \catcode 43=12 % plus + \catcode`\"=12 + \catcode`\==12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \escapechar=`\\ + % + \let\b=\ptexb + \let\bullet=\ptexbullet + \let\c=\ptexc + \let\,=\ptexcomma + \let\.=\ptexdot + \let\dots=\ptexdots + \let\equiv=\ptexequiv + \let\!=\ptexexclam + \let\i=\ptexi + \let\{=\ptexlbrace + \let\+=\tabalign + \let\}=\ptexrbrace + \let\*=\ptexstar + \let\t=\ptext + % + \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% + \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% + \def\@{@}% +\let\Etex=\endgroup} + +% Define @lisp ... @endlisp. +% @lisp does a \begingroup so it can rebind things, +% including the definition of @endlisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% Make each space character in the input produce a normal interword +% space in the output. Don't allow a line break at this space, as this +% is used only in environments like @example, where each line of input +% should produce a line of output anyway. +% +{\obeyspaces % +\gdef\sepspaces{\obeyspaces\let =\tie}} + +% Define \obeyedspace to be our active space, whatever it is. This is +% for use in \parsearg. +{\sepspaces% +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip +% +\def\aboveenvbreak{{\advance\envskipamount by \parskip +\endgraf \ifdim\lastskip<\envskipamount +\removelastskip \penalty-50 \vskip\envskipamount \fi}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. +\let\nonarrowing=\relax + +% @cartouche ... @end cartouche: draw rectangle w/rounded corners around +% environment contents. +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\long\def\cartouche{% +\begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18.4pt % allow for 3pt kerns on either +% side, and for 6pt waste from +% each corner char, and rule thickness + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip +\def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup +\endgroup +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \inENV % This group ends at the end of the body + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \singlespace + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +% Define the \E... control sequence only if we are inside the particular +% environment, so the error checking in \end will work. +% +% To end an @example-like environment, we first end the paragraph (via +% \afterenvbreak's vertical glue), and then the group. That way we keep +% the zero \parskip that the environments set -- \parskip glue will be +% inserted at the beginning of the next paragraph in the document, after +% the environment. +% +\def\nonfillfinish{\afterenvbreak\endgroup} + +% @lisp: indented, narrowed, typewriter font. +\def\lisp{\begingroup + \nonfillstart + \let\Elisp = \nonfillfinish + \tt + \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. + \gobble % eat return +} + +% @example: Same as @lisp. +\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} + +% @small... is usually equivalent to the non-small (@smallbook +% redefines). We must call \example (or whatever) last in the +% definition, since it reads the return following the @example (or +% whatever) command. +% +% This actually allows (for example) @end display inside an +% @smalldisplay. Too bad, but makeinfo will catch the error anyway. +% +\def\smalldisplay{\begingroup\def\Esmalldisplay{\nonfillfinish\endgroup}\display} +\def\smallexample{\begingroup\def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smallformat{\begingroup\def\Esmallformat{\nonfillfinish\endgroup}\format} +\def\smalllisp{\begingroup\def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + +% Real @smallexample and @smalllisp (when @smallbook): use smaller fonts. +% Originally contributed by Pavel@xerox. +\def\smalllispx{\begingroup + \def\Esmalllisp{\nonfillfinish\endgroup}% + \def\Esmallexample{\nonfillfinish\endgroup}% + \indexfonts + \lisp +} + +% @display: same as @lisp except keep current font. +% +\def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble +} + +% @smalldisplay (when @smallbook): @display plus smaller fonts. +% +\def\smalldisplayx{\begingroup + \def\Esmalldisplay{\nonfillfinish\endgroup}% + \indexfonts \rm + \display +} + +% @format: same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble +} + +% @smallformat (when @smallbook): @format plus smaller fonts. +% +\def\smallformatx{\begingroup + \def\Esmallformat{\nonfillfinish\endgroup}% + \indexfonts \rm + \format +} + +% @flushleft (same as @format). +% +\def\flushleft{\begingroup \def\Eflushleft{\nonfillfinish\endgroup}\format} + +% @flushright. +% +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble +} + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. +% +\def\quotation{% + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \let\nonarrowing = \relax + \fi +} + + +\message{defuns,} +% Define formatter for defuns +% First, allow user to change definition object font (\df) internally +\def\setdeffont #1 {\csname DEF#1\endcsname} + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deftypemargin \deftypemargin=12pt +\newskip\deflastargmargin \deflastargmargin=18pt + +\newcount\parencount +% define \functionparens, which makes ( and ) and & do special things. +% \functionparens affects the group it is contained in. +\def\activeparens{% +\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active +\catcode`\[=\active \catcode`\]=\active} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } +\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} +% This is used to turn on special parens +% but make & act ordinary (given that it's active). +\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr} + +% Definitions of (, ) and & used in args for functions. +% This is the definition of ( outside of all parentheses. +\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested + \global\advance\parencount by 1 +} +% +% This is the definition of ( when already inside a level of parens. +\gdef\opnested{\char`\(\global\advance\parencount by 1 } +% +\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. + % also in that case restore the outer-level definition of (. + \ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi + \global\advance \parencount by -1 } +% If we encounter &foo, then turn on ()-hacking afterwards +\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } +% +\gdef\normalparens{\boldbrax\let&=\ampnr} +} % End of definition inside \activeparens +%% These parens (in \boldbrax) actually are a little bolder than the +%% contained text. This is especially needed for [ and ] +\def\opnr{{\sf\char`\(}\global\advance\parencount by 1 } +\def\clnr{{\sf\char`\)}\global\advance\parencount by -1 } +\def\ampnr{\&} +\def\lbrb{{\bf\char`\[}} +\def\rbrb{{\bf\char`\]}} + +% First, defname, which formats the header line itself. +% #1 should be the function name. +% #2 should be the type of definition, such as "Function". + +\def\defname #1#2{% +% Get the values of \leftskip and \rightskip as they were +% outside the @def... +\dimen2=\leftskip +\advance\dimen2 by -\defbodyindent +\noindent +\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% +\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line +\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations +\parshape 2 0in \dimen0 \defargsindent \dimen1 +% Now output arg 2 ("Function" or some such) +% ending at \deftypemargin from the right margin, +% but stuck inside a box of width 0 so it does not interfere with linebreaking +{% Adjust \hsize to exclude the ambient margins, +% so that \rightline will obey them. +\advance \hsize by -\dimen2 +\rlap{\rightline{{\rm #2}\hskip -1.25pc }}}% +% Make all lines underfull and no complaints: +\tolerance=10000 \hbadness=10000 +\advance\leftskip by -\defbodyindent +\exdentamount=\defbodyindent +{\df #1}\enskip % Generate function name +} + +% Actually process the body of a definition +% #1 should be the terminating control sequence, such as \Edefun. +% #2 should be the "another name" control sequence, such as \defunx. +% #3 should be the control sequence that actually processes the header, +% such as \defunheader. + +\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % 61 is `=' +\obeylines\activeparens\spacesplit#3} + +% #1 is the \E... control sequence to end the definition (which we define). +% #2 is the \...x control sequence for consecutive fns (which we define). +% #3 is the control sequence to call to resume processing. +% #4, delimited by the space, is the class name. +% +\def\defmethparsebody#1#2#3#4 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + +% @deftypemethod has an extra argument that nothing else does. Sigh. +% #1 is the \E... control sequence to end the definition (which we define). +% #2 is the \...x control sequence for consecutive fns (which we define). +% #3 is the control sequence to call to resume processing. +% #4, delimited by the space, is the class name. +% #5 is the method's return type. +% +\def\deftypemethparsebody#1#2#3#4 #5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}{#5}}} + +\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + +% These parsing functions are similar to the preceding ones +% except that they do not make parens into active characters. +% These are used for "variables" since they have no arguments. + +\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\spacesplit#3} + +% This is used for \def{tp,vr}parsebody. It could probably be used for +% some of the others, too, with some judicious conditionals. +% +\def\parsebodycommon#1#2#3{% + \begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines +} + +\def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% +} + +% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the +% type is just `struct', because we lose the braces in `{struct +% termios}' when \spacesplit reads its undelimited argument. Sigh. +% \let\deftpparsebody=\defvrparsebody +% +% So, to get around this, we put \empty in with the type name. That +% way, TeX won't find exactly `{...}' as an undelimited argument, and +% won't strip off the braces. +% +\def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty +} + +% Fine, but then we have to eventually remove the \empty *and* the +% braces (if any). That's what this does. +% +\def\removeemptybraces\empty#1\relax{#1} + +% After \spacesplit has done its work, this is called -- #1 is the final +% thing to call, #2 the type name (which starts with \empty), and #3 +% (which might be empty) the arguments. +% +\def\parsetpheaderline#1#2#3{% + #1{\removeemptybraces#2\relax}{#3}% +}% + +\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#5}}} + +% Split up #2 at the first space token. +% call #1 with two arguments: +% the first is all of #2 before the space token, +% the second is all of #2 after that space token. +% If #2 contains no space token, all of it is passed as the first arg +% and the second is passed as empty. + +{\obeylines +\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% +\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% +\ifx\relax #3% +#1{#2}{}\else #1{#2}{#3#4}\fi}} + +% So much for the things common to all kinds of definitions. + +% Define @defun. + +% First, define the processing that is wanted for arguments of \defun +% Use this to expand the args and terminate the paragraph they make up + +\def\defunargs #1{\functionparens \sl +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\hyphenchar\tensl=0 +#1% +\hyphenchar\tensl=45 +\ifnum\parencount=0 \else \errmessage{Unbalanced parentheses in @def}\fi% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\nobreak\vskip -\parskip\nobreak +} + +\def\deftypefunargs #1{% +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +% Use \boldbraxnoamp, not \functionparens, so that & is not special. +\boldbraxnoamp +\tclose{#1}% avoid \code because of side effects on active chars +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\nobreak\vskip -\parskip\nobreak +} + +% Do complete processing of one @defun or @defunx line already parsed. + +% @deffn Command forward-char nchars + +\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + +\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% +\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defun == @deffn Function + +\def\defun{\defparsebody\Edefun\defunx\defunheader} + +\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{\putwordDeffunc}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefun int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + +% #1 is the data type. #2 is the name and args. +\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} +% #1 is the data type, #2 the name, #3 the args. +\def\deftypefunheaderx #1#2 #3\relax{% +\doind {fn}{\code{#2}}% Make entry in function index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypefun}% +\deftypefunargs {#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + +% \defheaderxcond#1\relax$$$ +% puts #1 in @code, followed by a space, but does nothing if #1 is null. +\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + +% #1 is the classification. #2 is the data type. #3 is the name and args. +\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} +% #1 is the classification, #2 the data type, #3 the name, #4 the args. +\def\deftypefnheaderx #1#2#3 #4\relax{% +\doind {fn}{\code{#3}}% Make entry in function index +\begingroup +\normalparens % notably, turn off `&' magic, which prevents +% at least some C++ text from working +\defname {\defheaderxcond#2\relax$$$#3}{#1}% +\deftypefunargs {#4}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defmac == @deffn Macro + +\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + +\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{\putwordDefmac}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defspec == @deffn Special Form + +\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + +\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{\putwordDefspec}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% This definition is run if you use @defunx +% anywhere other than immediately after a @defun or @defunx. + +\def\deffnx #1 {\errmessage{@deffnx in invalid context}} +\def\defunx #1 {\errmessage{@defunx in invalid context}} +\def\defmacx #1 {\errmessage{@defmacx in invalid context}} +\def\defspecx #1 {\errmessage{@defspecx in invalid context}} +\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}} +\def\deftypemethodx #1 {\errmessage{@deftypemethodx in invalid context}} +\def\deftypefunx #1 {\errmessage{@deftypefunx in invalid context}} + +% @defmethod, and so on + +% @defop CATEGORY CLASS OPERATION ARG... + +\def\defop #1 {\def\defoptype{#1}% +\defopparsebody\Edefop\defopx\defopheader\defoptype} + +\def\defopheader #1#2#3{% +\dosubind {fn}{\code{#2}}{\putwordon\ #1}% Make entry in function index +\begingroup\defname {#2}{\defoptype{}\putwordon\ #1}% +\defunargs {#3}\endgroup % +} + +% @deftypemethod CLASS RETURN-TYPE METHOD ARG... +% +\def\deftypemethod{% + \deftypemethparsebody\Edeftypemethod\deftypemethodx\deftypemethodheader} +% +% #1 is the class name, #2 the data type, #3 the method name, #4 the args. +\def\deftypemethodheader#1#2#3#4{% + \dosubind{fn}{\code{#3}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{\defheaderxcond#2\relax$$$#3}{\putwordMethodon\ \code{#1}}% + \deftypefunargs{#4}% + \endgroup +} + +% @defmethod == @defop Method +% +\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} +% +% #1 is the class name, #2 the method name, #3 the args. +\def\defmethodheader#1#2#3{% + \dosubind{fn}{\code{#2}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{#2}{\putwordMethodon\ \code{#1}}% + \defunargs{#3}% + \endgroup +} + +% @defcv {Class Option} foo-class foo-flag + +\def\defcv #1 {\def\defcvtype{#1}% +\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + +\def\defcvarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{\putwordof\ #1}% Make entry in var index +\begingroup\defname {#2}{\defcvtype\ \putwordof\ #1}% +\defvarargs {#3}\endgroup % +} + +% @defivar == @defcv {Instance Variable} + +\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} + +\def\defivarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{\putwordof\ #1}% Make entry in var index +\begingroup\defname {#2}{\putwordDefivar\ \putwordof\ #1}% +\defvarargs {#3}\endgroup % +} + +% These definitions are run if you use @defmethodx, etc., +% anywhere other than immediately after a @defmethod, etc. + +\def\defopx #1 {\errmessage{@defopx in invalid context}} +\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}} +\def\defcvx #1 {\errmessage{@defcvx in invalid context}} +\def\defivarx #1 {\errmessage{@defivarx in invalid context}} + +% Now @defvar + +% First, define the processing that is wanted for arguments of @defvar. +% This is actually simple: just print them in roman. +% This must expand the args and terminate the paragraph they make up +\def\defvarargs #1{\normalparens #1% +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak} + +% @defvr Counter foo-count + +\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + +\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% +\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + +% @defvar == @defvr Variable + +\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + +\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{\putwordDefvar}% +\defvarargs {#2}\endgroup % +} + +% @defopt == @defvr {User Option} + +\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + +\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{\putwordDefopt}% +\defvarargs {#2}\endgroup % +} + +% @deftypevar int foobar + +\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + +% #1 is the data type. #2 is the name, perhaps followed by text that +% is actually part of the data type, which should not be put into the index. +\def\deftypevarheader #1#2{% +\dovarind#2 \relax% Make entry in variables index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypevar}% +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak +\endgroup} +\def\dovarind#1 #2\relax{\doind{vr}{\code{#1}}} + +% @deftypevr {Global Flag} int enable + +\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + +\def\deftypevrheader #1#2#3{\dovarind#3 \relax% +\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak +\endgroup} + +% This definition is run if you use @defvarx +% anywhere other than immediately after a @defvar or @defvarx. + +\def\defvrx #1 {\errmessage{@defvrx in invalid context}} +\def\defvarx #1 {\errmessage{@defvarx in invalid context}} +\def\defoptx #1 {\errmessage{@defoptx in invalid context}} +\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}} +\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}} + +% Now define @deftp +% Args are printed in bold, a slight difference from @defvar. + +\def\deftpargs #1{\bf \defvarargs{#1}} + +% @deftp Class window height width ... + +\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + +\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% +\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + +% This definition is run if you use @deftpx, etc +% anywhere other than immediately after a @deftp, etc. + +\def\deftpx #1 {\errmessage{@deftpx in invalid context}} + + +\message{macros,} +% @macro. + +% To do this right we need a feature of e-TeX, \scantokens, +% which we arrange to emulate with a temporary file in ordinary TeX. +\ifx\eTeXversion\undefined + \newwrite\macscribble + \def\scanmacro#1{% + \begingroup \newlinechar`\^^M + % Undo catcode changes of \startcontents and \doprintindex + \catcode`\@=0 \catcode`\\=12 \escapechar=`\@ + % Append \endinput to make sure that TeX does not see the ending newline. + \toks0={#1\endinput}% + \immediate\openout\macscribble=\jobname.tmp + \immediate\write\macscribble{\the\toks0}% + \immediate\closeout\macscribble + \let\xeatspaces\eatspaces + \input \jobname.tmp + \endgroup +} +\else +\def\scanmacro#1{% +\begingroup \newlinechar`\^^M +% Undo catcode changes of \startcontents and \doprintindex +\catcode`\@=0 \catcode`\\=12 \escapechar=`\@ +\let\xeatspaces\eatspaces\scantokens{#1\endinput}\endgroup} +\fi + +\newcount\paramno % Count of parameters +\newtoks\macname % Macro name +\newif\ifrecursive % Is it recursive? +\def\macrolist{} % List of all defined macros in the form + % \do\macro1\do\macro2... + +% Utility routines. +% Thisdoes \let #1 = #2, except with \csnames. +\def\cslet#1#2{% +\expandafter\expandafter +\expandafter\let +\expandafter\expandafter +\csname#1\endcsname +\csname#2\endcsname} + +% Trim leading and trailing spaces off a string. +% Concepts from aro-bend problem 15 (see CTAN). +{\catcode`\@=11 +\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} +\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} +\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} +\def\unbrace#1{#1} +\unbrace{\gdef\trim@@@ #1 } #2@{#1} +} + +% Trim a single trailing ^^M off a string. +{\catcode`\^^M=12\catcode`\Q=3% +\gdef\eatcr #1{\eatcra #1Q^^MQ}% +\gdef\eatcra#1^^MQ{\eatcrb#1Q}% +\gdef\eatcrb#1Q#2Q{#1}% +} + +% Macro bodies are absorbed as an argument in a context where +% all characters are catcode 10, 11 or 12, except \ which is active +% (as in normal texinfo). It is necessary to change the definition of \. + +% It's necessary to have hard CRs when the macro is executed. This is +% done by making ^^M (\endlinechar) catcode 12 when reading the macro +% body, and then making it the \newlinechar in \scanmacro. + +\def\macrobodyctxt{% + \catcode`\~=12 + \catcode`\^=12 + \catcode`\_=12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \catcode`\+=12 + \catcode`\{=12 + \catcode`\}=12 + \catcode`\@=12 + \catcode`\^^M=12 + \usembodybackslash} + +\def\macroargctxt{% + \catcode`\~=12 + \catcode`\^=12 + \catcode`\_=12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \catcode`\+=12 + \catcode`\@=12 + \catcode`\\=12} + +% \mbodybackslash is the definition of \ in @macro bodies. +% It maps \foo\ => \csname macarg.foo\endcsname => #N +% where N is the macro parameter number. +% We define \csname macarg.\endcsname to be \realbackslash, so +% \\ in macro replacement text gets you a backslash. + +{\catcode`@=0 @catcode`@\=@active + @gdef@usembodybackslash{@let\=@mbodybackslash} + @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} +} +\expandafter\def\csname macarg.\endcsname{\realbackslash} + +\def\macro{\recursivefalse\parsearg\macroxxx} +\def\rmacro{\recursivetrue\parsearg\macroxxx} + +\def\macroxxx#1{% + \getargs{#1}% now \macname is the macname and \argl the arglist + \ifx\argl\empty % no arguments + \paramno=0% + \else + \expandafter\parsemargdef \argl;% + \fi + \if1\csname ismacro.\the\macname\endcsname + \message{Warning: redefining \the\macname}% + \else + \expandafter\ifx\csname \the\macname\endcsname \relax + \else \errmessage{The name \the\macname\space is reserved}\fi + \global\cslet{macsave.\the\macname}{\the\macname}% + \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% + % Add the macroname to \macrolist + \toks0 = \expandafter{\macrolist\do}% + \xdef\macrolist{\the\toks0 + \expandafter\noexpand\csname\the\macname\endcsname}% + \fi + \begingroup \macrobodyctxt + \ifrecursive \expandafter\parsermacbody + \else \expandafter\parsemacbody + \fi} + +\def\unmacro{\parsearg\unmacroxxx} +\def\unmacroxxx#1{% + \if1\csname ismacro.#1\endcsname + \global\cslet{#1}{macsave.#1}% + \global\expandafter\let \csname ismacro.#1\endcsname=0% + % Remove the macro name from \macrolist + \begingroup + \edef\tempa{\expandafter\noexpand\csname#1\endcsname}% + \def\do##1{% + \def\tempb{##1}% + \ifx\tempa\tempb + % remove this + \else + \toks0 = \expandafter{\newmacrolist\do}% + \edef\newmacrolist{\the\toks0\expandafter\noexpand\tempa}% + \fi}% + \def\newmacrolist{}% + % Execute macro list to define \newmacrolist + \macrolist + \global\let\macrolist\newmacrolist + \endgroup + \else + \errmessage{Macro #1 not defined}% + \fi +} + +% This makes use of the obscure feature that if the last token of a +% is #, then the preceding argument is delimited by +% an opening brace, and that opening brace is not consumed. +\def\getargs#1{\getargsxxx#1{}} +\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} +\def\getmacname #1 #2\relax{\macname={#1}} +\def\getmacargs#1{\def\argl{#1}} + +% Parse the optional {params} list. Set up \paramno and \paramlist +% so \defmacro knows what to do. Define \macarg.blah for each blah +% in the params list, to be ##N where N is the position in that list. +% That gets used by \mbodybackslash (above). + +% We need to get `macro parameter char #' into several definitions. +% The technique used is stolen from LaTeX: let \hash be something +% unexpandable, insert that wherever you need a #, and then redefine +% it to # just before using the token list produced. +% +% The same technique is used to protect \eatspaces till just before +% the macro is used. + +\def\parsemargdef#1;{\paramno=0\def\paramlist{}% + \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} +\def\parsemargdefxxx#1,{% + \if#1;\let\next=\relax + \else \let\next=\parsemargdefxxx + \advance\paramno by 1% + \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname + {\xeatspaces{\hash\the\paramno}}% + \edef\paramlist{\paramlist\hash\the\paramno,}% + \fi\next} + +% These two commands read recursive and nonrecursive macro bodies. +% (They're different since rec and nonrec macros end differently.) + +\long\def\parsemacbody#1@end macro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% +\long\def\parsermacbody#1@end rmacro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% + +% This defines the macro itself. There are six cases: recursive and +% nonrecursive macros of zero, one, and many arguments. +% Much magic with \expandafter here. +% \xdef is used so that macro definitions will survive the file +% they're defined in; @include reads the file inside a group. +\def\defmacro{% + \let\hash=##% convert placeholders to macro parameter chars + \ifrecursive + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\scanmacro{\temp}}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup\noexpand\scanmacro{\temp}}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{\egroup\noexpand\scanmacro{\temp}}% + \fi + \else + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \expandafter\noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \fi + \fi} + +\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} + +% \braceorline decides whether the next nonwhitespace character is a +% {. If so it reads up to the closing }, if not, it reads the whole +% line. Whatever was read is then fed to the next control sequence +% as an argument (by \parsebrace or \parsearg) +\def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx} +\def\braceorlinexxx{% + \ifx\nchar\bgroup\else + \expandafter\parsearg + \fi \next} + +% We mant to disable all macros during \shipout so that they are not +% expanded by \write. +\def\turnoffmacros{\begingroup \def\do##1{\let\noexpand##1=\relax}% + \edef\next{\macrolist}\expandafter\endgroup\next} + + +% @alias. +\def\alias#1=#2{\gdef#1{#2}} + + +\message{cross references,} +\newwrite\auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is relatively simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% @node's job is to define \lastnode. +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +% The sectioning commands (@chapter, etc.) call these. +\def\donoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}% + {Ysectionnumberandtype}% + \global\let\lastnode=\relax + \fi +} +\def\unnumbnoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}{Ynothing}% + \global\let\lastnode=\relax + \fi +} +\def\appendixnoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}% + {Yappendixletterandtype}% + \global\let\lastnode=\relax + \fi +} + + +% @anchor{NAME} -- define xref target at arbitrary point. +% +\def\anchor#1{\setref{#1}{Ynothing}} + + +% \setref{NAME}{SNT} defines a cross-reference point NAME, namely +% NAME-title, NAME-pg, and NAME-SNT. Called from \foonoderef. We have +% to set \indexdummies so commands such as @code in a section title +% aren't expanded. It would be nicer not to expand the titles in the +% first place, but there's so many layers that that is hard to do. +% +\def\setref#1#2{{% + \indexdummies + \dosetq{#1-title}{Ytitle}% + \dosetq{#1-pg}{Ypagenumber}% + \dosetq{#1-snt}{#2}% +}} + +% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is +% the node name, #2 the name of the Info cross-reference, #3 the printed +% node name, #4 the name of the Info file, #5 the name of the printed +% manual. All but the node name can be omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \def\printedmanual{\ignorespaces #5}% + \def\printednodename{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual}% + \setbox0=\hbox{\printednodename}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1 > 0pt + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' in \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\normalturnoffactive + % Only output a following space if the -snt ref is nonempty; for + % @unnumbered and @anchor, it won't be. + \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% + \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi + }% + % [mynode], + [\printednodename],\space + % page 3 + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi +\endgroup} + +% \dosetq is the interface for calls from other macros + +% Use \normalturnoffactive so that punctuation chars such as underscore +% and backslash work in node names. (\turnoffactive doesn't do \.) +\def\dosetq#1#2{% + {\let\folio=0 + \normalturnoffactive + \edef\next{\write\auxfile{\internalsetq{#1}{#2}}}% + \iflinks + \next + \fi + }% +} + +% \internalsetq {foo}{page} expands into +% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} +% When the aux file is read, ' is the escape character + +\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + +% Things to be expanded by \internalsetq + +\def\Ypagenumber{\folio} + +\def\Ytitle{\thissection} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\def\Yappendixletterandtype{% +\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\gdef\xreftie{'tie} + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Non-3.0. +\else + \def\linenumber{\the\inputlineno:\space} +\fi + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. + +\def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + \angleleft un\-de\-fined\angleright + \iflinks + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. +} + +% This is the macro invoked by entries in the aux file. +% +\def\xrdef#1{\begingroup + % Reenable \ as an escape while reading the second argument. + \catcode`\\ = 0 + \afterassignment\endgroup + \expandafter\gdef\csname X#1\endcsname +} + +% Read the last existing aux file, if any. No error if none exists. +\def\readauxfile{\begingroup + \catcode`\^^@=\other + \catcode`\^^A=\other + \catcode`\^^B=\other + \catcode`\^^C=\other + \catcode`\^^D=\other + \catcode`\^^E=\other + \catcode`\^^F=\other + \catcode`\^^G=\other + \catcode`\^^H=\other + \catcode`\^^K=\other + \catcode`\^^L=\other + \catcode`\^^N=\other + \catcode`\^^P=\other + \catcode`\^^Q=\other + \catcode`\^^R=\other + \catcode`\^^S=\other + \catcode`\^^T=\other + \catcode`\^^U=\other + \catcode`\^^V=\other + \catcode`\^^W=\other + \catcode`\^^X=\other + \catcode`\^^Z=\other + \catcode`\^^[=\other + \catcode`\^^\=\other + \catcode`\^^]=\other + \catcode`\^^^=\other + \catcode`\^^_=\other + \catcode`\@=\other + \catcode`\^=\other + % It was suggested to define this as 7, which would allow ^^e4 etc. + % in xref tags, i.e., node names. But since ^^e4 notation isn't + % supported in the main text, it doesn't seem desirable. Furthermore, + % that is not enough: for node names that actually contain a ^ + % character, we would end up writing a line like this: 'xrdef {'hat + % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first + % argument, and \hat is not an expandable control sequence. It could + % all be worked out, but why? Either we support ^^ or we don't. + % + % The other change necessary for this was to define \auxhat: + % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter + % and then to call \auxhat in \setq. + % + \catcode`\~=\other + \catcode`\[=\other + \catcode`\]=\other + \catcode`\"=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\$=\other + \catcode`\#=\other + \catcode`\&=\other + \catcode`+=\other % avoid \+ for paranoia even though we've turned it off + % Make the characters 128-255 be printing characters + {% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% + }% + % The aux file uses ' as the escape (for now). + % Turn off \ as an escape so we do not lose on + % entries which were dumped with control sequences in their names. + % For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ + % Reference to such entries still does not work the way one would wish, + % but at least they do not bomb out when the aux file is read in. + \catcode`\{=1 + \catcode`\}=2 + \catcode`\%=\other + \catcode`\'=0 + \catcode`\\=\other + % + \openin 1 \jobname.aux + \ifeof 1 \else + \closein 1 + \input \jobname.aux + \global\havexrefstrue + \global\warnedobstrue + \fi + % Open the new aux file. TeX will close it automatically at exit. + \openout\auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +% Oh yes, they do; otherwise, @ifset and anything else that uses +% \parseargline fail inside footnotes because the tokens are fixed when +% the footnote is read. --karl, 16nov96. +% +\long\gdef\footnotezzz{\insert\footins\bgroup + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + \futurelet\next\fo@t +} +\def\fo@t{\ifcat\bgroup\noexpand\next \let\next\f@@t + \else\let\next\f@t\fi \next} +\def\f@@t{\bgroup\aftergroup\@foot\let\next} +\def\f@t#1{#1\@foot} +\def\@foot{\strut\egroup} + +}%end \catcode `\@=11 + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + +% @image. We use the macros from epsf.tex to support this. +% If epsf.tex is not installed and @image is used, we complain. +% +% Check for and read epsf.tex up front. If we read it only at @image +% time, we might be inside a group, and then its definitions would get +% undone and the next image would fail. +\openin 1 = epsf.tex +\ifeof 1 \else + \closein 1 + % Do not bother showing banner with post-v2.7 epsf.tex (available in + % doc/epsf.tex until it shows up on ctan). + \def\epsfannounce{\toks0 = }% + \input epsf.tex +\fi +% +\newif\ifwarnednoepsf +\newhelp\noepsfhelp{epsf.tex must be installed for images to + work. It is also included in the Texinfo distribution, or you can get + it from ftp://tug.org/tex/epsf.tex.} +% +% Only complain once about lack of epsf.tex. +\def\image#1{% + \ifx\pdfoutput\undefined + \ifx\epsfbox\undefined + \ifwarnednoepsf \else + \errhelp = \noepsfhelp + \errmessage{epsf.tex not found, images will be ignored}% + \global\warnednoepsftrue + \fi + \else + \imagexxx #1,,,\finish + \fi + \else + \centerline{\pdfimage #1.pdf}% + \fi +} +% +% Arguments to @image: +% #1 is (mandatory) image filename; we tack on .eps extension. +% #2 is (optional) width, #3 is (optional) height. +% #4 is just the usual extra ignored arg for parsing this stuff. +\def\imagexxx#1,#2,#3,#4\finish{% + % \epsfbox itself resets \epsf?size at each figure. + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi + \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi + % If the image is by itself, center it. + \ifvmode + \nobreak\medskip + \nobreak + \centerline{\epsfbox{#1.eps}}% + \bigbreak + \else + % In the middle of a paragraph, no extra space. + \epsfbox{#1.eps}% + \fi +} + + +\message{localization,} + +% @documentlanguage is usually given very early, just after +% @setfilename. If done too late, it may not override everything +% properly. Single argument is the language abbreviation. +% It would be nice if we could set up a hyphenation file here. +% +\def\documentlanguage{\parsearg\dodocumentlanguage} +\def\dodocumentlanguage#1{% + \tex % read txi-??.tex file in plain TeX. + % Read the file if it exists. + \openin 1 txi-#1.tex + \ifeof1 + \errhelp = \nolanghelp + \errmessage{Cannot read language file txi-#1.tex}% + \let\temp = \relax + \else + \def\temp{\input txi-#1.tex }% + \fi + \temp + \endgroup +} +\newhelp\nolanghelp{The given language definition file cannot be found or +is empty. Maybe you need to install it? In the current directory +should work if nowhere else does.} + + +% @documentencoding should change something in TeX eventually, most +% likely, but for now just recognize it. +\let\documentencoding = \comment + + +% Page size parameters. +% +\newdimen\defaultparindent \defaultparindent = 15pt + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness = 10000 + +% Don't be so finicky about underfull hboxes, either. +\hbadness = 2000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. We call this whenever the paper size is set. +% +\def\setemergencystretch{% + \ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% + \else + \emergencystretch = \hsize + \divide\emergencystretch by 40 + \fi +} + +% Parameters in order: 1) textheight; 2) textwidth; 3) voffset; +% 4) hoffset; 5) binding offset; 6) topskip. Then whoever calls us can +% set \parskip and call \setleading for \baselineskip. +% +\def\internalpagesizes#1#2#3#4#5#6{% + \voffset = #3\relax + \topskip = #6\relax + \splittopskip = \topskip + % + \vsize = #1\relax + \advance\vsize by \topskip + \outervsize = \vsize + \advance\outervsize by 2\topandbottommargin + \pageheight = \vsize + % + \hsize = #2\relax + \outerhsize = \hsize + \advance\outerhsize by 0.5in + \pagewidth = \hsize + % + \normaloffset = #4\relax + \bindingoffset = #5\relax + % + \parindent = \defaultparindent + \setemergencystretch +} + +% @letterpaper (the default). +\def\letterpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \setleading{13.2pt}% + % + % If page is nothing but text, make it come out even. + \internalpagesizes{46\baselineskip}{6in}{\voffset}{.25in}{\bindingoffset}{36pt}% +}} + +% Use @smallbook to reset parameters for 7x9.5 (or so) format. +\def\smallbook{{\globaldefs = 1 + \parskip = 2pt plus 1pt + \setleading{12pt}% + % + \internalpagesizes{7.5in}{5.in}{\voffset}{.25in}{\bindingoffset}{16pt}% + % + \lispnarrowing = 0.3in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \deftypemargin = 0pt + \defbodyindent = .5cm + % + \let\smalldisplay = \smalldisplayx + \let\smallexample = \smalllispx + \let\smallformat = \smallformatx + \let\smalllisp = \smalllispx +}} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{{\globaldefs = 1 + \setleading{12pt}% + \parskip = 3pt plus 2pt minus 1pt + % + \internalpagesizes{53\baselineskip}{160mm}{\voffset}{4mm}{\bindingoffset}{44pt}% + % + \tolerance = 700 + \hfuzz = 1pt +}} + +% A specific text layout, 24x15cm overall, intended for A4 paper. Top margin +% 29mm, hence bottom margin 28mm, nominal side margin 3cm. +\def\afourlatex{{\globaldefs = 1 + \setleading{13.6pt}% + % + \afourpaper + \internalpagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm}% + % + \globaldefs = 0 +}} + +% Use @afourwide to print on European A4 paper in wide format. +\def\afourwide{% + \afourpaper + \internalpagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}% + % + \globaldefs = 0 +} + +% @pagesizes TEXTHEIGHT[,TEXTWIDTH] +% Perhaps we should allow setting the margins, \topskip, \parskip, +% and/or leading, also. Or perhaps we should compute them somehow. +% +\def\pagesizes{\parsearg\pagesizesxxx} +\def\pagesizesxxx#1{\pagesizesyyy #1,,\finish} +\def\pagesizesyyy#1,#2,#3\finish{{% + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi + \globaldefs = 1 + % + \parskip = 3pt plus 2pt minus 1pt + \setleading{13.2pt}% + % + \internalpagesizes{#1}{\hsize}{\voffset}{\normaloffset}{\bindingoffset}{44pt}% +}} + +% Set default to letter. +% +\letterpaper + +\message{and turning on texinfo input format.} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} + +% This macro is used to make a character print one way in ttfont +% where it can probably just be output, and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt\char34}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt\char126}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}} + +\catcode`\|=\active +\def|{{\tt\char124}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +%\catcode 27=\active +%\def^^[{$\diamondsuit$} + +% Set up an active definition for =, but don't enable it most of the time. +{\catcode`\==\active +\global\def={{\tt \char 61}}} + +\catcode`+=\active +\catcode`\_=\active + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +\catcode`\@=0 + +% \rawbackslashxx output one backslash character in current font +\global\chardef\rawbackslashxx=`\\ +%{\catcode`\\=\other +%@gdef@rawbackslashxx{\}} + +% \rawbackslash redefines \ as input to do \rawbackslashxx. +{\catcode`\\=\active +@gdef@rawbackslash{@let\=@rawbackslashxx }} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\rawbackslashxx}} + +% Say @foo, not \foo, in error messages. +\escapechar=`\@ + +% \catcode 17=0 % Define control-q +\catcode`\\=\active + +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{@let"=@normaldoublequote +@let\=@realbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +@def@normalturnoffactive{@let"=@normaldoublequote +@let\=@normalbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\{ in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also back turn on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active @catcode`@_=@active} + +% These look ok in all fonts, so just make them not special. The @rm below +% makes sure that the current font starts out as the newly loaded cmr10 +@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other + +@textfonts +@rm + +@c Local variables: +@c eval: (add-hook 'write-file-hooks 'time-stamp) +@c page-delimiter: "^\\\\message" +@c time-stamp-start: "def\\\\texinfoversion{" +@c time-stamp-format: "%:y-%02m-%02d.%H" +@c time-stamp-end: "}" +@c End: diff --git a/doc/vtysh.1 b/doc/vtysh.1 new file mode 100644 index 0000000..302e016 --- /dev/null +++ b/doc/vtysh.1 @@ -0,0 +1,68 @@ +.TH VTYSH 1 "July 2000" "Zebra Beast - VTY shell" "Version 0.88" + +.SH NAME +vtysh \- a integrated shell for Zebra routing software + +.SH SYNOPSIS +.B vtysh +[ +.B \-e command +] + +.SH DESCBGPTION +.B vtysh +is a integrated shell for +.B Zebra +routing engine. + + +.SH OPTIONS + +.TP +\fB\-e +Specify command to be executed under batch mode. + + +.SH COMMANDS + +\fB Almost Zebra commands. + +\fB ping +\fB traceroute +\fB telnnet + +\fB start-shell +\fB start-shell bash +\fB start-shell zsh + + +.SH FILES + +.TP +.BI /usr/local/etc/Zebra.conf +The default location of the +.B vtysh +config file. + + +.SH WARNING +This man page is intended as a quick reference for command line +options, and for config file commands. The definitive document is the +Info file \fBZebra\fR. + + +.SH "SEE ALSO" +References to other related man pages: + +bgpd(8), ripd(8), ripngd(8), ospfd(8), ospf6d(8), zebra(8) + + +.SH BUGS +.B vtysh +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. + diff --git a/doc/vtysh.texi b/doc/vtysh.texi new file mode 100644 index 0000000..72490db --- /dev/null +++ b/doc/vtysh.texi @@ -0,0 +1,27 @@ +@node VTY shell +@comment node-name, next, previous, up +@chapter VTY shell + +@command{vtysh} is integrated shell of Zebra software. + +To use vtysh please specify ---enable-vtysh to configure script. To use +PAM for authentication use ---with-libpam option to configure script. + +vtysh only searches @value{INSTALL_PREFIX_ETC} path for vtysh.conf which +is the vtysh configuration file. Vtysh does not search current +directory for configuration file because the file includes user +authentication settings. + +Currently, vtysh.conf has only one command. + +@example +! +username foo nopassword +! +@end example + +With this set, user foo does not need password authentication for user vtysh. +With PAM vtysh uses PAM authentication mechanism. + +If vtysh is compiled without PAM authentication, every user can use vtysh +without authentication. diff --git a/doc/zebra.8 b/doc/zebra.8 new file mode 100644 index 0000000..190f4a6 --- /dev/null +++ b/doc/zebra.8 @@ -0,0 +1,146 @@ +.TH ZEBRA 8 "July 2000" "Zebra" "Version 0.88" + +.SH NAME +zebra \- a routing manager for use with associated components + +.SH SYNOPSIS +.B zebra +[ +.B \-bdhklrv +] +[ +.B \-f config-file +] +[ +.B \-i pid-file +] +[ +.B \-P port-number +] + +.SH DESCRIPTION +.B zebra +is a routing manager that implements the +.B zebra +route engine. +.B zebra +supports RIPv1, RIPv2, RIPng, OSPF, OSPF6, BGP4+, and BGP4-. + + +.SH OPTIONS + +.TP +\fB\-b\fR, \fB\-\-batch\fR +Runs in batch mode, \fBzebra\fR parses its config and exits. + +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. + +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/zebra.conf\fR. + +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. + +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When zebra starts its process idenifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart zebra. The likely default is \fB\fI/var/run/zebra.pid\fR. + +.TP +\fB\-k\fR, \fB\-\-keep_kernel\fR +On startup, don't delete self inserted routes. + +.TP +\fB\-l\fR, \fB\-\-log_mode\fR +Turn verbose logging on. + +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the zebra VTY will listen on. This defaults to +2602, as specified in \fB\fI/etc/services\fR. + +.TP +\fB\-r\fR, \fB\-\-retain\fR +When the program terminates, retain routes added by \fBzebra\fR. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. + + +.SH COMMANDS + +\fB table [TABLENO] \fR -- for use with multi-table kernels + +\fB ip route [NETWORK] [GATEWAY] \fR +\fB ipv6 route [NETWORK] [GATEWAY] \fR + +\fB show ip route \fR +\fB show ipv6 route \fR +\fB show interface \fR +\fB show ipforward \fR +\fB show ipv6forward \fR + +.TP +\fB interface [IFNAME] \fR +\fB shutdown \fR +\fB no shutdown \fR +\fB ip address [IP-ADDRESS] \fR +\fB description [DESCRIPTION] \fR +\fB multicast \fR +\fB no multicast \fR + + +.SH FILES + +.TP +.BI /usr/local/sbin/zebra +The default location of the +.B zebra +binary. + +.TP +.BI /usr/local/etc/zebra.conf +The default location of the +.B zebra +config file. + +.TP +.BI $(PWD)/zebra.log +If the +.B zebra +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBzebra\fR. + + +.SH WARNING +This man page is intended as a quick reference for command line options, and for config file commands. The definitive document is the Info file \fBzebra\fR. + + +.SH DIAGNOSTICS +The zebra process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. +.B zebra +supports many debugging options, see the Info file, or the source for details. + + +.SH "SEE ALSO" +References to other related man pages: + +ripngd(8), ospfd(8), ospf6d(8), bgpd(8), zebra(8), vtysh(1) + + + +.SH BUGS +.B zebra +eats bugs for breakfast. If you have food for the maintainers try +.BI + + +.SH AUTHOR[S] +See <\fBwww.zebra.org\fR>, or the Info file for an accurate list of authors. + diff --git a/doc/zebra.info b/doc/zebra.info new file mode 100644 index 0000000..7245ae2 --- /dev/null +++ b/doc/zebra.info @@ -0,0 +1,170 @@ +This is zebra.info, produced by makeinfo version 4.2 from zebra.texi. + +INFO-DIR-SECTION Routing Software: +START-INFO-DIR-ENTRY +* Zebra: (zebra). The GNU Zebra routing software +END-INFO-DIR-ENTRY + + This file documents the GNU Zebra software which manages common +TCP/IP routing protocols. + + This is Edition 0.3, last updated 1 March 2004 of `The GNU Zebra +Manual', for Zebra Version 0.95. + + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Kunihiro Ishiguro + + Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be stated in a +translation approved by Kunihiro Ishiguro. + + +Indirect: +zebra.info-1: 1127 +zebra.info-2: 49231 +zebra.info-3: 97058 +zebra.info-4: 145340 + +Tag Table: +(Indirect) +Node: Top1127 +Node: Overview1662 +Node: About Zebra3167 +Node: System Architecture5440 +Node: Supported Platforms8847 +Node: Supported RFC9738 +Node: How to get Zebra11540 +Node: Mailing List12245 +Node: Bug Reports12905 +Node: Installation13750 +Node: Configure the Software14181 +Ref: Configure the Software-Footnote-116548 +Node: Build the Software18190 +Node: Install the Software18732 +Node: Basic commands20103 +Node: Config Commands20816 +Node: Basic Config Commands21698 +Node: Sample Config File24096 +Node: Common Invocation Options24856 +Node: Virtual Terminal Interfaces25978 +Node: VTY Overview26483 +Node: VTY Modes27766 +Node: VTY View Mode28206 +Node: VTY Enable Mode28460 +Node: VTY Other Modes28724 +Node: VTY CLI Commands28886 +Node: CLI Movement Commands29336 +Node: CLI Editing Commands29869 +Node: CLI Advanced Commands30442 +Node: Zebra31193 +Node: Invoking zebra31700 +Node: Interface Commands32286 +Node: Static Route Commands33116 +Node: zebra Terminal Mode Commands35203 +Node: RIP36164 +Node: Starting and Stopping ripd37099 +Node: RIP netmask38520 +Node: RIP Configuration39642 +Node: How to Announce RIP route43537 +Node: Filtering RIP Routes46066 +Node: RIP Metric Manipulation47525 +Node: RIP distance48428 +Node: RIP route-map49231 +Node: RIP Authentication51733 +Node: RIP Timers52823 +Node: Show RIP Information54098 +Node: RIP Debug Commands55461 +Node: RIPng56445 +Node: Invoking ripngd56763 +Node: ripngd Configuration57020 +Node: ripngd Terminal Mode Commands57759 +Node: ripngd Filtering Commands58109 +Node: OSPFv258608 +Node: Configuring ospfd59165 +Node: OSPF router59642 +Node: OSPF area62437 +Node: OSPF interface64651 +Node: Redistribute routes to OSPF67433 +Node: Showing OSPF information69549 +Node: Debugging OSPF70769 +Node: OSPFv371780 +Node: OSPF6 router72098 +Node: OSPF6 area72455 +Node: OSPF6 interface72627 +Node: Redistribute routes to OSPF673479 +Node: Showing OSPF6 information73783 +Node: BGP74588 +Node: Starting BGP75449 +Node: BGP router76034 +Node: BGP distance77270 +Node: BGP decision process77711 +Node: BGP network77967 +Node: BGP route78148 +Node: Route Aggregation78709 +Node: Redistribute to BGP79261 +Node: BGP Peer79770 +Node: Defining Peer79948 +Node: BGP Peer commands80564 +Node: Peer filtering82935 +Node: BGP Peer Group83426 +Node: BGP Address Family83728 +Node: Autonomous System83873 +Node: AS Path Regular Expression84704 +Node: Display BGP Routes by AS Path85967 +Node: AS Path Access List86396 +Node: Using AS Path in Route Map86850 +Node: Private AS Numbers87116 +Node: BGP Communities Attribute87261 +Node: BGP Community Lists89722 +Node: Numbered BGP Community Lists92403 +Node: BGP Community in Route Map93977 +Node: Display BGP Routes by Community95904 +Node: Using BGP Communities Attribute97058 +Node: BGP Extended Communities Attribute100616 +Node: BGP Extended Community Lists102382 +Node: BGP Extended Communities in Route Map104283 +Node: Displaying BGP routes104726 +Node: Show IP BGP104952 +Node: More Show IP BGP105674 +Node: Capability Negotiation106794 +Node: Route Reflector110082 +Node: Route Server110347 +Node: Multiple instance111405 +Node: BGP instance and view113218 +Node: Routing policy114584 +Node: Viewing the view115340 +Node: How to set up a 6-Bone connection115612 +Node: Dump BGP packets and table116984 +Node: VTY shell117514 +Node: Filtering118354 +Node: IP Access List118702 +Node: IP Prefix List119093 +Node: ip prefix-list description122262 +Node: ip prefix-list sequential number control122795 +Node: Showing ip prefix-list123320 +Node: Clear counter of ip prefix-list124403 +Node: Route Map124824 +Node: Route Map Command125325 +Node: Route Map Match Command125528 +Node: Route Map Set Command126136 +Node: IPv6 Support126994 +Node: Router Advertisement127559 +Node: Kernel Interface127890 +Node: SNMP Support129840 +Node: How to get net-snmp130469 +Node: SMUX configuration131446 +Node: Zebra Protocol131879 +Node: Packet Binary Dump Format133773 +Node: Command Index145340 +Node: VTY Key Index175058 + +End Tag Table diff --git a/doc/zebra.texi b/doc/zebra.texi new file mode 100644 index 0000000..c93937c --- /dev/null +++ b/doc/zebra.texi @@ -0,0 +1,150 @@ +\input texinfo @c -*- texinfo -*- +@c %**start of header +@setchapternewpage odd +@settitle GNU Zebra +@setfilename zebra.info +@defcodeindex op +@synindex pg cp +@c %**end of header + +@c Set variables +@set EDITION 0.3 +@set VERSION 0.95 +@set UPDATED 1 March 2004 +@set UPDATED-MONTH March 2004 + +@c These may vary with installation environment. +@set INSTALL_PREFIX_ETC /usr/local/etc +@set INSTALL_PREFIX_SBIN /usr/local/sbin + +@c Info entry +@dircategory Routing Software: +@direntry +* Zebra: (zebra). The @sc{gnu} Zebra routing software +@end direntry + +@c @smallbook + +@ifinfo +This file documents the @sc{gnu} Zebra software which manages common +TCP/IP routing protocols. + +This is Edition @value{EDITION}, last updated @value{UPDATED} of +@cite{The GNU Zebra Manual}, for Zebra Version @value{VERSION}. + +Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Kunihiro Ishiguro + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries a copyright permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by Kunihiro Ishiguro. +@end ifinfo + +@titlepage +@title GNU Zebra +@subtitle A routing software package for TCP/IP networks +@subtitle Zebra version @value{VERSION} +@subtitle @value{UPDATED-MONTH} +@author Kunihiro Ishiguro + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1999, 2000, 2001, 2002, 2003, 2004 Kunihiro Ishiguro + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by Kunihiro Ishiguro. +@end titlepage +@page + +@ifnottex +@node Top, Overview, (dir), (dir) +@comment node-name, next, previous, up +@top Zebra + +Zebra is the advanced TCP/IP routing software. This Info file +describes how to install and use it. This manual coressponds to GNU +Zebra @value{VERSION}. +@end ifnottex + +@menu +* Overview:: +* Installation:: +* Basic commands:: +* Zebra:: +* RIP:: +* RIPng:: +* OSPFv2:: +* OSPFv3:: +* BGP:: +* VTY shell:: +* Filtering:: +* Route Map:: +* IPv6 Support:: +* Kernel Interface:: +* SNMP Support:: +* Zebra Protocol:: +* Packet Binary Dump Format:: +* Command Index:: +* VTY Key Index:: +@end menu + +@include overview.texi +@include install.texi +@include basic.texi +@include main.texi +@include ripd.texi +@include ripngd.texi +@include ospfd.texi +@include ospf6d.texi +@include bgpd.texi +@include vtysh.texi +@include filter.texi +@include routemap.texi +@include ipv6.texi +@include kernel.texi +@include snmp.texi +@include protocol.texi +@include appendix.texi + +@node Command Index, VTY Key Index, Top, Top +@comment node-name, next, previous, up +@unnumbered Command Index + +@printindex fn + +@node VTY Key Index, , Command Index, Top +@comment node-name, next, previous, up +@unnumbered VTY Key Index + +@printindex ky + +@summarycontents +@contents +@bye diff --git a/init/redhat/bgpd.init b/init/redhat/bgpd.init new file mode 100644 index 0000000..91d2aeb --- /dev/null +++ b/init/redhat/bgpd.init @@ -0,0 +1,45 @@ +#!/bin/bash +# +# chkconfig: - 16 84 +# description: A BGPv4, BGPv4+, BGPv4- routing engine for use with Zebra +# +# processname: bgpd +# config: /etc/bgpd.conf + +# source function library +. /etc/rc.d/init.d/functions + +RETVAL=0 + +[ -f /etc/bgpd.conf ] || exit 0 + +case "$1" in + start) + echo -n "Starting bgpd: " + daemon /usr/sbin/bgpd -d + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/bgpd + echo + ;; + stop) + echo -n "Shutting down bgpd: " + killproc bgpd + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/bgpd + echo + ;; + restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status bgpd + RETVAL=$? + ;; + *) + echo "Usage: bgpd {start|stop|restart|status}" + exit 1 +esac + +exit $RETVAL diff --git a/init/redhat/ospf6d.init b/init/redhat/ospf6d.init new file mode 100644 index 0000000..4d89f8a --- /dev/null +++ b/init/redhat/ospf6d.init @@ -0,0 +1,45 @@ +#!/bin/bash +# +# chkconfig: - 16 84 +# description: An OSPF routing engine for use with Zebra and IPv6 +# +# processname: ospf6d +# config: /etc/ospf6d.conf + +# source function library +. /etc/rc.d/init.d/functions + +RETVAL=0 + +[ -f /etc/ospf6d.conf ] || exit 0 + +case "$1" in + start) + echo -n "Starting ospf6d: " + daemon /usr/sbin/ospf6d -d + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ospf6d + echo + ;; + stop) + echo -n "Shutting down ospf6d: " + killproc ospf6d + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ospf6d + echo + ;; + restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status ospf6d + RETVAL=$? + ;; + *) + echo "Usage: ospf6d {start|stop|restart|status}" + exit 1 +esac + +exit $RETVAL diff --git a/init/redhat/ospfd.init b/init/redhat/ospfd.init new file mode 100644 index 0000000..d7453b6 --- /dev/null +++ b/init/redhat/ospfd.init @@ -0,0 +1,45 @@ +#!/bin/bash +# +# chkconfig: - 16 84 +# description: An OSPF v2 routing engine for use with Zebra +# +# processname: ospfd +# config: /etc/ospfd.conf + +# source function library +. /etc/rc.d/init.d/functions + +RETVAL=0 + +[ -f /etc/ospfd.conf ] || exit 0 + +case "$1" in + start) + echo -n "Starting ospfd: " + daemon /usr/sbin/ospfd -d + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ospfd + echo + ;; + stop) + echo -n "Shutting down ospfd: " + killproc ospfd + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ospfd + echo + ;; + restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status ospfd + RETVAL=$? + ;; + *) + echo "Usage: ospfd {start|stop|restart|status}" + exit 1 +esac + +exit $RETVAL diff --git a/init/redhat/ripd.init b/init/redhat/ripd.init new file mode 100644 index 0000000..d87f498 --- /dev/null +++ b/init/redhat/ripd.init @@ -0,0 +1,45 @@ +#!/bin/bash +# +# chkconfig: - 16 84 +# description: A RIP routing engine for use with Zebra +# +# processname: ripd +# config: /etc/ripd.conf + +# source function library +. /etc/rc.d/init.d/functions + +RETVAL=0 + +[ -f /etc/ripd.conf ] || exit 0 + +case "$1" in + start) + echo -n "Starting ripd: " + daemon /usr/sbin/ripd -d + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ripd + echo + ;; + stop) + echo -n "Shutting down ripd: " + killproc ripd + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ripd + echo + ;; + restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status ripd + RETVAL=$? + ;; + *) + echo "Usage: ripd {start|stop|restart|status}" + exit 1 +esac + +exit $RETVAL diff --git a/init/redhat/ripngd.init b/init/redhat/ripngd.init new file mode 100644 index 0000000..26c153b --- /dev/null +++ b/init/redhat/ripngd.init @@ -0,0 +1,45 @@ +#!/bin/bash +# +# chkconfig: - 16 84 +# description: A RIP routing engine for use with Zebra and IPv6 +# +# processname: ripngd +# config: /etc/ripngd.conf + +# source function library +. /etc/rc.d/init.d/functions + +RETVAL=0 + +[ -f /etc/ripngd.conf ] || exit 0 + +case "$1" in + start) + echo -n "Starting ripngd: " + daemon /usr/sbin/ripngd -d + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ripngd + echo + ;; + stop) + echo -n "Shutting down ripngd: " + killproc ripngd + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ripngd + echo + ;; + restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status ripngd + RETVAL=$? + ;; + *) + echo "Usage: ripngd {start|stop|restart|status}" + exit 1 +esac + +exit $RETVAL diff --git a/init/redhat/zebra.init b/init/redhat/zebra.init new file mode 100644 index 0000000..b09918a --- /dev/null +++ b/init/redhat/zebra.init @@ -0,0 +1,45 @@ +#!/bin/bash +# +# chkconfig: - 15 85 +# description: GNU Zebra routing manager +# +# processname: zebra +# config: /etc/zebra.conf + +# source function library +. /etc/rc.d/init.d/functions + +RETVAL=0 + +[ -f /etc/zebra.conf ] || exit 0 + +case "$1" in + start) + echo -n "Starting zebra: " + daemon /usr/sbin/zebra -d + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/zebra + echo + ;; + stop) + echo -n "Shutting down zebra: " + killproc zebra + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/zebra + echo + ;; + restart) + $0 stop + $0 start + RETVAL=$? + ;; + status) + status zebra + RETVAL=$? + ;; + *) + echo "Usage: zebra {start|stop|restart|status}" + exit 1 +esac + +exit $RETVAL diff --git a/init/redhat/zebra.logrotate b/init/redhat/zebra.logrotate new file mode 100644 index 0000000..0d13baf --- /dev/null +++ b/init/redhat/zebra.logrotate @@ -0,0 +1,47 @@ +/var/log/zebra/zebra.log { + notifempty + missingok + postrotate + /usr/bin/killall -USR1 zebra + endscript +} + +/var/log/zebra/bgpd.log { + notifempty + missingok + postrotate + /usr/bin/killall -USR1 bgpd + endscript +} + +/var/log/zebra/ospf.log { + notifempty + missingok + postrotate + /usr/bin/killall -USR1 ospfd + endscript +} + +/var/log/zebra/ospf6.log { + notifempty + missingok + postrotate + /usr/bin/killall -USR1 ospf6d + endscript +} + +/var/log/zebra/rip.log { + notifempty + missingok + postrotate + /usr/bin/killall -USR1 ripd + endscript +} + +/var/log/zebra/ripng.log { + notifempty + missingok + postrotate + /usr/bin/killall -USR1 ripng + endscript +} diff --git a/init/redhat/zebra.spec.in b/init/redhat/zebra.spec.in new file mode 100644 index 0000000..e517a46 --- /dev/null +++ b/init/redhat/zebra.spec.in @@ -0,0 +1,128 @@ +%define version @VERSION@ + +Summary: Zebra routing engine +Name: zebra +Version: %{version} +Release: 1 +Source: zebra-%{version}.tar.gz +URL: http://www.zebra.org +Copyright: GPL +Group: System Environment/Daemons +BuildRoot: /tmp/zebra-%{version}-root + +%description +GNU Zebra is free software (distributed under GNU Generic Public License) +that manages TCP/IP based routing protocols. It supports BGP-4 protocol as +described in RFC1771 (A Border Gateway Protocol 4) as well as RIPv1, RIPv2 +and OSPFv2. Unlike traditional, Gated based, monolithic architectures and +even the so-called "new modular architectures" that remove the burden of +processing routing functions from the cpu and utilize special ASIC chips +instead, Zebra software offers true modularity. + +%prep +%setup + +%build +#./configure --enable-snmp --prefix=/usr --sysconfdir=/etc +./configure --prefix=/usr --sysconfdir=/etc +make + +%install +rm -rf $RPM_BUILD_ROOT +make DESTDIR=$RPM_BUILD_ROOT install +rm -f $RPM_BUILD_ROOT/usr/info/dir +rm -f $RPM_BUILD_ROOT/usr/man/man8/ospf6* +rm -f $RPM_BUILD_ROOT/usr/man/man8/ripng* +rm -f $RPM_BUILD_ROOT/usr/sbin/ospf6d +rm -f $RPM_BUILD_ROOT/usr/sbin/ripngd +strip $RPM_BUILD_ROOT/usr/sbin/* + +mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d +install -m755 init/redhat/bgpd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/bgpd +#install -m755 init/redhat/ospf6d.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ospf6d +install -m755 init/redhat/ospfd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ospfd +install -m755 init/redhat/ripd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ripd +#install -m755 init/redhat/ripngd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ripngd +install -m755 init/redhat/zebra.init $RPM_BUILD_ROOT/etc/rc.d/init.d/zebra + +mkdir -p $RPM_BUILD_ROOT/etc/logrotate.d +install -m644 init/redhat/zebra.logrotate $RPM_BUILD_ROOT/etc/logrotate.d/zebra + + +%post +# zebra_spec_add_service +# e.g. zebra_spec_add_service zebrasrv 2600/tcp "zebra service" + +zebra_spec_add_service () +{ + # Add port /etc/services entry if it isn't already there + if [ -f /etc/services ] && ! grep -q "^$1[^a-zA-Z0-9]" /etc/services ; then + echo "$1 $2 # $3" >> /etc/services + fi +} + +zebra_spec_add_service zebrasrv 2600/tcp "zebra service" +zebra_spec_add_service zebra 2601/tcp "zebra vty" +zebra_spec_add_service ripd 2602/tcp "RIPd vty" +zebra_spec_add_service ripngd 2603/tcp "RIPngd vty" +zebra_spec_add_service ospfd 2604/tcp "OSPFd vty" +zebra_spec_add_service bgpd 2605/tcp "BGPd vty" +zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty" + +#Install info +/sbin/install-info /usr/info/zebra.info /usr/info/dir + +if [ -x /sbin/chkconfig ]; then + chkconfig --add bgpd +# chkconfig --add ospf6d + chkconfig --add ospfd + chkconfig --add ripd +# chkconfig --add ripngd + chkconfig --add zebra +fi + + +%preun +if [ "$1" = 0 ] ; then + /sbin/install-info --delete /usr/info/zebra.info /usr/info/dir + + if [ -x /sbin/chkconfig ]; then + chkconfig --del bgpd +# chkconfig --del ospf6d + chkconfig --del ospfd + chkconfig --del ripd +# chkconfig --del ripngd + chkconfig --del zebra + fi +fi + +%clean +rm -rf $RPM_BUILD_ROOT +rm -rf $RPM_BUILD_DIR/%{name}-%{version} + +%files +%attr(-,root,root) %doc AUTHORS COPYING ChangeLog INSTALL NEWS README SERVICES TODO bgpd/bgpd.conf.sample ospfd/ospfd.conf.sample ripd/ripd.conf.sample zebra/zebra.conf.sample +%attr(-,root,root) %config /etc/rc.d/init.d/* +%attr(-,root,root) %config /etc/logrotate.d/* +%attr(-,root,root) /usr/info/* +#%attr(-,root,root) /usr/man/* # Not man1 to exclude vtysh man page as + # it is not build by default (for now) +%attr(-,root,root) /usr/man/man8/* +%attr(-,root,root) /usr/sbin/* + +%changelog +* Mon Nov 6 2000 Lennert Buytenhek +- Don't include ospf6d and ripngd in package. +- Fix logrotate file (add ospf.log). +* Mon Oct 2 2000 Horms +- Install and uninstall info in %post and %preun respectively +- Moved chkconfig --del operations from %postun to %preun, as + chkconfig needs to run while the init files are still present on + the system. +- Don't install vtysh man page as vtysh is not build by default +- Added logrotate script so logs won't grow without bound +* Wed Sep 27 2000 Horms +- Add ports to /etc/services if they aren't there +- forcibly remove $RPM_BUILD_ROOT/usr/info/dir and friends so + there is no error if it does not exist when rm is run. +- Clean up the zebra build dir diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..398a88e --- /dev/null +++ b/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + : +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=$mkdirprog + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + : + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + : + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + : + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' + ' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + : + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + : + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/lib/ChangeLog b/lib/ChangeLog new file mode 100644 index 0000000..261090c --- /dev/null +++ b/lib/ChangeLog @@ -0,0 +1,1953 @@ +2004-12-11 Yasuhiro Ohara + + * vty.c: moreline problem is fixed. + +2004-05-17 Akihiro Mizutani + + * routemap.c: Add "continue" commands. + Add "show route-map" commands. + +2004-05-06 Akihiro Mizutani + + * command.c: Fix password disappear problem. + +2003-10-21 Kunihiro Ishiguro + + * vty.c: Change buffer handling to prevent DoS attack. Reported + by Jay Fenlason CAN-2003-0795. + +2003-08-20 Yasuhiro Ohara + + * command.c: Fix display problem for command line + description. + +2003-08-07 Kunihiro Ishiguro + + * vty.c (vty_serv_sock_addrinfo): Check HAVE_GETADDRINFO. + +2002-09-28 Yasuhiro Ohara + + * vty.c (vty_flush): One line more on vty. + +2002-09-27 Kunihiro Ishiguro + + * vector.c (vector_lookup): Add new function. + +2002-08-19 Kunihiro Ishiguro + + * thread.c (timeval_adjust): Fix unconditional crush due to + FreeBSD's select() system call timeval value check. + +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2002-06-21 Kunihiro Ishiguro + + * if.c (ifc_pointopoint): Add ifc_pointopoint() accoding to Frank + van Maarseveen's suggestion. + +2002-06-18 Kunihiro Ishiguro + + * command.c: Change bcopy() to memcpy(). + +2001-12-12 Kunihiro Ishiguro + + * command.c (config_password): Fix host.password clear bug. + Reported by Wang Jian . + +2001-08-29 Kunihiro Ishiguro + + * thread.c (thread_should_yield): New function to check thread + should yeild it's execution to other thread. Suggested by: Rick + Payne + +2001-08-20 Kunihiro Ishiguro + + * thread.c (thread_timer_cmp): Rewrite function. + + * hash.c: Add hash_get(). Change hash_pull() to hash_release(). + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-12 Akihiro Mizutani + + * prefix.c (netmask_str2prefix_str): Convert "1.1.0.0 255.255.0.0" + string to "1.1.0.0/16". + +2001-08-10 Kunihiro Ishiguro + + * filter.c (access_list_lookup): access_list_lookup's first + argument is changed from address family to AFI. + + * plist.c: (prefix_list_lookup): Likewise. + +2001-07-27 Akihiro Mizutani + + * plist.c: ge and le display order is changed. Old compatible + rule (len <= ge-value <= le-value) is removed. + +2001-07-08 Kunihiro Ishiguro + + * prefix.h: Temporary fix for alignment of prefix problem. + +2001-06-21 Kunihiro Ishiguro + + * prefix.h (struct prefix): Remove safi and padding field. + (struct prefix_ipv4): Likewise. + (struct prefix_ipv6): Likewise. + (struct prefix_ls): Likewise. + (struct prefix_rd): Likewise. + + * command.h (enum node_type): Preparation for BGP new config. + + * vty.c (vty_end_config): Likewise. + +2001-06-17 Kunihiro Ishiguro + + * routemap.c (route_map_rule_delete): Call func_free when + route-map rule is deleted. + +2001-06-14 "Akihiro Mizutani" + + * routemap.c (route_map_index_lookup): Prevent to use deny and + permit for same route-map sequence. + +2001-04-12 Kunihiro Ishiguro + + * vty.c (vty_read_config): Fix warning. + +2001-03-08 Kunihiro Ishiguro + + * command.c (IPV6_PREFIX_STR): Add '.' and '%' for IPv6 address + strings. + +2001-03-07 Kunihiro Ishiguro + + * zebra.h (_XPG4_2): Define _XPG4_2 and __EXTENSIONS__ for + CMSG_FIRSTHDR. + +2001-03-07 Michael Rozhavsky + + * zebra.h (struct in_pktinfo): structure in_pktinfo declaration. + +2001-02-19 Kunihiro Ishiguro + + * memory.c (memory_list_lib): Add MTYPE_NEXTHOP for "show memory + lib" member. + +2001-02-13 Matthew Grant + + * vty.c (vty_read_config): Revert check of integrate_default when + VTYSH is defined. + +2001-02-13 Kunihiro Ishiguro + + * vty.c (vty_read_config): Do not check integrate_default. That + should be used only by vtysh. + +2001-02-08 Matthew Grant + + * vty.c (vty_serv_un): Set umask 0077. + (vty_read_config): Stat for vtysh Zebra.conf, if found startup and + wait for boot configuration. + + * if.c (if_lookup_address): Make it smart implementation. + + * sockopt.c (setsockopt_multicast_ipv4): Set up a multicast socket + options for IPv4 This is here so that people only have to do their + OS multicast mess in one place rather than all through zebra, + ospfd, and ripd . + +2001-02-04 Akihiro Mizutani + + * plist.c (vty_prefix_list_install): Even when argument is + invalid, new memory is allocated. Now memory allocation is done + after argument check. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-31 Akihiro Mizutani + + * vty.c (vty_login): Add vty login command. + +2001-01-31 Kunihiro Ishiguro + + * vty.c (vty_reset): Close accept socket. + +2001-01-30 Kunihiro Ishiguro + + * memory.h (enum): MTYPE_ATTR_TRANSIT is added for unknown transit + attribute. + +2001-01-22 Kunihiro Ishiguro + + * zclient.c (zebra_interface_address_add_read): Fetch interface + address flag. + (zebra_interface_address_delete_read): Likewise. + +2001-01-16 Kunihiro Ishiguro + + * table.c (route_node_match_ipv4): Utility function for IPv4 + address lookup. + (route_node_match_ipv6): Utility function for IPv4 address lookup. + +2001-01-15 Kunihiro Ishiguro + + * if.c: Delete RIP_API part until new implementation comes out. + +2001-01-13 Kunihiro Ishiguro + + * hash.h (struct Hash): Rename alloc to count. Change type to + unsigned long. + + * stream.c (stream_getc_from): New function. + (stream_getw_from): Likewise. + + * zebra.h (ZEBRA_FLAG_STATIC): Add new flag for persistent route. + +2001-01-11 Kunihiro Ishiguro + + * flap.c: File is removed. + + * flap.c: Likewise. + + * roken.h: Likewise. + + * buffer.c (buffer_new): Remove type option to buffer_new(). + +2001-01-10 Kunihiro Ishiguro + + * zclient.c (zapi_ipv4_delete): Remove OLD_RIB part. + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + + * command.c: Update Copyright year. + +2001-01-09 Matthew Grant + + * if.c (if_create): Register connected_free() function for + deletion. + (if_delete): Free connected information when the interface is + deleted. + (if_lookup_by_index): Fix argument type from int to unsigned int. + (connected_add): Keep list in order if old info found, essential + for repeatable operation in some daemons. + +2001-01-09 endo@suri.co.jp (Masahiko Endo) + + * vty.c (vty_flush): When vty->statis is VTY_CLOSE do not add vty + read thread. + +2001-01-08 Kunihiro Ishiguro + + * filter.c (access_list_delete): Access-list name is not freed. + + * plist.c (prefix_list_delete): Prefix-list name is not freed. + +2000-12-29 Kunihiro Ishiguro + + * zclient.c (zclient_start): Change to use UNIX domain + socket for zebra communication. + + * vector.c (vector_init): vector_alloc and vector_data_alloc is + removed. All memory allocation count should be maintained by + XMALLOC and XFREE macros. + +2000-12-28 Kunihiro Ishiguro + + * zebra.h (ZEBRA_NEXTHOP_IFINDEX): Define ZEBRA_NEXTHOP_* values. + +2000-12-27 Kunihiro Ishiguro + + * zebra.h (ZEBRA_ERR_RTEXIST): Make zebra error code to negative + value. + +2000-12-25 "Wataru Uno" + + * vty.c (vtysh_read): Don't allocate new buffer because buffer is + allocated in vty_new (). + +2000-12-14 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_AS_FILTER_STR. + + * command.c (config_write_terminal): Display "end" at the end of + configuration. + + * plist.c (vty_prefix_list_install): Use AF_INET to determine + lenum length. + +2000-12-13 "Wataru Uno" + + * buffer.c (buffer_flush_vty): If IOV_MAX defined in the System, + then all lines write by IOV_MAX. + +2000-12-12 Michael Rozhavsky + + * command.c (config_write_file): Robust method for writing + configuration file and recover from backing up config file. + +2000-11-29 Kunihiro Ishiguro + + * smux.c (smux_connect): More fail check. + (smux_trap): When SMUX connection is not established, do nothing. + +2000-11-28 Gleb Natapov + + * thread.c (thread_fetch): Execut event list first. Old event + list is renamed to ready list. With this change, event thread is + executed before any other thread. + + * thread.h (struct thread_master): Add ready list. + +2000-11-28 Kunihiro Ishiguro + + * linklist.c (listnode_add_after): Add node right after the + listnode pointer. + +2000-11-27 Kunihiro Ishiguro + + * smux.h: Pass struct variable to WriteMethod. + +2000-11-25 Frank van Maarseveen + + * if.c (if_lookup_address): When looking up interface with IP + address, Sometimes multiple interfaces will match. Now PtP + interfaces prevail in such a case which seem the right thing to + do: There will probably also be host routes which usually prevail + over network routes. + +2000-11-25 Kunihiro Ishiguro + + * smux.c (smux_trap): SMUX trap implementation. + +2000-11-19 Akihiro Mizutani + + * plist.c: Add automatic conversion function of an old rule. + ex.) 10.0.0.0/8 ge 8 -> 10.0.0.0/8 le 32 + +2000-11-16 Yon Uriarte + + * zclient.c (zebra_interface_add_read): Read hardware address when + hw_addr_len is greater than 0. + +2000-11-15 Akihiro Mizutani + + * plist.c: The rule of "len <= ge-value <= le-value" + was changed to "len < ge-value <= le-value". + +2000-11-09 Yasuhiro Ohara + + * memory.[ch]: Added #define and functions for ospf6d. + + * log.[ch]: some platform says that the data of used va_list + is undefined. Changed to hold list of va_list for each + vsnprintf. + +2000-11-07 Rick Payne + + * memory.h (enum): Add MTYPE_COMMUNITY_REGEXP. + +2000-11-06 Kunihiro Ishiguro + + * command.c (config_exit): Fix bug of missing break after case + BGP_VPNV4_NODE. + +2000-10-30 Kunihiro Ishiguro + + * vector.c (vector_unset): Check i is not nevative. + +2000-10-24 Arkadiusz Miskiewicz + + * smux.c (smux_sock): Set terminating '\0'. Check address family. + + * vty.c (vty_serv_sock_addrinfo): Set terminating '\0'. Use + gai_strerror. Check address family. + +2000-10-23 Jochen Friedrich + + * smux.c: Use linklist rather than vector. + (smux_getnext): A SMUX subagent has to behave as if it manages the + whole SNMP MIB tree itself. It's the duty of the master agent to + collect the best answer and return it to the manager. See RFC 1227 + chapter 3.1.6 for the glory details :-). ucd-snmp really behaves + bad here as it actually might ask multiple times for the same + GETNEXT request as it throws away the answer when it expects it in + a different subtree and might come back later with the very same + request. + +2000-10-23 Kunihiro Ishiguro + + * command.c (cmd_init): Log related command are only installed for + terminal mode. + +2000-10-21 Kunihiro Ishiguro + + * Makefile.am (libzebra_a_SOURCES): Remove duplicated buffer.c. + + * zebra.h: Remove #warn directive. + +2000-10-20 Kunihiro Ishiguro + + * keychain.c (keychain_init): Register "key chain" command to + KEYCHAIN_NODE and KEYCHAIN_KEY_NODE. + + * vty.c (vty_end_config): Fix missing vty_cinfig_unlock for other + CONFIG_NODE. + + * command.c (config_end): Likewise. + + * keychain.c (keychain_get): Key is sorted by it's identifier + value. + +2000-10-19 Kunihiro Ishiguro + + * linklist.c (list_delete_all_node): Call delete function if it is + defined. + + * command.c (cmd_execute_command_strict): Add modification for + vtysh. + (cmd_execute_command_strict): Remove first argument cmdvec because + it is global varibale in command.c. + +2000-10-18 Kunihiro Ishiguro + + * command.c (cmd_init): Install + copy_runningconfig_startupconfig_cmd only in terminal mode. + + * linklist.c (list_delete_node): Simplify the function. + (listnode_lookup): Renamed from list_lookup_node. + +2000-10-17 Kunihiro Ishiguro + + * stream.h: Undef stream_read and stream_write without + parenthesis. + + * newlist.c: File removed. + + * newlist.h: Likewise. + + * linklist.c (list_new): Remove list_init(). To allocate new + linked list, please use list_new(). + (listnode_add): Remove list_add_node(). To add new node to linked + list, please use listnode_add(). + (list_delete_by_val): Revemove fucntion. + +2000-10-16 Nobuaki Tanaka + + * table.c (route_table_free): Reimplement route_table_free(). + +2000-10-11 Kunihiro Ishiguro + + * keychain.c (keychain_get): Register key_delete_func to key + list's delete function. Use linklist.c instead of newlist.c. + +2000-10-04 Akihiro Mizutani + + * filter.c (access_list_remark): Add access-list's remark command. + (no_access_list): "no access-list 100 permit any" error message + bug is fixed. + +2000-10-03 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_SOCKUNION. + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-10-01 Kunihiro Ishiguro + + * linklist.c (list_add_node_head): Delete unused function. + (list_add_node_tail): Likewise. + +2000-09-26 Kunihiro Ishiguro + + * stream.c (stream_read_unblock): Add new function for unblocking + read. + +2000-09-26 Jochen Friedrich + + * smux.c (smux_register): Fix bug of can't register more than one + MIB with SMUX. + +2000-09-26 Makoto Otsuka + + * vty.c (vty_close): Fix memory leak of sb_buffer. + (vty_new): Likewise. + +2000-09-21 steve@Watt.COM (Steve Watt) + + * log.h: Do not declare zlog_priority[0] variable. + +2000-09-12 Kunihiro Ishiguro + + * linklist.h (struct _list ): Add member cmp for compare function. + (struct _list ): Member up is deleted + +2000-09-12 David Lipovkov + + * if.c: Include RIP_API header when RIP API is enabled. + +2000-09-10 Kunihiro Ishiguro + + * prefix.c (prefix_free): Siplify prefix_free(). + + * keychain.c (key_match_for_accept): strncmp check bug is fixed. + +2000-09-07 Kunihiro Ishiguro + + * zebra.h: Merge roken.h into zebra.h. + +2000-09-05 Akihiro Mizutani + + * routemap.c (route_map_init_vty): Install route-map command to + RMAP_NODE. + +2000-08-22 Kunihiro Ishiguro + + * thread.c (thread_get_id): Remove pthread related garbage. + + * command.h (struct host): Likewise. + + * zebra.h: Likewise. + +2000-08-20 Kunihiro Ishiguro + + * command.h (node_type ): Add AAA node for authentication. + + * vty.c (vty_close): Do not close stdout. + +2000-08-18 Kunihiro Ishiguro + + * vty.c (vty_init_vtysh): Added for vtysh. + + * distribute.c (districute_list_prefix_all): Interface independent + filter can be set. + (distribute_list_all): Likewise. + (config_show_distribute): Display current distribute-list status + for "show ip protocols". + +2000-08-18 Akihiro Mizutani + + * command.c (config_terminal_no_length): no terminal monitor -> + terminal no monitor + (cmd_init): Do not install service_terminal_length_cmd into + ENABLE_NODE. + + * vty.c (terminal_no_monitor): no terminal length -> terminal no + length. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +2000-08-17 Magnus Ahltorp + + * vty.h (struct vty ): Add iac_sb_in_progress and sb_buffer for + better IAC handling. + + * vty.c (vty_telnet_option): Change telnet option handling. + +2000-08-15 Gleb Natapov + + * zclient.c (zclient_redistribute_unset): New function added. + +2000-08-14 Kunihiro Ishiguro + + * zclient.c (zebra_interface_add_read): Change ifindex restore + size from two octet to four. + (zebra_interface_state_read): Likewise. + (zebra_interface_address_add_read): Likewise. + +2000-08-13 Kunihiro Ishiguro + + * vty.c (vty_event): Use vector_set_index() instead of + vector_set(). + +2000-08-07 Kunihiro Ishiguro + + * zebra.h (ZEBRA_XXX_DISTANCE_DEFAULT): Define Default + Administrative Distance of each protocol. + +2000-08-07 Matthew Grant + + * if.h (struct interface ): Add new member bandwidth to struct + interface. + + * zclient.c (zebra_interface_add_read): Fetch bandwidth value. + (zebra_interface_state_read): Likewise. + +2000-08-07 Gleb Natapov + + * routemap.c (route_map_event_hook): New hook route_map_event_hook + is added. This hook is called when route-map is changed. The + parameters passed to the hook are 'event' and 'route-map name' + + * routemap.h: Add prototype for route_map_event_hook(). + +2000-08-06 Kunihiro Ishiguro + + * zclient.c (zebra_ipv4_route): zebra_ipv4_route(), + zebra_ipv4_add(), zebra_ipv4_delete() are removed. + + * routemap.c (route_map_empty): Add new function. + (route_map_delete): Use route_map_index_delete() instead of + route_map_index_free(). + (route_map_index_free): Function removed. + +2000-08-06 Gleb Natapov + + * routemap.c (route_map_index_delete): Add check for route-map is + empty or not. + +2000-08-03 Kunihiro Ishiguro + + * zclient.c (zebra_ipv4_add): Change socket arguemnt with struct + zclient. + +2000-08-02 Kunihiro Ishiguro + + * zclient.h (struct zebra): Add obuf for output buffer. + + * if.c: Remove #ifdef NRL enclosing if_nametoindex() and + if_indextoname(). + +2000-08-02 David Lipovkov + + * if.h (IF_PSEUDO_UNSET): IF_PSEUDO related macro added. + (IF_UNKNOWN_SET): IF_UNKNOWN related macro deleted. + + * if.c (interface_pseudo): Add "pseudo" command to interface node. + (no_interface_pseudo): Add "no pseudo" command to interface node. + + * zclient.c (zebra_interface_add_read): Set pseudo flag when it is + send from zebra. + +2000-08-01 Kunihiro Ishiguro + + * zebra.h (ZEBRA_IPV4_NEXTHOP_LOOKUP): Add new message. + (ZEBRA_IPV6_NEXTHOP_LOOKUP): Likewise. + + * vty.c (vty_serv_un): Use AF_UNIX for backward compatibility. + +2000-07-31 Kunihiro Ishiguro + + * vty.c: Use vector for VTY server thread listing instead of + single value. + +2000-07-30 Kunihiro Ishiguro + + * keychain.c (no_key_chain): "no key chain WORD" command is added. + +2000-07-29 Kunihiro Ishiguro + + * command.c (config_from_file): If command fail in + KEYCHAIN_KEY_NODE, down to KEYCHAIN_NODE. + + * vty.h (struct vty ): Add index_sub member. + +2000-07-27 Akihiro Mizutani + + * if.c: Help strings updates. + +2000-07-11 Akihiro Mizutani + + * command.c (no_config_enable_password): Add "no enable password" + command. + (config_write_host): Display password string. + + * routemap.c (route_map_delete_match): Add support for delete + match without argument. + (route_map_delete_set): Likewise. + +2000-07-09 Kunihiro Ishiguro + + * command.h (node_type ): Change KEYCHAIN_NODE and + KEYCHAIN_KEY_NODE place just before INTERFACE_NODE. + +2000-07-09 Jochen Friedrich + + * smux.c (config_write_smux): Fixes the option to override OID and + password for SMUX. + +2000-07-09 Kunihiro Ishiguro + + * command.h (node_type ): Add SMUX_NODE for SMUX configuration. + +2000-07-09 Toshiaki Takada + + * command.c: Sort descvec command's help. + + * vty.c (vty_describe_command): Display '' at the end of + descriptions. + +2000-07-05 Toshiaki Takada + + * command.c (cmd_ipv6_match), (cmd_ipv6_prefix_match): Fix bug + treatment of double colon. + +2000-07-04 Kunihiro Ishiguro + + * zclient.h: Add zclient_redistribute_default_{set,unset}(). + + * keychain.c: New file for authentication key management. + * keychain.h: Likewise. + + * tcpfilter.c: New file for TCP/UDP base filtering using ipfw or + ipchains. + * tcpfilter.h: Likewise. + + * flap.h: New file for route flap dampening. + * flap.c: Likewise. + +2000-07-04 Toshiaki Takada + + * filter.c (struct filter): Add exact flag. + (access_list): Add exact-match command. + (ipv6_access_list): Add exact-match command. + +2000-07-03 Kunihiro Ishiguro + + * zebra.h (ZEBRA_REDISTRIBUTE_DEFAULT_ADD): New message for + request default route. + +2000-07-01 Hideaki YOSHIFUJI ($B5HF#1QL@(B) + + * smux.c: Add IPv6 smux connection code. + +2000-06-15 Kunihiro Ishiguro + + * vty.c (vty_complete_command): To cooperate readline library, + returned string is newly allocated. So some match function case + need, free of memory. + +2000-06-12 Akihiro Mizutani + + * distribute.c: Fix help strings. + +2000-06-11 Kunihiro Ishiguro + + * command.c (cmd_complete_command): Add check for vector_slot + (vline, index) is not NULL when calculating lcd. + (cmd_entry_function): First check variable arguemnt to prevent it + from completion. + +2000-06-10 Kunihiro Ishiguro + + * vty.h (struct vty ): Add output_count member for displaying + output route count. Remove arugment arg from output_func because + the value is passed by vty argument. Change output to output_rn. + Add output_clean function pointer member. Add output_type member. + +2000-06-10 Toshiaki Takada + + * command.c (show_startup_config): Add "show startup-config" + command. + +2000-06-06 Akihiro Mizutani + + * filter.c: Fix help strings. + +2000-06-05 Kunihiro Ishiguro + + * prefix.h (struct prefix_rd): New prefix structure for routing + distinguisher. + (struct prefix): Add padding to every prefix structure. + + + * routemap.c (route_map_add_match): When completely same match + statement exists, don't duplicate it. + +2000-06-05 Akihiro Mizutani + + * routemap.c: Change NAME to WORD. + + * plist.c: Fix help strings. + +2000-06-02 Akihiro Mizutani + + * routemap.c: Fix route-map help strings. + +2000-06-01 Kunihiro Ishiguro + + * command.c (cmd_filter_by_completion): Fix CMD_VARARG treatment + to filter other non vararg commands. + + * routemap.c (route_map_init_vty): Use install_default() for + install common commands into route-map node.. + +2000-06-01 Akihiro Mizutani + + * command.h (OSPF_STR): Macro added. + +2000-05-31 Kunihiro Ishiguro + + * command.c (cmd_complete_command): LCD completion must not modify + installed command string. + + * plist.c (ipv6_prefix_list): Fix wrong syntax definition. Change + X:X::X:X to X:X::X:X/M. + +2000-05-31 Toshiaki Takada + + * vty.c (show_history): New defun added. + +2000-05-30 Kunihiro Ishiguro + + * command.h (CMD_COMPLETE_LIST_MATCH): New define for completion + list. CMD_COMPLETE_MATCH is used for LCD completion. + + * vty.c (vty_complete_command): Matched string's LCD is completed. + + * command.c (cmd_lcd): New function for calculate LCD of matched + strings. + +2000-05-26 Kunihiro Ishiguro + + * command.c (install_default): config_write_terminal_cmd, + config_write_file_cmd, config_write_memory_cmd are added to + default node. + + * memory.c (memory_init): Divide show memory command into each + sort. + + * command.c (cmd_init): config_write_terminal_cmd, + config_write_file_cmd, config_write_memory_cmd are added to + CONFIG_NODE. + + * routemap.c (route_map_index_free): New function. + (no_route_map_all): New DEFUN for "no route-map NAME". + + * filter.c (no_access_list_all): New DEFUN for delete access-list + with NAME. + (no_ipv6_access_list_all): Likewise. + +2000-05-23 Kunihiro Ishiguro + + * plist.c: Change IPV6_PREFIX to X:X::X:X. When "any" is + specified, user can not use "ge" and "le" statement. + +2000-05-22 Thomas Molkenbur + + * routemap.c (route_map_add_set): Fix bug of next pointer missing. + + * table.c (route_table_free): Like wise. + +2000-05-22 Toshiaki Takada + + * vty.c (vty_stop_input): Set history pointer to the latest one. + + * vty.c (vty_hist_add): Do not add command line history when input + is as same as previous one. + +2000-05-14 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_ECOMMUNITY and MTYPE_ECOMMUNITY_VAL. + +2000-05-13 Kunihiro Ishiguro + + * command.h (node_type ): Add BGP_VPNV4_NODE. + +2000-05-08 Kunihiro Ishiguro + + * vty.c (vtysh_accept): Add cast of struct sockaddr * to bind + argument. Reported by: Vesselin Mladenov . + + * filter.c (ipv6_access_list): Add IPv6 prefix example instead of + IPv4 example. Reported by: Love . + + * command.c (cmd_complete_command): Make it sure last element of + matchvec is NULL. This fix problem which cause crush in + vty_complete_command(). Reported by: JINMEI Tatuya + . + +2000-04-28 Love + + * prefix.h (struct prefix): Add padding. + +2000-04-28 Kunihiro Ishiguro + + * command.c (show_version): Update copyright year. + +2000-04-27 Kunihiro Ishiguro + + * routemap.c (route_map_apply): When map is NULL, return deny. + +2000-04-26 Kunihiro Ishiguro + + * filter.c (access_list_apply): When access is NULL, return deny. + + * plist.c (prefix_list_apply): When plist is NULL, return deny. + +2000-04-23 Kunihiro Ishiguro + + * command.h (node_type ): Change RDISC_NODE to IRDP_NODE. + +2000-04-18 Toshiaki Takada + + * filter.[ch] (access_list_add_hook), (access_list_delete_hook): + Add argument for hook function to give struct access_list *. + +2000-04-17 Kunihiro Ishiguro + + * plist.c (prefix_list_entry_match): In case of le nor ge is + specified, exact match is performed. + (prefix_list_entry_match): Add any entry matching check. + +2000-04-09 Kunihiro Ishiguro + + * vty.c (exec_timeout): Separate timeout setting to minutes and + seconds. + (no_exec_timeout): Add "no exec-timeout" command. + + * vty.h (VTY_TIMEOUT_DEFAULT): Change default value from 300 to + 600. + +2000-03-31 Jochen Friedrich + + * smux.h (SMUX_CLOSE): The SMUX_CLOSE PDU is implicit integer, so + it is a primitive encoding and not constructed. + +2000-03-28 Toshiaki Takada + + * memory.[ch] (enum): Add MTYPE_OSPF_EXTERNAL_INFO. + +2000-03-26 Love + + * zclient.c (zclient_read): Add nbytes size check for + ZEBRA_HEADER_SIZE. Check return value of steam_read (). + +2000-03-26 Rick Payne + + * routemap.c: Add flexible route-map commands such as on-match + next, on-match goto N. + + * routemap.h: Likewise + +2000-03-23 Adrian Bool + + * command.c (config_log_trap): Add new command "log trap + PRIORITY". + +2000-03-14 Toshiaki Takada + + * memory.c (struct memory_list): Add Link List and Link Node + to view. + + * memory.h (enum): Remove MTYPE_OSPF_EXTERNAL_ROUTE. + +2000-01-20 Hideto Yamakawa + + * str.c (snprintf): Fix bug of calling sprintf instead of + vsprintf. + +2000-01-16 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_RIP_PEER. + +2000-01-15 Toshiaki Takada + + * memory.h (enum): Add MTYPE_OSPF_CRYPT_KEY. + +2000-01-15 Kunihiro Ishiguro + + * command.h (node_type ): Add MASC_NODE for masc. + +2000-01-09 Wang Jianliang + + * routemap.c (route_map_index_add): When route_map_index is not + empty and insert new item at the head, it can cause core dump. + Fix "if (index == map->head)" to "if (point == map->head). + (route_map_add_set): If there is an old set command, override old + set command with new one. + (route_map_index_delete): Use while() instead of for for() for + logical correctness. + +1999-12-26 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_BGP_STATIC. + +1999-12-23 Alex Zinin + * zebra.h, zclient.*: dynamic int up/down message + support + +1999-12-10 Kunihiro Ishiguro + + * thread.c (thread_cancel_event): Add a function for clean up + events. + +1999-12-09 Kunihiro Ishiguro + + * dropline.c: Delete file. + dropline.h: Linewise. + +1999-12-14 Kunihiro Ishiguro + + * filter.c (access_list_filter_delete): Wrong pointer + access->master was pointed out after access is freed. I store + master value at the beginning of the function. + +1999-12-08 Kunihiro Ishiguro + + * vty.c (exec_timeout): Change of VTY timeout affect to current + VTY connection. + (vty_accept): Instead of immediate exit() return -1. + +1999-12-07 Kunihiro Ishiguro + + * vty.c (vty_configure_lock): Configuration lock function added. + Only one VTY can use CONFI_NODE at the same time. + + * log.c: Delete zvlog_* functions. Now zlog_* does the same + thing. + + * log.c (log_init): Function removed. + (log_close): Likewise. + (log_flush): Likewise. + (log_open): Likewise. + + * vty.c (terminal_monitor): Add new command. + (no_terminal_monitor): Likewise. + + * log.c (old_log): Function removed. + (old_log2): Likewise. + (old_log_warn): Likewise. + +1999-12-04 Toshiaki Takada + + * command.c (cmd_ipv6_match): New function added. + (cmd_ipv6_prefix_match): Likewise. + +1999-12-04 Kunihiro Ishiguro + + * command.c (cmd_ipv6_match): + + * table.c: Delete #ifdef HAVE_MBGPV4. + + * prefix.h (struct prefix): Add safi member. + (struct prefix_ipv4): Likewise. + (struct prefix_ipv6): Likewise. + +1999-12-04 Rumen Svobodnikov + + * memory.c (struct mstat): Revert to support MEMORY_LOG. + +1999-11-25 Kunihiro Ishiguro + + * version.h: Bump up to 0.81c for testing new kernel codes. + +1999-11-21 Kunihiro Ishiguro + + * thread.h (struct thread): Pthread support is disabled all + platform. + +1999-11-21 Michael Handler + + * Include and under SUNOS_5. + +1999-11-21 Kunihiro Ishiguro + + * sockunion.c (in6addr_cmp): Enclosed by #define HAVE_IPV6 +1999-11-13 Kunihiro Ishiguro + + * command.h (node_type ): Add BGP_IPV4_NODE and BGP_IPV6_NODE. + +1999-11-12 Kunihiro Ishiguro + + * command.c (disable): Add `disable' command. + +1999-11-09 Kunihiro Ishiguro + + * plist.c (vty_prefix_list_install): Add any check. + +1999-11-04 Kunihiro Ishiguro + + * command.h (node_type ): Add DUMP_NODE. + +1999-11-03 Kunihiro Ishiguro + + * smux.c: Change default SMUX oid to compatible with gated. + +1999-10-30 Kunihiro Ishiguro + + * if_rmap.c: New file added. + + * if_rmap.h: New file added. + +1999-10-29 Alex Zinin + + * hash.c: add hash_free() function + +1999-10-25 Kunihiro Ishiguro + + * hash.c (hash_clean): Add clean function. + + * plist.c (prefix_list_reset): Add reset function. + + * filter.c (access_list_reset): Add reset function. + +1999-10-17 Kunihiro Ishiguro + + * client.c: Merged with zclient.c. + * client.h: Merged with zclient.h. + +1999-10-15 Jordan Mendelson + + * md5.c: Imported from GNU C Library. + * md5-gnu.h: Likewise. + +1999-10-15 Jochen Friedrich + + * smux.c (smux_getresp_send): SMUX_GETRSP codes improvement. + +1999-10-06 Kunihiro Ishiguro + + * smux.h: New file added. + + * snmp.c: Rename to smux.c. + +1999-10-02 Kunihiro Ishiguro + + * command.c (cmd_execute_command_strict): Filter ambious commands. + (cmd_filter_by_string): Change to return enum match_type. + +1999-10-01 Toshiaki Takada + + * vty.c (vty_describe_fold): New function which does VTY + description line fold. + * vty.c (vty_describe_command): Set description column. + +1999-09-30 Kunihiro Ishiguro + + * plist.c (prefix_list_init_ipv4): VTY user interface is improved. + +1999-09-26 Kunihiro Ishiguro + + * command.c (cmd_filter_by_string): Fix bug of CMD_IPV4 and + CMD_IPV4_PREFIX check. Both return type must be exact_match. + +1999-09-24 Toshiaki Takada + + * command.c (cmd_filter_by_completion), + (is_cmd_ambiguous): Check IPv4 address, IPv4 prefix and range + parameter matches range. + +1999-09-22 Kunihiro Ishiguro + + * routemap.c (route_map_apply): Returm RM_DENYMATCH when no match + is performed. + +1999-09-21 Kunihiro Ishiguro + + * vty.c (vty_read): Control-C stop VTY_MORE mode. + +1999-09-20 Kunihiro Ishiguro + + * command.h (node_type ): Add ACCESS_IPV6_NODE and + PREFIX_IPV6_NODE. + + * distribute.h: New file added. + + * command.h (node_type ): Delete DISTRIBUTE_NODE. + +1999-09-18 Kunihiro Ishiguro + + * vty.c (vty_terminate_all): New function added for reload + support. + +1999-09-06 Kunihiro Ishiguro + + * memory.h (enum): Add new type MTYPE_OSPF_EXTERNAL_ROUTE. + +1999-08-31 Janos Farkas + + * vty.c (vty_read): Handle also 0x7f (alt-backspace), just like + esc-ctrl-h (delete word backwards). + +1999-08-24 Kunihiro Ishiguro + + * if.h: Add if_nametoindex for NRL. + +1999-08-23 Kunihiro Ishiguro + + * if.c (if_create): New function. + +1999-08-22 Kunihiro Ishiguro + + * snmp.c: New file. + +1999-08-21 Kunihiro Ishiguro + + * stream.c (stream_put): stream_memcpy () is changed to stream_put + (). stream_get () is added. + +1999-08-18 Toshiaki Takada + + * memory.h (enum): Add MTYPE_OSPF_LSA_DATA. + +1999-08-18 Yasuhiro Ohara + + * table.c (route_table_finish): add function frees table. + +1999-08-12 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_RTADV_PREFIX. + +1999-08-11 Kunihiro Ishiguro + + * if.h (struct interface ): hw_address, hw_address_len added. + +1999-08-10 Kunihiro Ishiguro + + * if.h (struct interface ): Change structure member if_data to + info, index to ifindex. + +1999-08-08 Rick Payne + + * routemap.c: Multi protocol route-map modification. + + * routemap.c (route_map_apply): Route match process bug is fixed. + +1999-08-05 Kunihiro Ishiguro + + * thread.c (thread_fetch): When signal comes, goto retry point. + +1999-08-04 Kunihiro Ishiguro + + * Makefile.am: Add sockopt.c and sockopt.h + * sockopt.c: New file. + * sockopt.h: New file. + +1999-08-02 Kunihiro Ishiguro + + * version.h (ZEBRA_VERSION): Release zebra-0.75 + +1999-08-01 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_RIPNG_AGGREGATE. + +1999-07-31 Kunihiro Ishiguro + + * sockunion.h: Add sockunion_getpeername (). + +1999-07-27 Kunihiro Ishiguro + + * version.h: Release zebra-0.74 + +1999-07-26 Kunihiro Ishiguro + + * command.h (struct host): Delete lines from struct host. Add + lines to struct vty. + + * command.c: Delete `lines LINES'. Terminal display line settings + should be done by `terminal length' command. + +1999-07-24 Kunihiro Ishiguro + + * memory.h (enum): MTYPE_OSPF_PATH are added. + +1999-07-22 Toshiaki Takada + + * memory.h (enum): MTYPE_OSPF_NEXTHOP is added. + +1999-07-21 Toshiaki Takada + + * linklist.c (list_add_node_prev), (list_add_node_next), + (list_add_list): New function added. + + * table.c (route_table_free): New function added. + +1999-07-21 Kunihiro Ishiguro + + * plist.c (config_write_prefix): Set write flag when configuration + is written. + +1999-07-15 Yasuhiro Ohara + + * prefix.c : prefix_cmp() added. change apply_mask() to + apply_mask_ipv4(), and new apply_mask() added. + +1999-07-14 Yasuhiro Ohara + + * prefix.c (prefix2str): append prefixlen. + +1999-07-13 Kunihiro Ishiguro + + * command.c (config_terminal): Change "config terminal" to + "configure terminal". Reported by Georg Hitsch + . + (config_terminal_length): `terminal length <0-512>' is added. At + this moment this command is only usef for vty interface. + Suggested by Georg Hitsch . + +1999-07-12 Kunihiro Ishiguro + + * routemap.c (rulecmp): Add wrapper function of strcmp. + +1999-07-08 Rick Payne + + * sockunion.c (inet_aton): Fix bug of inet_aton. + +1999-07-08 Kunihiro Ishiguro + + * version.h (ZEBRA_VERSION): Start zebra-0.73 + +1999-07-06 Kunihiro Ishiguro + + * version.h: Bump up to 0.72. + +1999-07-05 Kunihiro Ishiguro + + * command.c (install_default): New function for install default + commands to the node. + + * memory.h (enum): MTYPE_NEXTHOP is added. + +1999-07-01 + + * command.c (no_banner_motd): `no banner motd' command added. + +1999-06-30 Kunihiro Ishiguro + + * regex.c: Update to glibc-2.1.1's posix/regex.c + + * regex-gnu.h: Update to glibc-2.1.1's posix/regex.h + + * prefix.h (IPV4_ADDR_SAME): Macro added. + (IPV6_ADDR_SAME): Likewise. + +1999-06-29 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_OSPF_VERTEX + + * version.h: Bump up to 0.71. + + * vty.c (vty_serv_sock_addrinfo): Use addrinfo function to bind + VTY socket when IPv6 is enabled. + +1999-06-28 Kunihiro Ishiguro + + * vty.c (vty_serv_sock): Change vty_serv_sock determine which + address family to bind. + + * command.c: Add quit command. + +1999-06-26 NOGUCHI kay + + * vty.c (vty_read_config): Fix bug of configuration file path + detection. + +1999-06-25 Kunihiro Ishiguro + + * version.h: Bump up to 0.70. + +1999-06-17 Kunihiro Ishiguro + + * buffer.h (GETL): Remove GETL macro. + + * version.h: Bump up to 0.69. + +1999-06-14 Kunihiro Ishiguro + + * if.c (connected_add): Commented out connected_log. + +1999-06-13 Kunihiro Ishiguro + + * command.h (struct cmd_element ): strvec and descvec is combined + into newstrvec. + + * command.c (desc_make): Function removed. + (desc_next): Function removed. + + * command.h (struct cmd_element ): docvec is removed from struct + cmd_element. + +1999-06-12 Kunihiro Ishiguro + + * command.c (cmd_execute_command): Remove command NULL check. + + * command.h (struct cmd_element ): Add newstrvec entry to struct + cmd_element. + (DEFUN2): DEFUN2 macro is removed. DEFUN is extended to support + (a|b|c) statement. + (DESC): DESC macro is removed. + + * vty.c (vty_complete_command): When return value is + CMD_ERR_NO_MATCH, don't display error message. + +1999-06-08 Kunihiro Ishiguro + + * table.c (route_next_until): New function. + + * version.h: Bump up to 0.68. + +1999-06-06 Kunihiro Ishiguro + + * vty.c (vty_close): Free vty->buf when vty is closed. + + * memory.h (enum): Add MTYPE_COMMUNITY_ENTRY and + MTYPE_COMMUNITY_LIST. + + * vty.h (struct vty ): Change buf from static length buffer to + variable length buffer. + + * vty.c (vty_ensure): New function added. + +1999-06-04 Kunihiro Ishiguro + + * command.h (node_type ): Add COMMUNITY_LIST_NODE. + + * command.c (config_enable_password): Freeing host.enable bug is + fixed. + (config_enable_password): Add argc count check. + +1999-05-31 Kunihiro Ishiguro + + * version.h: Bump up to 0.67. + +1999-05-30 Kunihiro Ishiguro + + * command.c (zencrypt): New function for encrypt password. + + * command.h (struct host): Add password_encrypt and + enable_encrypt. + +1999-05-30 Jochen Friedrich + + * command.h (struct host): New member encrypt is added for + encrypted password. + +1999-05-30 Kunihiro Ishiguro + + * vty.c: Remove all_digit_check function. Instead use all_digit. + + * prefix.c (all_digit): New function for checking string is made + from digit character. + +1999-05-25 Kunihiro Ishiguro + + * Makefile.am (libzebra_a_SOURCES): Add zclient.c. + (noinst_HEADERS): Add zclient.h + + * zclient.[ch]: New file for zebra client routine. + + * memory.h (enum): Add MTYPE_ZEBRA. + +1999-05-19 Kunihiro Ishiguro + + * version.h (ZEBRA_VERSION): Update to 0.66. + +1999-05-15 Kunihiro Ishiguro + + * buffer.h (GETC,GETW): Macro deleted. + +1999-05-15 Carlos Alberto Barcenilla + + * prefix.h (IPV4_NET0, IPV4_NET127): Macro added. + +1999-05-15 Kunihiro Ishiguro + + * vty.c (service_advanced_vty): New command added. + (no_service_advanced_vty): Likewise. + +1999-05-14 Kunihiro Ishiguro + + * vty.c (vty_auth): If advanced flag is set and enable password is + not set, directly login to the ENABLE_NODE. This feature is + originally designed and implemented by Stephen R. van den Berg + . + + * command.h (host): Add advanced flag to struct host for advanced + vty terminal interface. + + * version.h (ZEBRA_VERSION): Update to 0.65 for next beta release. + +1999-05-14 Stephen R. van den Berg + + * command.h (node_type ): Add TABLE_NODE. + + * vty.c (vty_telnet_option): Check host.lines value. + + * command.c (config_lines): DEFUN for 'lines LINES' command. + + * zebra.h: Include for uname(). + (RT_TABLE_MAIN): Defined as 0 if OS does not support multiple + routing table. + + * vty.c (vty_auth): Directly login to the ENABLE_NODE when enable + password is not set. + (vty_prompt): Get machine's hostname when hostname is not set. + +1999-05-11 James Willard + + * command.c (config_exit): Close connection when `exit' command is + executed at ENABLE_NODE. + +1999-05-10 Kunihiro Ishiguro + + * vty.c (vty_stop_input): `C-c' key change node to ENABLE_NODE. + + * command.c (cmd_execute_command_strict): Matched command size + check added. + (cmd_make_desc_line): New function for DEFUN2. + + * command.h (struct cmd_element ): Add descsize. + +1999-05-09 Kunihiro Ishiguro + + * command.h (struct cmd_element ): Remame descvec to docvec. + (struct cmd_element ): Add descvec for new description system. + + * command.c (desc_make): Check cmd->descvec. + +1999-05-06 Kunihiro Ishiguro + + * memory.h (enum): Add MTYPE_CLUSTER, MTYPE_CLUSTER_VAL. + +1999-05-05 Kunihiro Ishiguro + + * version.h (ZEBRA_VERSION): Bump up to 0.64 for next beta + release. + +1999-05-04 Yasuhiro Ohara + + * linklist.c (list_delete_all_node): bug fix. + previous code loses current position when node + is deleted. + +1999-05-03 Kunihiro Ishiguro + + * command.h (DESC): Macro added. + (struct cmd_element2): Delete struct cmd_element2. + + * plist.c (prefix_list): Sequential number option check is added. + +1999-05-02 Yasuhiro Ohara + + * log.c (zvlog_{debug,info,notice,warn,err}): have been + added. now we can log both console and file, but still + need some fix about config write. + +1999-05-02 Kunihiro Ishiguro + + * log.c (zvlog_debug): Fix yasu's change. + +1999-05-01 Kunihiro Ishiguro + + * plist.c (prefix_list): Fix typo. + +1999-04-30 Kunihiro Ishiguro + + * Set version to 0.63 for first beta package. + +1999-04-27 Carlos Barcenilla + + * prefix.c (str2prefix_ipv4): Fix prefix length check. + (str2prefix_ipv6): Likewise. + +1999-04-25 Kunihiro Ishiguro + + * memory.h (enum): Add MTPYE_PREFIX_LIST and + MTYPE_PREFIX_LIST_ENTRY. + + * command.h (node_type ): Add PREFIX_NODE. + +1999-04-25 Carlos Barcenilla + + * command.c: ALIAS (config_write_memory_cmd) and ALIAS + (copy_runningconfig_startupconfig_cmd) is added. + + * table.c (route_node_lookup): Unused match variable deletion. + +1999-04-24 Kunihiro Ishiguro + + * Makefile.am (libzebra_a_SOURCES): plist.c added. + (noinst_HEADERS): plist.h added. + + * plist.c, plist.h: New file added. + + * memory.h (enum): Rename MTYPE_AS_PASN to MTYPE_AS_STR. + * memory.c: Likewise. + +1999-04-19 Carlos Alberto Barcenilla + + * command.c (show_version): `show version' command added. + +1999-04-19 Kunihiro Ishiguro + + * prefix.c (str2prefix_ipv6): Prefix length overflow check. + +1999-04-19 Carlos Alberto Barcenilla + + * prefix.c (str2prefix_ipv4): Prefix length overflow check. + +1999-04-19 Alex Bligh + + * prefix.c (sockunion2hostprefix): Function added. + (sockunion2prefix): Address family was not set. Now it is set. + + * vty.c: VTY access-class command is added. + +1999-04-18 Kunihiro Ishiguro + + * memory.c: Change xmalloc to zmalloc. xcalloc, xrealloc, xfree, + xstrdup are likewise. + +1999-04-18 Yasuhiro Ohara + + * thread.c: Add thread_execute for other routing daemon. + OSPF tasks need to be generated by "sheduled" and "executed". + +1999-04-13 Kunihiro Ishiguro + + * buffer.c: Rewrite buffer_write and buffer_flush related + functions for fixing bugs. Reason of the problem and fix is + suggested by Alex Bligh . + +1999-04-12 Alex Bligh + + * command.c (cmd_entry_function_descr): Added for variable + argument help display. + +1999-04-07 Kunihiro Ishiguro + + * regex.c, regex-gnu.h: Imported from GNU sed-3.02 distribution. + +1999-03-24 Kunihiro Ishiguro + + * stream.c: stream_fifo_free bug is fixed. + +1999-03-19 Toshiaki Takada + + * stream.c (stream_strncpy): Added for getting any length bytes + from stream. + +1999-03-16 Kunihiro Ishiguro + + * version.h (ZEBRA_BUG_ADDRESS): New macro added. + +1999-03-14 Kunihiro Ishiguro + + * buffer.c (buffer_flush_window): If ep is same as buffer's size + length and lp is overrun one octet. + +1999-03-13 Kunihiro Ishiguro + + * vty.h: add VTY's timeout function. + +1999-03-05 + + * command.h (node_type ): Add OSPF6_node. + +1999-03-04 Kunihiro Ishiguro + + * zebra.h: Check HAVE_SYS_SELECT_H when include + +1999-03-03 Jeroen Ruigrok/Asmodai + + * zebra.h: Include if it exists. + +1999-03-02 Kunihiro Ishiguro + + * getopt.[ch],getopt1.c: Sync with glibc-2.1. + + * log.c (zlog): Tempolary ZLOG_STDOUT feature added. + + * command.h: Include vector.h and vty.h + +1999-02-25 Kunihiro Ishiguro + + * routemap.h (struct route_map_rule_cmd): Add prefix arguemnt. + + * routemap.c (route_map_apply_index): Add prefix argument. + (route_map_apply): Likewise. + + * memory.h (enum): Add MTYPE_ROUTE_MAP_COMPILED. + + * stream.c: Add stream_fifo related functions. + +1999-02-24 Kunihiro Ishiguro + + * daemon.c: Return integer value. File descriptor close is added. + + * memory.h (enum): add MTYPE_OSPF_LSA. + +1999-02-23 Kunihiro Ishiguro + + * rsh.c: Remove empty file. + +1999-02-22 + + * routemap.c: Add add/delete hook to route_map_master. + +1999-02-19 Peter Galbavy + + * str.[ch] added to supply wrappers for snprintf(), strlcat() and + strlcpy on system without these. + +1999-02-18 Peter Galbavy + + * syslog support added + +1999-02-02 Kunihiro Ishiguro + + * filter.c (access_list_add_hook): added for hook function management. + * filter.c (access_list_delete_hook): Likewise. + +1999-01-19 Kunihiro Ishiguro + + * stream.c: New file. + * stream.h: New file. + * Divide stream related fucntions from buffer.[ch] into stream.[ch]. + +1999-01-14 Kunihiro Ishiguro + + * memory.h (enum): add MTYPE_STREAM, MTYPE_STREAM_DATA + + * buffer.c (stream_new): Set MTYPE_STREAM to XMALLOC argument. + +1998-12-23 Kunihiro Ishiguro + + * routemap.c: route_map_index_delete() added. + +1998-12-22 Kunihiro Ishiguro + + * buffer.c (buffer_empty): check cp instead of sp. + +1998-12-17 Kunihiro Ishiguro + + * radix.[ch]: Deleted. + +1998-12-15 Magnus Ahltorp + + * buffer.c: Prototype fixes. + * prefix.c: Likewise. + * sockunion.c: Likewise. + * sockunion.h: Likewise. + +1998-12-14 Kunihiro Ishiguro + + * vty.c (vty_read): DELETE key works as vty_delete_char. + +1998-12-13 Kunihiro Ishiguro + + * log.c (time_print): chane %y to %Y. + +1998-12-10 Kunihiro Ishiguro + + * distribute.c: new file. + +1998-12-09 Kunihiro Ishiguro + + * filter.c: Remove all of struct prefix_{ipv4,ipv6} and add + complete support of IPv6 access list. + + * command.c (config_write_element): function delete. + (config_write_host): function add. password and enable password + isn't printed to vty interface. + +1998-12-08 Kunihiro Ishiguro + + * filter.c: Change prefix_ipv4 to prefix and add support of + prefix_ipv6 filtering. + +1998-12-07 Kunihiro Ishiguro + + * Makefile.am (INCLUDES): add @INCLUDES@ for Linux IPv6 inet6-apps + header includes. + +1998-12-05 Kunihiro Ishiguro + + * log.c (log_flush): fix function name typo. + +1998-12-04 Yasuhiro Ohara + + * memory.h: OSPF memory type is added. + +1998-11-15 Kunihiro Ishiguro + + * command.c (sort_node): add sort_node() for pretty printing of + command on vty interface. + (config_password): delete the restriction of charaster of password + string. + +1998-09-05 Kunihiro Ishiguro + + * prefix.c (prefix_ipv4_any): add prefix_ipv4_any(). + +1998-08-25 Kunihiro Ishiguro + + * network.h: New file. + +1998-08-24 Kunihiro Ishiguro + + * vty.c (vty_will_echo): function name change from vty_off_echo. + +1998-08-18 Kunihiro Ishiguro + + * buffer.h: add PUTC,PUTW,PUTL macros. + +1998-07-22 Kunihiro Ishiguro + + * route.[ch]: renamed to prefix.[ch] + +1998-06-09 Kunihiro Ishiguro + + * prefix_in, prefix_in6 is replaced by prefix_ipv4, prefix_ipv6. + + * Makefile.am: @INCLUDES@ is deleted from INCLUDES. + +1998-06-07 Kunihiro Ishiguro + + * host.[ch]: merged with command.[ch] + +1998-05-08 Kunihiro Ishiguro + + * Makefile.am (libzebra_a_SOURCES): add route.c to libzebra_a_SOURCES. + +1998-05-07 Kunihiro Ishiguro + + * route.c (str2prefix): str2prefix () is gone. + +1998-05-03 Kunihiro Ishiguro + + * vty.c (vty_read_config): change CONDIR to SYSCONFDIR. + + * .cvsignore: add file. + + * memory.c (xerror): add arguent `type' and `size'. + + * socket.c: deleted. + +1998-05-02 Kunihiro Ishiguro + + * vector.c: malloc,free,realloc -> XMALLOC,XFREE,XREALLOC. + * linklist.c: same as above. + +1998-04-30 Kunihiro Ishiguro + + * filter.[ch]: added. + +1998-04-01 Kunihiro Ishiguro + + * vty.c (config_who): return CMD_SUCCESS + +1998-04-01 Jochen Friedrich + + * table.c (route_dump_node): route_dump_node is IPv6 specific + function so move #ifdef to the end of route_dump_node (). + +1998-03-05 "Hannes R. Boehm" + + * if.c: DEFUN(interface_desc) added. + +1998-03-05 Kunihiro Ishiguro + + * if.c: separated from ripd/rip_interface.c + +1998-03-04 Kunihiro Ishiguro + + * thread.[ch] : added. + +1998-02-14 Kunihiro Ishiguro + + * vty.c (vty_delete_char): fix size bug. + (vty_backward_pure_word): function added. + (vty_read): ESC + 'f' perform vty_forward_word. + (vty_read): ESC + 'b' perform vty_backward_word. + +1998-02-11 Kunihiro Ishiguro + + * radix.c (radix_lookup_rt): add mask check. + (radix_delete_duproute): add mask check. + +1998-02-10 Kunihiro Ishiguro + + * command.c (config_write_file): fix vty -> file_vty. + +1998-02-06 Kunihiro Ishiguro + + * command.c (cmd_filter_ambiguous): add complex type treatment. + +1998-02-05 Kunihiro Ishiguro + + * vty.c (vty_time_print): function added. + (vty_complete_command): now [...] element isn't shown by completion. + +1998-01-26 Kunihiro Ishiguro + + * command.c : change from cmd_install_node() to install_node(). + +1998-01-16 Kunihiro Ishiguro + + * route.[ch]: struct rt{} is replaced by struct prefix{}. + +1998-01-06 Kunihiro Ishiguro + + * command.c (cmd_execute_command): check command length. + + * timer.c (zebra_timer_set): add zebra_timer_set. + +1998-01-05 Kunihiro Ishiguro + + * command.h (node_type ): add ZEBRA_NODE. + + * command.c (config_exit): add RIP_NODE. + (config_write_file): add RIP_NODE. + +1998-01-04 Kunihiro Ishiguro + + * print_version.c (print_version): Now Copyright is 1996-1998. + + * sockunion.c (sockunion_log): moved from ../zebra/route.c + +1997-12-30 Kunihiro Ishiguro + + * host.c (config_logfile): change 'log PATH' to 'logfile PATH'. + + * sockunion.c (sockunion_sameprefix): add same prefix for + sockunion. + +1997-12-29 Kunihiro Ishiguro + + * radix.[ch] : are moved from ../zebra directroy. + + * command.c (config_from_file): if command execution failed down + level to CONFIG_NODE. + + * host.c: config_log function which enable 'log FILENAME' command. + +1997-12-23 Kunihiro Ishiguro + + * vty.c: add vty_transpose_chars (). Now you can use '^T' to + transpose character. + + * command.c: cmd_cmdsize add, this is useful to check incomplete + command. + +1997-12-07 Kunihiro Ishiguro + + * fd.h: add family for address family + +1997-12-06 Kunihiro Ishiguro + + * command.o + * vty.o + * host.o is moved from ../zebra + +1997-08-14 Kunihiro Ishiguro + + * make library directory. + diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000..475b9a2 --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,30 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" + +noinst_LIBRARIES = libzebra.a + +libzebra_a_SOURCES = \ + version.c network.c pid_output.c getopt.c getopt1.c daemon.c \ + print_version.c checksum.c vector.c linklist.c vty.c command.c \ + sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \ + filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ + zclient.c sockopt.c smux.c md5.c keychain.c pqueue.c + +libzebra_a_DEPENDENCIES = @LIB_REGEX@ + +libzebra_a_LIBADD = @LIB_REGEX@ + +noinst_HEADERS = \ + buffer.h command.h filter.h getopt.h hash.h if.h linklist.h log.h \ + memory.h network.h prefix.h routemap.h distribute.h sockunion.h \ + str.h stream.h table.h thread.h checksum.h vector.h version.h vty.h \ + zebra.h plist.h zclient.h sockopt.h smux.h md5-gnu.h keychain.h \ + pqueue.h + +EXTRA_DIST = regex.c regex-gnu.h + +version.c: Makefile + echo '' >version.c + echo 'char *host_name = "$(host_alias)";' >>version.c diff --git a/lib/Makefile.in b/lib/Makefile.in new file mode 100644 index 0000000..6bd11ec --- /dev/null +++ b/lib/Makefile.in @@ -0,0 +1,400 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CPP = @CPP@ +CURSES = @CURSES@ +DEPDIR = @DEPDIR@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LIBPAM = @LIBPAM@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" + +noinst_LIBRARIES = libzebra.a + +libzebra_a_SOURCES = \ + version.c network.c pid_output.c getopt.c getopt1.c daemon.c \ + print_version.c checksum.c vector.c linklist.c vty.c command.c \ + sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \ + filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ + zclient.c sockopt.c smux.c md5.c keychain.c pqueue.c + + +libzebra_a_DEPENDENCIES = @LIB_REGEX@ + +libzebra_a_LIBADD = @LIB_REGEX@ + +noinst_HEADERS = \ + buffer.h command.h filter.h getopt.h hash.h if.h linklist.h log.h \ + memory.h network.h prefix.h routemap.h distribute.h sockunion.h \ + str.h stream.h table.h thread.h checksum.h vector.h version.h vty.h \ + zebra.h plist.h zclient.h sockopt.h smux.h md5-gnu.h keychain.h \ + pqueue.h + + +EXTRA_DIST = regex.c regex-gnu.h +subdir = lib +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libzebra_a_AR = $(AR) cru +am_libzebra_a_OBJECTS = version.$(OBJEXT) network.$(OBJEXT) \ + pid_output.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \ + daemon.$(OBJEXT) print_version.$(OBJEXT) checksum.$(OBJEXT) \ + vector.$(OBJEXT) linklist.$(OBJEXT) vty.$(OBJEXT) \ + command.$(OBJEXT) sockunion.$(OBJEXT) prefix.$(OBJEXT) \ + thread.$(OBJEXT) if.$(OBJEXT) memory.$(OBJEXT) buffer.$(OBJEXT) \ + table.$(OBJEXT) hash.$(OBJEXT) filter.$(OBJEXT) \ + routemap.$(OBJEXT) distribute.$(OBJEXT) stream.$(OBJEXT) \ + str.$(OBJEXT) log.$(OBJEXT) plist.$(OBJEXT) zclient.$(OBJEXT) \ + sockopt.$(OBJEXT) smux.$(OBJEXT) md5.$(OBJEXT) \ + keychain.$(OBJEXT) pqueue.$(OBJEXT) +libzebra_a_OBJECTS = $(am_libzebra_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/buffer.Po ./$(DEPDIR)/checksum.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/command.Po ./$(DEPDIR)/daemon.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/distribute.Po ./$(DEPDIR)/filter.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/getopt.Po ./$(DEPDIR)/getopt1.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/hash.Po ./$(DEPDIR)/if.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/keychain.Po ./$(DEPDIR)/linklist.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/log.Po ./$(DEPDIR)/md5.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/memory.Po ./$(DEPDIR)/network.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/pid_output.Po ./$(DEPDIR)/plist.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/pqueue.Po ./$(DEPDIR)/prefix.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/print_version.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/routemap.Po ./$(DEPDIR)/smux.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/sockopt.Po ./$(DEPDIR)/sockunion.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/str.Po ./$(DEPDIR)/stream.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/table.Po ./$(DEPDIR)/thread.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/vector.Po ./$(DEPDIR)/version.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/vty.Po ./$(DEPDIR)/zclient.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CFLAGS = @CFLAGS@ +DIST_SOURCES = $(libzebra_a_SOURCES) +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in +SOURCES = $(libzebra_a_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libzebra.a: $(libzebra_a_OBJECTS) $(libzebra_a_DEPENDENCIES) + -rm -f libzebra.a + $(libzebra_a_AR) libzebra.a $(libzebra_a_OBJECTS) $(libzebra_a_LIBADD) + $(RANLIB) libzebra.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checksum.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/distribute.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/if.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keychain.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linklist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/network.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pid_output.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pqueue.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prefix.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print_version.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/routemap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smux.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockopt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockunion.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/table.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vector.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vty.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zclient.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `cygpath -w $<` +CCDEPMODE = @CCDEPMODE@ +uninstall-info-am: + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(HEADERS) + +installdirs: + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-info-am + +.PHONY: GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES distclean distclean-compile \ + distclean-depend distclean-generic distclean-tags distdir dvi \ + dvi-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic tags uninstall uninstall-am \ + uninstall-info-am + + +version.c: Makefile + echo '' >version.c + echo 'char *host_name = "$(host_alias)";' >>version.c +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/buffer.c b/lib/buffer.c new file mode 100644 index 0000000..de51ee3 --- /dev/null +++ b/lib/buffer.c @@ -0,0 +1,568 @@ +/* + * Buffering of output and input. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "buffer.h" + +/* Make buffer data. */ +struct buffer_data * +buffer_data_new (size_t size) +{ + struct buffer_data *d; + + d = XMALLOC (MTYPE_BUFFER_DATA, sizeof (struct buffer_data)); + memset (d, 0, sizeof (struct buffer_data)); + d->data = XMALLOC (MTYPE_BUFFER_DATA, size); + + return d; +} + +void +buffer_data_free (struct buffer_data *d) +{ + if (d->data) + XFREE (MTYPE_BUFFER_DATA, d->data); + XFREE (MTYPE_BUFFER_DATA, d); +} + +/* Make new buffer. */ +struct buffer * +buffer_new (size_t size) +{ + struct buffer *b; + + b = XMALLOC (MTYPE_BUFFER, sizeof (struct buffer)); + memset (b, 0, sizeof (struct buffer)); + + b->size = size; + + return b; +} + +/* Free buffer. */ +void +buffer_free (struct buffer *b) +{ + struct buffer_data *d; + struct buffer_data *next; + + d = b->head; + while (d) + { + next = d->next; + buffer_data_free (d); + d = next; + } + + d = b->unused_head; + while (d) + { + next = d->next; + buffer_data_free (d); + d = next; + } + + XFREE (MTYPE_BUFFER, b); +} + +/* Make string clone. */ +char * +buffer_getstr (struct buffer *b) +{ + return strdup ((char *)b->head->data); +} + +/* Return 1 if buffer is empty. */ +int +buffer_empty (struct buffer *b) +{ + if (b->tail == NULL || b->tail->cp == b->tail->sp) + return 1; + else + return 0; +} + +/* Clear and free all allocated data. */ +void +buffer_reset (struct buffer *b) +{ + struct buffer_data *data; + struct buffer_data *next; + + for (data = b->head; data; data = next) + { + next = data->next; + buffer_data_free (data); + } + b->head = b->tail = NULL; + b->alloc = 0; + b->length = 0; +} + +/* Add buffer_data to the end of buffer. */ +void +buffer_add (struct buffer *b) +{ + struct buffer_data *d; + + d = buffer_data_new (b->size); + + if (b->tail == NULL) + { + d->prev = NULL; + d->next = NULL; + b->head = d; + b->tail = d; + } + else + { + d->prev = b->tail; + d->next = NULL; + + b->tail->next = d; + b->tail = d; + } + + b->alloc++; +} + +/* Write data to buffer. */ +int +buffer_write (struct buffer *b, u_char *ptr, size_t size) +{ + struct buffer_data *data; + + data = b->tail; + b->length += size; + + /* We use even last one byte of data buffer. */ + while (size) + { + /* If there is no data buffer add it. */ + if (data == NULL || data->cp == b->size) + { + buffer_add (b); + data = b->tail; + } + + /* Last data. */ + if (size <= (b->size - data->cp)) + { + memcpy ((data->data + data->cp), ptr, size); + + data->cp += size; + size = 0; + } + else + { + memcpy ((data->data + data->cp), ptr, (b->size - data->cp)); + + size -= (b->size - data->cp); + ptr += (b->size - data->cp); + + data->cp = b->size; + } + } + return 1; +} + +/* Insert character into the buffer. */ +int +buffer_putc (struct buffer *b, u_char c) +{ + buffer_write (b, &c, 1); + return 1; +} + +/* Insert word (2 octets) into ther buffer. */ +int +buffer_putw (struct buffer *b, u_short c) +{ + buffer_write (b, (char *)&c, 2); + return 1; +} + +/* Put string to the buffer. */ +int +buffer_putstr (struct buffer *b, u_char *c) +{ + size_t size; + + size = strlen ((char *)c); + buffer_write (b, c, size); + return 1; +} + +/* Flush specified size to the fd. */ +void +buffer_flush (struct buffer *b, int fd, size_t size) +{ + int iov_index; + struct iovec *iovec; + struct buffer_data *data; + struct buffer_data *out; + struct buffer_data *next; + + iovec = malloc (sizeof (struct iovec) * b->alloc); + iov_index = 0; + + for (data = b->head; data; data = data->next) + { + iovec[iov_index].iov_base = (char *)(data->data + data->sp); + + if (size <= (data->cp - data->sp)) + { + iovec[iov_index++].iov_len = size; + data->sp += size; + if (data->sp == data->cp) + data = data->next; + break; + } + else + { + iovec[iov_index++].iov_len = data->cp - data->sp; + size -= data->cp - data->sp; + data->sp = data->cp; + } + } + + /* Write buffer to the fd. */ + writev (fd, iovec, iov_index); + + /* Free printed buffer data. */ + for (out = b->head; out && out != data; out = next) + { + next = out->next; + if (next) + next->prev = NULL; + else + b->tail = next; + b->head = next; + + buffer_data_free (out); + b->alloc--; + } + + free (iovec); +} + +/* Flush all buffer to the fd. */ +int +buffer_flush_all (struct buffer *b, int fd) +{ + int ret; + struct buffer_data *d; + int iov_index; + struct iovec *iovec; + + if (buffer_empty (b)) + return 0; + + iovec = malloc (sizeof (struct iovec) * b->alloc); + iov_index = 0; + + for (d = b->head; d; d = d->next) + { + iovec[iov_index].iov_base = (char *)(d->data + d->sp); + iovec[iov_index].iov_len = d->cp - d->sp; + iov_index++; + } + ret = writev (fd, iovec, iov_index); + + free (iovec); + + buffer_reset (b); + + return ret; +} + +/* Flush all buffer to the fd. */ +int +buffer_flush_vty_all (struct buffer *b, int fd, int erase_flag, + int no_more_flag) +{ + int nbytes; + int iov_index; + struct iovec *iov; + struct iovec small_iov[3]; + char more[] = " --More-- "; + char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; + struct buffer_data *data; + struct buffer_data *out; + struct buffer_data *next; + + /* For erase and more data add two to b's buffer_data count.*/ + if (b->alloc == 1) + iov = small_iov; + else + iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2)); + + data = b->head; + iov_index = 0; + + /* Previously print out is performed. */ + if (erase_flag) + { + iov[iov_index].iov_base = erase; + iov[iov_index].iov_len = sizeof erase; + iov_index++; + } + + /* Output data. */ + for (data = b->head; data; data = data->next) + { + iov[iov_index].iov_base = (char *)(data->data + data->sp); + iov[iov_index].iov_len = data->cp - data->sp; + iov_index++; + } + + /* In case of `more' display need. */ + if (! buffer_empty (b) && !no_more_flag) + { + iov[iov_index].iov_base = more; + iov[iov_index].iov_len = sizeof more; + iov_index++; + } + + /* We use write or writev*/ + nbytes = writev (fd, iov, iov_index); + + /* Error treatment. */ + if (nbytes < 0) + { + if (errno == EINTR) + ; + if (errno == EWOULDBLOCK) + ; + } + + /* Free printed buffer data. */ + for (out = b->head; out && out != data; out = next) + { + next = out->next; + if (next) + next->prev = NULL; + else + b->tail = next; + b->head = next; + + buffer_data_free (out); + b->alloc--; + } + + if (iov != small_iov) + XFREE (MTYPE_TMP, iov); + + return nbytes; +} + +/* Flush buffer to the file descriptor. Mainly used from vty + interface. */ +int +buffer_flush_vty (struct buffer *b, int fd, int size, + int erase_flag, int no_more_flag) +{ + int nbytes; + int iov_index; + struct iovec *iov; + struct iovec small_iov[3]; + char more[] = " --More-- "; + char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; + struct buffer_data *data; + struct buffer_data *out; + struct buffer_data *next; + +#ifdef IOV_MAX + int iov_size; + int total_size; + struct iovec *c_iov; + int c_nbytes; +#endif /* IOV_MAX */ + + /* For erase and more data add two to b's buffer_data count.*/ + if (b->alloc == 1) + iov = small_iov; + else + iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2)); + + data = b->head; + iov_index = 0; + + /* Previously print out is performed. */ + if (erase_flag) + { + iov[iov_index].iov_base = erase; + iov[iov_index].iov_len = sizeof erase; + iov_index++; + } + + /* Output data. */ + for (data = b->head; data; data = data->next) + { + iov[iov_index].iov_base = (char *)(data->data + data->sp); + + if (size <= (data->cp - data->sp)) + { + iov[iov_index++].iov_len = size; + data->sp += size; + if (data->sp == data->cp) + data = data->next; + break; + } + else + { + iov[iov_index++].iov_len = data->cp - data->sp; + size -= (data->cp - data->sp); + data->sp = data->cp; + } + } + + /* In case of `more' display need. */ + if (!buffer_empty (b) && !no_more_flag) + { + iov[iov_index].iov_base = more; + iov[iov_index].iov_len = sizeof more; + iov_index++; + } + + /* We use write or writev*/ + +#ifdef IOV_MAX + /* IOV_MAX are normally defined in , Posix.1g. + example: Solaris2.6 are defined IOV_MAX size at 16. */ + c_iov = iov; + total_size = iov_index; + nbytes = 0; + + while( total_size > 0 ) + { + /* initialize write vector size at once */ + iov_size = ( total_size > IOV_MAX ) ? IOV_MAX : total_size; + + c_nbytes = writev (fd, c_iov, iov_size ); + + if( c_nbytes < 0 ) + { + if(errno == EINTR) + ; + ; + if(errno == EWOULDBLOCK) + ; + ; + nbytes = c_nbytes; + break; + + } + + nbytes += c_nbytes; + + /* move pointer io-vector */ + c_iov += iov_size; + total_size -= iov_size; + } +#else /* IOV_MAX */ + nbytes = writev (fd, iov, iov_index); + + /* Error treatment. */ + if (nbytes < 0) + { + if (errno == EINTR) + ; + if (errno == EWOULDBLOCK) + ; + } +#endif /* IOV_MAX */ + + /* Free printed buffer data. */ + for (out = b->head; out && out != data; out = next) + { + next = out->next; + if (next) + next->prev = NULL; + else + b->tail = next; + b->head = next; + + buffer_data_free (out); + b->alloc--; + } + + if (iov != small_iov) + XFREE (MTYPE_TMP, iov); + + return nbytes; +} + +/* Calculate size of outputs then flush buffer to the file + descriptor. */ +int +buffer_flush_window (struct buffer *b, int fd, int width, int height, + int erase, int no_more) +{ + unsigned long cp; + unsigned long size; + int lp; + int lineno; + struct buffer_data *data; + + if (height >= 2) + height--; + + /* We have to calculate how many bytes should be written. */ + lp = 0; + lineno = 0; + size = 0; + + for (data = b->head; data; data = data->next) + { + cp = data->sp; + + while (cp < data->cp) + { + if (data->data[cp] == '\n' || lp == width) + { + lineno++; + if (lineno == height) + { + cp++; + size++; + goto flush; + } + lp = 0; + } + cp++; + lp++; + size++; + } + } + + /* Write data to the file descriptor. */ + flush: + + return buffer_flush_vty (b, fd, size, erase, no_more); +} diff --git a/lib/buffer.h b/lib/buffer.h new file mode 100644 index 0000000..7449aa7 --- /dev/null +++ b/lib/buffer.h @@ -0,0 +1,77 @@ +/* + * Buffering to output and input. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_BUFFER_H +#define _ZEBRA_BUFFER_H + +/* Buffer master. */ +struct buffer +{ + /* Data list. */ + struct buffer_data *head; + struct buffer_data *tail; + + /* Current allocated data. */ + unsigned long alloc; + + /* Total length of buffer. */ + unsigned long size; + + /* For allocation. */ + struct buffer_data *unused_head; + struct buffer_data *unused_tail; + + /* Current total length of this buffer. */ + unsigned long length; +}; + +/* Data container. */ +struct buffer_data +{ + struct buffer *parent; + struct buffer_data *next; + struct buffer_data *prev; + + /* Acctual data stream. */ + unsigned char *data; + + /* Current pointer. */ + unsigned long cp; + + /* Start pointer. */ + unsigned long sp; +}; + +/* Buffer prototypes. */ +struct buffer *buffer_new (size_t); +int buffer_write (struct buffer *, u_char *, size_t); +void buffer_free (struct buffer *); +char *buffer_getstr (struct buffer *); +int buffer_putc (struct buffer *, u_char); +int buffer_putstr (struct buffer *, u_char *); +void buffer_reset (struct buffer *); +int buffer_flush_all (struct buffer *, int); +int buffer_flush_vty_all (struct buffer *, int, int, int); +int buffer_flush_window (struct buffer *, int, int, int, int, int); +int buffer_empty (struct buffer *); + +#endif /* _ZEBRA_BUFFER_H */ diff --git a/lib/checksum.c b/lib/checksum.c new file mode 100644 index 0000000..6a29cba --- /dev/null +++ b/lib/checksum.c @@ -0,0 +1,47 @@ +/* + * Checksum routine for Internet Protocol family headers (C Version). + * + * Refer to "Computing the Internet Checksum" by R. Braden, D. Borman and + * C. Partridge, Computer Communication Review, Vol. 19, No. 2, April 1989, + * pp. 86-101, for additional details on computing this checksum. + */ + +#include + +int /* return checksum in low-order 16 bits */ +in_cksum(ptr, nbytes) +register u_short *ptr; +register int nbytes; +{ + register long sum; /* assumes long == 32 bits */ + u_short oddbyte; + register u_short answer; /* assumes u_short == 16 bits */ + + /* + * Our algorithm is simple, using a 32-bit accumulator (sum), + * we add sequential 16-bit words to it, and at the end, fold back + * all the carry bits from the top 16 bits into the lower 16 bits. + */ + + sum = 0; + while (nbytes > 1) { + sum += *ptr++; + nbytes -= 2; + } + + /* mop up an odd byte, if necessary */ + if (nbytes == 1) { + oddbyte = 0; /* make sure top half is zero */ + *((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */ + sum += oddbyte; + } + + /* + * Add back carry outs from top 16 bits to low 16 bits. + */ + + sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */ + sum += (sum >> 16); /* add carry */ + answer = ~sum; /* ones-complement, then truncate to 16 bits */ + return(answer); +} diff --git a/lib/checksum.h b/lib/checksum.h new file mode 100644 index 0000000..bb5e550 --- /dev/null +++ b/lib/checksum.h @@ -0,0 +1,9 @@ +/* + * Checksum routine for Internet Protocol family headers (C Version). + * + * Refer to "Computing the Internet Checksum" by R. Braden, D. Borman and + * C. Partridge, Computer Communication Review, Vol. 19, No. 2, April 1989, + * pp. 86-101, for additional details on computing this checksum. + */ + +int in_cksum (void *ptr, int nbytes); diff --git a/lib/command.c b/lib/command.c new file mode 100644 index 0000000..b04214e --- /dev/null +++ b/lib/command.c @@ -0,0 +1,3167 @@ +/* Command interpreter routine for virtual terminal [aka TeletYpe] + Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your +option) any later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include + +#include "command.h" +#include "memory.h" +#include "log.h" +#include "version.h" + +/* Command vector which includes some level of command lists. Normally + each daemon maintains each own cmdvec. */ +vector cmdvec; + +/* Host information structure. */ +struct host host; + +/* Default motd string. */ +char *default_motd = +"\r\n\ +Hello, this is zebra (version " ZEBRA_VERSION ").\r\n\ +Copyright 1996-2004 Kunihiro Ishiguro.\r\n\ +\r\n"; + +/* Standard command node structures. */ +struct cmd_node auth_node = +{ + AUTH_NODE, + "Password: ", +}; + +struct cmd_node view_node = +{ + VIEW_NODE, + "%s> ", +}; + +struct cmd_node auth_enable_node = +{ + AUTH_ENABLE_NODE, + "Password: ", +}; + +struct cmd_node enable_node = +{ + ENABLE_NODE, + "%s# ", +}; + +struct cmd_node config_node = +{ + CONFIG_NODE, + "%s(config)# ", + 1 +}; + +/* Utility function to concatenate argv argument into a single string + with inserting ' ' character between each argument. */ +char * +argv_concat (char **argv, int argc, int shift) +{ + int i; + int len; + int index; + char *str; + + str = NULL; + index = 0; + + for (i = shift; i < argc; i++) + { + len = strlen (argv[i]); + + if (i == shift) + { + str = XSTRDUP (MTYPE_TMP, argv[i]); + index = len; + } + else + { + str = XREALLOC (MTYPE_TMP, str, (index + len + 2)); + str[index++] = ' '; + memcpy (str + index, argv[i], len); + index += len; + str[index] = '\0'; + } + } + return str; +} + +/* Install top node of command vector. */ +void +install_node (struct cmd_node *node, + int (*func) (struct vty *)) +{ + vector_set_index (cmdvec, node->node, node); + node->func = func; + node->cmd_vector = vector_init (VECTOR_MIN_SIZE); +} + +/* Compare two command's string. Used in sort_node (). */ +int +cmp_node (const void *p, const void *q) +{ + struct cmd_element *a = *(struct cmd_element **)p; + struct cmd_element *b = *(struct cmd_element **)q; + + return strcmp (a->string, b->string); +} + +int +cmp_desc (const void *p, const void *q) +{ + struct desc *a = *(struct desc **)p; + struct desc *b = *(struct desc **)q; + + return strcmp (a->cmd, b->cmd); +} + +/* Sort each node's command element according to command string. */ +void +sort_node () +{ + int i, j; + struct cmd_node *cnode; + vector descvec; + struct cmd_element *cmd_element; + + for (i = 0; i < vector_max (cmdvec); i++) + if ((cnode = vector_slot (cmdvec, i)) != NULL) + { + vector cmd_vector = cnode->cmd_vector; + qsort (cmd_vector->index, cmd_vector->max, sizeof (void *), cmp_node); + + for (j = 0; j < vector_max (cmd_vector); j++) + if ((cmd_element = vector_slot (cmd_vector, j)) != NULL) + { + descvec = vector_slot (cmd_element->strvec, + vector_max (cmd_element->strvec) - 1); + qsort (descvec->index, descvec->max, sizeof (void *), cmp_desc); + } + } +} + +/* Breaking up string into each command piece. I assume given + character is separated by a space character. Return value is a + vector which includes char ** data element. */ +vector +cmd_make_strvec (char *string) +{ + char *cp, *start, *token; + int strlen; + vector strvec; + + if (string == NULL) + return NULL; + + cp = string; + + /* Skip white spaces. */ + while (isspace ((int) *cp) && *cp != '\0') + cp++; + + /* Return if there is only white spaces */ + if (*cp == '\0') + return NULL; + + if (*cp == '!' || *cp == '#') + return NULL; + + /* Prepare return vector. */ + strvec = vector_init (VECTOR_MIN_SIZE); + + /* Copy each command piece and set into vector. */ + while (1) + { + start = cp; + while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') && + *cp != '\0') + cp++; + strlen = cp - start; + token = XMALLOC (MTYPE_STRVEC, strlen + 1); + memcpy (token, start, strlen); + *(token + strlen) = '\0'; + vector_set (strvec, token); + + while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') && + *cp != '\0') + cp++; + + if (*cp == '\0') + return strvec; + } +} + +/* Free allocated string vector. */ +void +cmd_free_strvec (vector v) +{ + int i; + char *cp; + + if (!v) + return; + + for (i = 0; i < vector_max (v); i++) + if ((cp = vector_slot (v, i)) != NULL) + XFREE (MTYPE_STRVEC, cp); + + vector_free (v); +} + +/* Fetch next description. Used in cmd_make_descvec(). */ +char * +cmd_desc_str (char **string) +{ + char *cp, *start, *token; + int strlen; + + cp = *string; + + if (cp == NULL) + return NULL; + + /* Skip white spaces. */ + while (isspace ((int) *cp) && *cp != '\0') + cp++; + + /* Return if there is only white spaces */ + if (*cp == '\0') + return NULL; + + start = cp; + + while (!(*cp == '\r' || *cp == '\n') && *cp != '\0') + cp++; + + strlen = cp - start; + token = XMALLOC (MTYPE_STRVEC, strlen + 1); + memcpy (token, start, strlen); + *(token + strlen) = '\0'; + + *string = cp; + + return token; +} + +/* New string vector. */ +vector +cmd_make_descvec (char *string, char *descstr) +{ + int multiple = 0; + char *sp; + char *token; + int len; + char *cp; + char *dp; + vector allvec; + vector strvec = NULL; + struct desc *desc; + + cp = string; + dp = descstr; + + if (cp == NULL) + return NULL; + + allvec = vector_init (VECTOR_MIN_SIZE); + + while (1) + { + while (isspace ((int) *cp) && *cp != '\0') + cp++; + + if (*cp == '(') + { + multiple = 1; + cp++; + } + if (*cp == ')') + { + multiple = 0; + cp++; + } + if (*cp == '|') + { + if (! multiple) + { + fprintf (stderr, "Command parse error!: %s\n", string); + exit (1); + } + cp++; + } + + while (isspace ((int) *cp) && *cp != '\0') + cp++; + + if (*cp == '(') + { + multiple = 1; + cp++; + } + + if (*cp == '\0') + return allvec; + + sp = cp; + + while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0') + cp++; + + len = cp - sp; + + token = XMALLOC (MTYPE_STRVEC, len + 1); + memcpy (token, sp, len); + *(token + len) = '\0'; + + desc = XCALLOC (MTYPE_DESC, sizeof (struct desc)); + desc->cmd = token; + desc->str = cmd_desc_str (&dp); + + if (multiple) + { + if (multiple == 1) + { + strvec = vector_init (VECTOR_MIN_SIZE); + vector_set (allvec, strvec); + } + multiple++; + } + else + { + strvec = vector_init (VECTOR_MIN_SIZE); + vector_set (allvec, strvec); + } + vector_set (strvec, desc); + } +} + +/* Count mandantory string vector size. This is to determine inputed + command has enough command length. */ +int +cmd_cmdsize (vector strvec) +{ + int i; + char *str; + int size = 0; + vector descvec; + + for (i = 0; i < vector_max (strvec); i++) + { + descvec = vector_slot (strvec, i); + + if (vector_max (descvec) == 1) + { + struct desc *desc = vector_slot (descvec, 0); + + str = desc->cmd; + + if (str == NULL || CMD_OPTION (str)) + return size; + else + size++; + } + else + size++; + } + return size; +} + +/* Return prompt character of specified node. */ +char * +cmd_prompt (enum node_type node) +{ + struct cmd_node *cnode; + + cnode = vector_slot (cmdvec, node); + return cnode->prompt; +} + +/* Install a command into a node. */ +void +install_element (enum node_type ntype, struct cmd_element *cmd) +{ + struct cmd_node *cnode; + + cnode = vector_slot (cmdvec, ntype); + + if (cnode == NULL) + { + fprintf (stderr, "Command node %d doesn't exist, please check it\n", + ntype); + exit (1); + } + + vector_set (cnode->cmd_vector, cmd); + + cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc); + cmd->cmdsize = cmd_cmdsize (cmd->strvec); +} + +static unsigned char itoa64[] = +"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void +to64(char *s, long v, int n) +{ + while (--n >= 0) + { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } +} + +char *zencrypt (char *passwd) +{ + char salt[6]; + struct timeval tv; + char *crypt (const char *, const char *); + + gettimeofday(&tv,0); + + to64(&salt[0], random(), 3); + to64(&salt[3], tv.tv_usec, 3); + salt[5] = '\0'; + + return crypt (passwd, salt); +} + +char * +syslog_facility_print (int facility) +{ + switch (facility) + { + case LOG_KERN: + return "kern"; + break; + case LOG_USER: + return "user"; + break; + case LOG_MAIL: + return "mail"; + break; + case LOG_DAEMON: + return "daemon"; + break; + case LOG_AUTH: + return "auth"; + break; + case LOG_SYSLOG: + return "syslog"; + break; + case LOG_LPR: + return "lpr"; + break; + case LOG_NEWS: + return "news"; + break; + case LOG_UUCP: + return "uucp"; + break; + case LOG_CRON: + return "cron"; + break; + case LOG_LOCAL0: + return "local0"; + break; + case LOG_LOCAL1: + return "local1"; + break; + case LOG_LOCAL2: + return "local2"; + break; + case LOG_LOCAL3: + return "local3"; + break; + case LOG_LOCAL4: + return "local4"; + break; + case LOG_LOCAL5: + return "local5"; + break; + case LOG_LOCAL6: + return "local6"; + break; + case LOG_LOCAL7: + return "local7"; + break; + default: + break; + } + return ""; +} + +/* This function write configuration of this host. */ +int +config_write_host (struct vty *vty) +{ + if (host.name) + vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE); + + if (host.encrypt) + { + if (host.password_encrypt) + vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE); + if (host.enable_encrypt) + vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE); + } + else + { + if (host.password) + vty_out (vty, "password %s%s", host.password, VTY_NEWLINE); + else if (host.password_encrypt) + vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE); + + if (host.enable) + vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE); + else if (host.enable_encrypt) + vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE); + } + + if (host.logfile) + vty_out (vty, "log file %s%s", host.logfile, VTY_NEWLINE); + + if (host.log_stdout) + vty_out (vty, "log stdout%s", VTY_NEWLINE); + + if (host.log_syslog) + { + vty_out (vty, "log syslog"); + if (zlog_default->facility != LOG_DAEMON) + vty_out (vty, " facility %s", syslog_facility_print (zlog_default->facility)); + vty_out (vty, "%s", VTY_NEWLINE); + } + if (zlog_default->maskpri != LOG_DEBUG) + vty_out (vty, "log trap %s%s", zlog_priority[zlog_default->maskpri], VTY_NEWLINE); + + if (zlog_default->record_priority == 1) + vty_out (vty, "log record-priority%s", VTY_NEWLINE); + + if (host.advanced) + vty_out (vty, "service advanced-vty%s", VTY_NEWLINE); + + if (host.encrypt) + vty_out (vty, "service password-encryption%s", VTY_NEWLINE); + + if (host.lines >= 0) + vty_out (vty, "service terminal-length %d%s", host.lines, + VTY_NEWLINE); + + if (! host.motd) + vty_out (vty, "no banner motd%s", VTY_NEWLINE); + + return 1; +} + +/* Utility function for getting command vector. */ +vector +cmd_node_vector (vector v, enum node_type ntype) +{ + struct cmd_node *cnode = vector_slot (v, ntype); + return cnode->cmd_vector; +} + +/* Filter command vector by symbol */ +int +cmd_filter_by_symbol (char *command, char *symbol) +{ + int i, lim; + + if (strcmp (symbol, "IPV4_ADDRESS") == 0) + { + i = 0; + lim = strlen (command); + while (i < lim) + { + if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/')) + return 1; + i++; + } + return 0; + } + if (strcmp (symbol, "STRING") == 0) + { + i = 0; + lim = strlen (command); + while (i < lim) + { + if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-')) + return 1; + i++; + } + return 0; + } + if (strcmp (symbol, "IFNAME") == 0) + { + i = 0; + lim = strlen (command); + while (i < lim) + { + if (! isalnum ((int) command[i])) + return 1; + i++; + } + return 0; + } + return 0; +} + +/* Completion match types. */ +enum match_type +{ + no_match, + extend_match, + ipv4_prefix_match, + ipv4_match, + ipv6_prefix_match, + ipv6_match, + range_match, + vararg_match, + partly_match, + exact_match +}; + +enum match_type +cmd_ipv4_match (char *str) +{ + char *sp; + int dots = 0, nums = 0; + char buf[4]; + + if (str == NULL) + return partly_match; + + for (;;) + { + memset (buf, 0, sizeof (buf)); + sp = str; + while (*str != '\0') + { + if (*str == '.') + { + if (dots >= 3) + return no_match; + + if (*(str + 1) == '.') + return no_match; + + if (*(str + 1) == '\0') + return partly_match; + + dots++; + break; + } + if (!isdigit ((int) *str)) + return no_match; + + str++; + } + + if (str - sp > 3) + return no_match; + + strncpy (buf, sp, str - sp); + if (atoi (buf) > 255) + return no_match; + + nums++; + + if (*str == '\0') + break; + + str++; + } + + if (nums < 4) + return partly_match; + + return exact_match; +} + +enum match_type +cmd_ipv4_prefix_match (char *str) +{ + char *sp; + int dots = 0; + char buf[4]; + + if (str == NULL) + return partly_match; + + for (;;) + { + memset (buf, 0, sizeof (buf)); + sp = str; + while (*str != '\0' && *str != '/') + { + if (*str == '.') + { + if (dots == 3) + return no_match; + + if (*(str + 1) == '.' || *(str + 1) == '/') + return no_match; + + if (*(str + 1) == '\0') + return partly_match; + + dots++; + break; + } + + if (!isdigit ((int) *str)) + return no_match; + + str++; + } + + if (str - sp > 3) + return no_match; + + strncpy (buf, sp, str - sp); + if (atoi (buf) > 255) + return no_match; + + if (dots == 3) + { + if (*str == '/') + { + if (*(str + 1) == '\0') + return partly_match; + + str++; + break; + } + else if (*str == '\0') + return partly_match; + } + + if (*str == '\0') + return partly_match; + + str++; + } + + sp = str; + while (*str != '\0') + { + if (!isdigit ((int) *str)) + return no_match; + + str++; + } + + if (atoi (sp) > 32) + return no_match; + + return exact_match; +} + +#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%" +#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/" +#define STATE_START 1 +#define STATE_COLON 2 +#define STATE_DOUBLE 3 +#define STATE_ADDR 4 +#define STATE_DOT 5 +#define STATE_SLASH 6 +#define STATE_MASK 7 + +enum match_type +cmd_ipv6_match (char *str) +{ + int state = STATE_START; + int colons = 0, nums = 0, double_colon = 0; + char *sp = NULL; + + if (str == NULL) + return partly_match; + + if (strspn (str, IPV6_ADDR_STR) != strlen (str)) + return no_match; + + while (*str != '\0') + { + switch (state) + { + case STATE_START: + if (*str == ':') + { + if (*(str + 1) != ':' && *(str + 1) != '\0') + return no_match; + colons--; + state = STATE_COLON; + } + else + { + sp = str; + state = STATE_ADDR; + } + + continue; + case STATE_COLON: + colons++; + if (*(str + 1) == ':') + state = STATE_DOUBLE; + else + { + sp = str + 1; + state = STATE_ADDR; + } + break; + case STATE_DOUBLE: + if (double_colon) + return no_match; + + if (*(str + 1) == ':') + return no_match; + else + { + if (*(str + 1) != '\0') + colons++; + sp = str + 1; + state = STATE_ADDR; + } + + double_colon++; + nums++; + break; + case STATE_ADDR: + if (*(str + 1) == ':' || *(str + 1) == '\0') + { + if (str - sp > 3) + return no_match; + + nums++; + state = STATE_COLON; + } + if (*(str + 1) == '.') + state = STATE_DOT; + break; + case STATE_DOT: + state = STATE_ADDR; + break; + default: + break; + } + + if (nums > 8) + return no_match; + + if (colons > 7) + return no_match; + + str++; + } + +#if 0 + if (nums < 11) + return partly_match; +#endif /* 0 */ + + return exact_match; +} + +enum match_type +cmd_ipv6_prefix_match (char *str) +{ + int state = STATE_START; + int colons = 0, nums = 0, double_colon = 0; + int mask; + char *sp = NULL; + char *endptr = NULL; + + if (str == NULL) + return partly_match; + + if (strspn (str, IPV6_PREFIX_STR) != strlen (str)) + return no_match; + + while (*str != '\0' && state != STATE_MASK) + { + switch (state) + { + case STATE_START: + if (*str == ':') + { + if (*(str + 1) != ':' && *(str + 1) != '\0') + return no_match; + colons--; + state = STATE_COLON; + } + else + { + sp = str; + state = STATE_ADDR; + } + + continue; + case STATE_COLON: + colons++; + if (*(str + 1) == '/') + return no_match; + else if (*(str + 1) == ':') + state = STATE_DOUBLE; + else + { + sp = str + 1; + state = STATE_ADDR; + } + break; + case STATE_DOUBLE: + if (double_colon) + return no_match; + + if (*(str + 1) == ':') + return no_match; + else + { + if (*(str + 1) != '\0' && *(str + 1) != '/') + colons++; + sp = str + 1; + + if (*(str + 1) == '/') + state = STATE_SLASH; + else + state = STATE_ADDR; + } + + double_colon++; + nums += 1; + break; + case STATE_ADDR: + if (*(str + 1) == ':' || *(str + 1) == '.' + || *(str + 1) == '\0' || *(str + 1) == '/') + { + if (str - sp > 3) + return no_match; + + for (; sp <= str; sp++) + if (*sp == '/') + return no_match; + + nums++; + + if (*(str + 1) == ':') + state = STATE_COLON; + else if (*(str + 1) == '.') + state = STATE_DOT; + else if (*(str + 1) == '/') + state = STATE_SLASH; + } + break; + case STATE_DOT: + state = STATE_ADDR; + break; + case STATE_SLASH: + if (*(str + 1) == '\0') + return partly_match; + + state = STATE_MASK; + break; + default: + break; + } + + if (nums > 11) + return no_match; + + if (colons > 7) + return no_match; + + str++; + } + + if (state < STATE_MASK) + return partly_match; + + mask = strtol (str, &endptr, 10); + if (*endptr != '\0') + return no_match; + + if (mask < 0 || mask > 128) + return no_match; + +/* I don't know why mask < 13 makes command match partly. + Forgive me to make this comments. I Want to set static default route + because of lack of function to originate default in ospf6d; sorry + yasu + if (mask < 13) + return partly_match; +*/ + + return exact_match; +} + +#define DECIMAL_STRLEN_MAX 10 + +int +cmd_range_match (char *range, char *str) +{ + char *p; + char buf[DECIMAL_STRLEN_MAX + 1]; + char *endptr = NULL; + unsigned long min, max, val; + + if (str == NULL) + return 1; + + val = strtoul (str, &endptr, 10); + if (*endptr != '\0') + return 0; + + range++; + p = strchr (range, '-'); + if (p == NULL) + return 0; + if (p - range > DECIMAL_STRLEN_MAX) + return 0; + strncpy (buf, range, p - range); + buf[p - range] = '\0'; + min = strtoul (buf, &endptr, 10); + if (*endptr != '\0') + return 0; + + range = p + 1; + p = strchr (range, '>'); + if (p == NULL) + return 0; + if (p - range > DECIMAL_STRLEN_MAX) + return 0; + strncpy (buf, range, p - range); + buf[p - range] = '\0'; + max = strtoul (buf, &endptr, 10); + if (*endptr != '\0') + return 0; + + if (val < min || val > max) + return 0; + + return 1; +} + +/* Make completion match and return match type flag. */ +enum match_type +cmd_filter_by_completion (char *command, vector v, int index) +{ + int i; + char *str; + struct cmd_element *cmd_element; + enum match_type match_type; + vector descvec; + struct desc *desc; + + match_type = no_match; + + /* If command and cmd_element string does not match set NULL to vector */ + for (i = 0; i < vector_max (v); i++) + if ((cmd_element = vector_slot (v, i)) != NULL) + { + if (index >= vector_max (cmd_element->strvec)) + vector_slot (v, i) = NULL; + else + { + int j; + int matched = 0; + + descvec = vector_slot (cmd_element->strvec, index); + + for (j = 0; j < vector_max (descvec); j++) + { + desc = vector_slot (descvec, j); + str = desc->cmd; + + if (CMD_VARARG (str)) + { + if (match_type < vararg_match) + match_type = vararg_match; + matched++; + } + else if (CMD_RANGE (str)) + { + if (cmd_range_match (str, command)) + { + if (match_type < range_match) + match_type = range_match; + + matched++; + } + } + else if (CMD_IPV6 (str)) + { + if (cmd_ipv6_match (command)) + { + if (match_type < ipv6_match) + match_type = ipv6_match; + + matched++; + } + } + else if (CMD_IPV6_PREFIX (str)) + { + if (cmd_ipv6_prefix_match (command)) + { + if (match_type < ipv6_prefix_match) + match_type = ipv6_prefix_match; + + matched++; + } + } + else if (CMD_IPV4 (str)) + { + if (cmd_ipv4_match (command)) + { + if (match_type < ipv4_match) + match_type = ipv4_match; + + matched++; + } + } + else if (CMD_IPV4_PREFIX (str)) + { + if (cmd_ipv4_prefix_match (command)) + { + if (match_type < ipv4_prefix_match) + match_type = ipv4_prefix_match; + matched++; + } + } + else + /* Check is this point's argument optional ? */ + if (CMD_OPTION (str) || CMD_VARIABLE (str)) + { + if (match_type < extend_match) + match_type = extend_match; + matched++; + } + else if (strncmp (command, str, strlen (command)) == 0) + { + if (strcmp (command, str) == 0) + match_type = exact_match; + else + { + if (match_type < partly_match) + match_type = partly_match; + } + matched++; + } + } + if (! matched) + vector_slot (v, i) = NULL; + } + } + return match_type; +} + +/* Filter vector by command character with index. */ +enum match_type +cmd_filter_by_string (char *command, vector v, int index) +{ + int i; + char *str; + struct cmd_element *cmd_element; + enum match_type match_type; + vector descvec; + struct desc *desc; + + match_type = no_match; + + /* If command and cmd_element string does not match set NULL to vector */ + for (i = 0; i < vector_max (v); i++) + if ((cmd_element = vector_slot (v, i)) != NULL) + { + /* If given index is bigger than max string vector of command, + set NULL*/ + if (index >= vector_max (cmd_element->strvec)) + vector_slot (v, i) = NULL; + else + { + int j; + int matched = 0; + + descvec = vector_slot (cmd_element->strvec, index); + + for (j = 0; j < vector_max (descvec); j++) + { + desc = vector_slot (descvec, j); + str = desc->cmd; + + if (CMD_VARARG (str)) + { + if (match_type < vararg_match) + match_type = vararg_match; + matched++; + } + else if (CMD_RANGE (str)) + { + if (cmd_range_match (str, command)) + { + if (match_type < range_match) + match_type = range_match; + matched++; + } + } + else if (CMD_IPV6 (str)) + { + if (cmd_ipv6_match (command) == exact_match) + { + if (match_type < ipv6_match) + match_type = ipv6_match; + matched++; + } + } + else if (CMD_IPV6_PREFIX (str)) + { + if (cmd_ipv6_prefix_match (command) == exact_match) + { + if (match_type < ipv6_prefix_match) + match_type = ipv6_prefix_match; + matched++; + } + } + else if (CMD_IPV4 (str)) + { + if (cmd_ipv4_match (command) == exact_match) + { + if (match_type < ipv4_match) + match_type = ipv4_match; + matched++; + } + } + else if (CMD_IPV4_PREFIX (str)) + { + if (cmd_ipv4_prefix_match (command) == exact_match) + { + if (match_type < ipv4_prefix_match) + match_type = ipv4_prefix_match; + matched++; + } + } + else if (CMD_OPTION (str) || CMD_VARIABLE (str)) + { + if (match_type < extend_match) + match_type = extend_match; + matched++; + } + else + { + if (strcmp (command, str) == 0) + { + match_type = exact_match; + matched++; + } + } + } + if (! matched) + vector_slot (v, i) = NULL; + } + } + return match_type; +} + +/* Check ambiguous match */ +int +is_cmd_ambiguous (char *command, vector v, int index, enum match_type type) +{ + int i; + int j; + char *str = NULL; + struct cmd_element *cmd_element; + char *matched = NULL; + vector descvec; + struct desc *desc; + + for (i = 0; i < vector_max (v); i++) + if ((cmd_element = vector_slot (v, i)) != NULL) + { + int match = 0; + + descvec = vector_slot (cmd_element->strvec, index); + + for (j = 0; j < vector_max (descvec); j++) + { + enum match_type ret; + + desc = vector_slot (descvec, j); + str = desc->cmd; + + switch (type) + { + case exact_match: + if (! (CMD_OPTION (str) || CMD_VARIABLE (str)) + && strcmp (command, str) == 0) + match++; + break; + case partly_match: + if (! (CMD_OPTION (str) || CMD_VARIABLE (str)) + && strncmp (command, str, strlen (command)) == 0) + { + if (matched && strcmp (matched, str) != 0) + return 1; /* There is ambiguous match. */ + else + matched = str; + match++; + } + break; + case range_match: + if (cmd_range_match (str, command)) + { + if (matched && strcmp (matched, str) != 0) + return 1; + else + matched = str; + match++; + } + break; + case ipv6_match: + if (CMD_IPV6 (str)) + match++; + break; + case ipv6_prefix_match: + if ((ret = cmd_ipv6_prefix_match (command)) != no_match) + { + if (ret == partly_match) + return 2; /* There is incomplete match. */ + + match++; + } + break; + case ipv4_match: + if (CMD_IPV4 (str)) + match++; + break; + case ipv4_prefix_match: + if ((ret = cmd_ipv4_prefix_match (command)) != no_match) + { + if (ret == partly_match) + return 2; /* There is incomplete match. */ + + match++; + } + break; + case extend_match: + if (CMD_OPTION (str) || CMD_VARIABLE (str)) + match++; + break; + case no_match: + default: + break; + } + } + if (! match) + vector_slot (v, i) = NULL; + } + return 0; +} + +/* If src matches dst return dst string, otherwise return NULL */ +char * +cmd_entry_function (char *src, char *dst) +{ + /* Skip variable arguments. */ + if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) || + CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst)) + return NULL; + + /* In case of 'command \t', given src is NULL string. */ + if (src == NULL) + return dst; + + /* Matched with input string. */ + if (strncmp (src, dst, strlen (src)) == 0) + return dst; + + return NULL; +} + +/* If src matches dst return dst string, otherwise return NULL */ +/* This version will return the dst string always if it is + CMD_VARIABLE for '?' key processing */ +char * +cmd_entry_function_desc (char *src, char *dst) +{ + if (CMD_VARARG (dst)) + return dst; + + if (CMD_RANGE (dst)) + { + if (cmd_range_match (dst, src)) + return dst; + else + return NULL; + } + + if (CMD_IPV6 (dst)) + { + if (cmd_ipv6_match (src)) + return dst; + else + return NULL; + } + + if (CMD_IPV6_PREFIX (dst)) + { + if (cmd_ipv6_prefix_match (src)) + return dst; + else + return NULL; + } + + if (CMD_IPV4 (dst)) + { + if (cmd_ipv4_match (src)) + return dst; + else + return NULL; + } + + if (CMD_IPV4_PREFIX (dst)) + { + if (cmd_ipv4_prefix_match (src)) + return dst; + else + return NULL; + } + + /* Optional or variable commands always match on '?' */ + if (CMD_OPTION (dst) || CMD_VARIABLE (dst)) + return dst; + + /* In case of 'command \t', given src is NULL string. */ + if (src == NULL) + return dst; + + if (strncmp (src, dst, strlen (src)) == 0) + return dst; + else + return NULL; +} + +/* Check same string element existence. If it isn't there return + 1. */ +int +cmd_unique_string (vector v, char *str) +{ + int i; + char *match; + + for (i = 0; i < vector_max (v); i++) + if ((match = vector_slot (v, i)) != NULL) + if (strcmp (match, str) == 0) + return 0; + return 1; +} + +/* Compare string to description vector. If there is same string + return 1 else return 0. */ +int +desc_unique_string (vector v, char *str) +{ + int i; + struct desc *desc; + + for (i = 0; i < vector_max (v); i++) + if ((desc = vector_slot (v, i)) != NULL) + if (strcmp (desc->cmd, str) == 0) + return 1; + return 0; +} + +/* '?' describe command support. */ +vector +cmd_describe_command (vector vline, struct vty *vty, int *status) +{ + int i; + vector cmd_vector; +#define INIT_MATCHVEC_SIZE 10 + vector matchvec; + struct cmd_element *cmd_element; + int index; + int ret; + enum match_type match; + char *command; + static struct desc desc_cr = { "", "" }; + + /* Set index. */ + index = vector_max (vline) - 1; + + /* Make copy vector of current node's command vector. */ + cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); + + /* Prepare match vector */ + matchvec = vector_init (INIT_MATCHVEC_SIZE); + + /* Filter commands. */ + /* Only words precedes current word will be checked in this loop. */ + for (i = 0; i < index; i++) + { + command = vector_slot (vline, i); + match = cmd_filter_by_completion (command, cmd_vector, i); + + if (match == vararg_match) + { + struct cmd_element *cmd_element; + vector descvec; + int j, k; + + for (j = 0; j < vector_max (cmd_vector); j++) + if ((cmd_element = vector_slot (cmd_vector, j)) != NULL) + { + descvec = vector_slot (cmd_element->strvec, + vector_max (cmd_element->strvec) - 1); + for (k = 0; k < vector_max (descvec); k++) + { + struct desc *desc = vector_slot (descvec, k); + vector_set (matchvec, desc); + } + } + + vector_set (matchvec, &desc_cr); + vector_free (cmd_vector); + + return matchvec; + } + + if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1) + { + vector_free (cmd_vector); + *status = CMD_ERR_AMBIGUOUS; + return NULL; + } + else if (ret == 2) + { + vector_free (cmd_vector); + *status = CMD_ERR_NO_MATCH; + return NULL; + } + } + + /* Prepare match vector */ + /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */ + + /* Make sure that cmd_vector is filtered based on current word */ + command = vector_slot (vline, index); + if (command) + match = cmd_filter_by_completion (command, cmd_vector, index); + + /* Make description vector. */ + for (i = 0; i < vector_max (cmd_vector); i++) + if ((cmd_element = vector_slot (cmd_vector, i)) != NULL) + { + char *string = NULL; + vector strvec = cmd_element->strvec; + + /* if command is NULL, index may be equal to vector_max */ + if (command && index >= vector_max (strvec)) + vector_slot (cmd_vector, i) = NULL; + else + { + /* Check if command is completed. */ + if (command == NULL && index == vector_max (strvec)) + { + string = ""; + if (! desc_unique_string (matchvec, string)) + vector_set (matchvec, &desc_cr); + } + else + { + int j; + vector descvec = vector_slot (strvec, index); + struct desc *desc; + + for (j = 0; j < vector_max (descvec); j++) + { + desc = vector_slot (descvec, j); + string = cmd_entry_function_desc (command, desc->cmd); + if (string) + { + /* Uniqueness check */ + if (! desc_unique_string (matchvec, string)) + vector_set (matchvec, desc); + } + } + } + } + } + vector_free (cmd_vector); + + if (vector_slot (matchvec, 0) == NULL) + { + vector_free (matchvec); + *status= CMD_ERR_NO_MATCH; + } + else + *status = CMD_SUCCESS; + + return matchvec; +} + +/* Check LCD of matched command. */ +int +cmd_lcd (char **matched) +{ + int i; + int j; + int lcd = -1; + char *s1, *s2; + char c1, c2; + + if (matched[0] == NULL || matched[1] == NULL) + return 0; + + for (i = 1; matched[i] != NULL; i++) + { + s1 = matched[i - 1]; + s2 = matched[i]; + + for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++) + if (c1 != c2) + break; + + if (lcd < 0) + lcd = j; + else + { + if (lcd > j) + lcd = j; + } + } + return lcd; +} + +/* Command line completion support. */ +char ** +cmd_complete_command (vector vline, struct vty *vty, int *status) +{ + int i; + vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); +#define INIT_MATCHVEC_SIZE 10 + vector matchvec; + struct cmd_element *cmd_element; + int index = vector_max (vline) - 1; + char **match_str; + struct desc *desc; + vector descvec; + char *command; + int lcd; + + /* First, filter by preceeding command string */ + for (i = 0; i < index; i++) + { + enum match_type match; + int ret; + + command = vector_slot (vline, i); + + /* First try completion match, if there is exactly match return 1 */ + match = cmd_filter_by_completion (command, cmd_vector, i); + + /* If there is exact match then filter ambiguous match else check + ambiguousness. */ + if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1) + { + vector_free (cmd_vector); + *status = CMD_ERR_AMBIGUOUS; + return NULL; + } + /* + else if (ret == 2) + { + vector_free (cmd_vector); + *status = CMD_ERR_NO_MATCH; + return NULL; + } + */ + } + + /* Prepare match vector. */ + matchvec = vector_init (INIT_MATCHVEC_SIZE); + + /* Now we got into completion */ + for (i = 0; i < vector_max (cmd_vector); i++) + if ((cmd_element = vector_slot (cmd_vector, i)) != NULL) + { + char *string; + vector strvec = cmd_element->strvec; + + /* Check field length */ + if (index >= vector_max (strvec)) + vector_slot (cmd_vector, i) = NULL; + else + { + int j; + + descvec = vector_slot (strvec, index); + for (j = 0; j < vector_max (descvec); j++) + { + desc = vector_slot (descvec, j); + + if ((string = cmd_entry_function (vector_slot (vline, index), + desc->cmd))) + if (cmd_unique_string (matchvec, string)) + vector_set (matchvec, XSTRDUP (MTYPE_TMP, string)); + } + } + } + + /* We don't need cmd_vector any more. */ + vector_free (cmd_vector); + + /* No matched command */ + if (vector_slot (matchvec, 0) == NULL) + { + vector_free (matchvec); + + /* In case of 'command \t' pattern. Do you need '?' command at + the end of the line. */ + if (vector_slot (vline, index) == '\0') + *status = CMD_ERR_NOTHING_TODO; + else + *status = CMD_ERR_NO_MATCH; + return NULL; + } + + /* Only one matched */ + if (vector_slot (matchvec, 1) == NULL) + { + match_str = (char **) matchvec->index; + vector_only_wrapper_free (matchvec); + *status = CMD_COMPLETE_FULL_MATCH; + return match_str; + } + /* Make it sure last element is NULL. */ + vector_set (matchvec, NULL); + + /* Check LCD of matched strings. */ + if (vector_slot (vline, index) != NULL) + { + lcd = cmd_lcd ((char **) matchvec->index); + + if (lcd) + { + int len = strlen (vector_slot (vline, index)); + + if (len < lcd) + { + char *lcdstr; + + lcdstr = XMALLOC (MTYPE_TMP, lcd + 1); + memcpy (lcdstr, matchvec->index[0], lcd); + lcdstr[lcd] = '\0'; + + /* match_str = (char **) &lcdstr; */ + + /* Free matchvec. */ + for (i = 0; i < vector_max (matchvec); i++) + { + if (vector_slot (matchvec, i)) + XFREE (MTYPE_TMP, vector_slot (matchvec, i)); + } + vector_free (matchvec); + + /* Make new matchvec. */ + matchvec = vector_init (INIT_MATCHVEC_SIZE); + vector_set (matchvec, lcdstr); + match_str = (char **) matchvec->index; + vector_only_wrapper_free (matchvec); + + *status = CMD_COMPLETE_MATCH; + return match_str; + } + } + } + + match_str = (char **) matchvec->index; + vector_only_wrapper_free (matchvec); + *status = CMD_COMPLETE_LIST_MATCH; + return match_str; +} + +/* Execute command by argument vline vector. */ +int +cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd) +{ + int i; + int index; + vector cmd_vector; + struct cmd_element *cmd_element; + struct cmd_element *matched_element; + unsigned int matched_count, incomplete_count; + int argc; + char *argv[CMD_ARGC_MAX]; + enum match_type match = 0; + int varflag; + char *command; + + /* Make copy of command elements. */ + cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); + + for (index = 0; index < vector_max (vline); index++) + { + int ret; + + command = vector_slot (vline, index); + + match = cmd_filter_by_completion (command, cmd_vector, index); + + if (match == vararg_match) + break; + + ret = is_cmd_ambiguous (command, cmd_vector, index, match); + + if (ret == 1) + { + vector_free (cmd_vector); + return CMD_ERR_AMBIGUOUS; + } + else if (ret == 2) + { + vector_free (cmd_vector); + return CMD_ERR_NO_MATCH; + } + } + + /* Check matched count. */ + matched_element = NULL; + matched_count = 0; + incomplete_count = 0; + + for (i = 0; i < vector_max (cmd_vector); i++) + if (vector_slot (cmd_vector,i) != NULL) + { + cmd_element = vector_slot (cmd_vector,i); + + if (match == vararg_match || index >= cmd_element->cmdsize) + { + matched_element = cmd_element; +#if 0 + printf ("DEBUG: %s\n", cmd_element->string); +#endif + matched_count++; + } + else + { + incomplete_count++; + } + } + + /* Finish of using cmd_vector. */ + vector_free (cmd_vector); + + /* To execute command, matched_count must be 1.*/ + if (matched_count == 0) + { + if (incomplete_count) + return CMD_ERR_INCOMPLETE; + else + return CMD_ERR_NO_MATCH; + } + + if (matched_count > 1) + return CMD_ERR_AMBIGUOUS; + + /* Argument treatment */ + varflag = 0; + argc = 0; + + for (i = 0; i < vector_max (vline); i++) + { + if (varflag) + argv[argc++] = vector_slot (vline, i); + else + { + vector descvec = vector_slot (matched_element->strvec, i); + + if (vector_max (descvec) == 1) + { + struct desc *desc = vector_slot (descvec, 0); + char *str = desc->cmd; + + if (CMD_VARARG (str)) + varflag = 1; + + if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str)) + argv[argc++] = vector_slot (vline, i); + } + else + argv[argc++] = vector_slot (vline, i); + } + + if (argc >= CMD_ARGC_MAX) + return CMD_ERR_EXEED_ARGC_MAX; + } + + /* For vtysh execution. */ + if (cmd) + *cmd = matched_element; + + if (matched_element->daemon) + return CMD_SUCCESS_DAEMON; + + /* Execute matched command. */ + return (*matched_element->func) (matched_element, vty, argc, argv); +} + +/* Execute command by argument readline. */ +int +cmd_execute_command_strict (vector vline, struct vty *vty, + struct cmd_element **cmd) +{ + int i; + int index; + vector cmd_vector; + struct cmd_element *cmd_element; + struct cmd_element *matched_element; + unsigned int matched_count, incomplete_count; + int argc; + char *argv[CMD_ARGC_MAX]; + int varflag; + enum match_type match = 0; + char *command; + + /* Make copy of command element */ + cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); + + for (index = 0; index < vector_max (vline); index++) + { + int ret; + + command = vector_slot (vline, index); + + match = cmd_filter_by_string (vector_slot (vline, index), + cmd_vector, index); + + /* If command meets '.VARARG' then finish matching. */ + if (match == vararg_match) + break; + + ret = is_cmd_ambiguous (command, cmd_vector, index, match); + if (ret == 1) + { + vector_free (cmd_vector); + return CMD_ERR_AMBIGUOUS; + } + if (ret == 2) + { + vector_free (cmd_vector); + return CMD_ERR_NO_MATCH; + } + } + + /* Check matched count. */ + matched_element = NULL; + matched_count = 0; + incomplete_count = 0; + for (i = 0; i < vector_max (cmd_vector); i++) + if (vector_slot (cmd_vector,i) != NULL) + { + cmd_element = vector_slot (cmd_vector,i); + + if (match == vararg_match || index >= cmd_element->cmdsize) + { + matched_element = cmd_element; + matched_count++; + } + else + incomplete_count++; + } + + /* Finish of using cmd_vector. */ + vector_free (cmd_vector); + + /* To execute command, matched_count must be 1.*/ + if (matched_count == 0) + { + if (incomplete_count) + return CMD_ERR_INCOMPLETE; + else + return CMD_ERR_NO_MATCH; + } + + if (matched_count > 1) + return CMD_ERR_AMBIGUOUS; + + /* Argument treatment */ + varflag = 0; + argc = 0; + + for (i = 0; i < vector_max (vline); i++) + { + if (varflag) + argv[argc++] = vector_slot (vline, i); + else + { + vector descvec = vector_slot (matched_element->strvec, i); + + if (vector_max (descvec) == 1) + { + struct desc *desc = vector_slot (descvec, 0); + char *str = desc->cmd; + + if (CMD_VARARG (str)) + varflag = 1; + + if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str)) + argv[argc++] = vector_slot (vline, i); + } + else + argv[argc++] = vector_slot (vline, i); + } + + if (argc >= CMD_ARGC_MAX) + return CMD_ERR_EXEED_ARGC_MAX; + } + + /* For vtysh execution. */ + if (cmd) + *cmd = matched_element; + + if (matched_element->daemon) + return CMD_SUCCESS_DAEMON; + + /* Now execute matched command */ + return (*matched_element->func) (matched_element, vty, argc, argv); +} + +/* Configration make from file. */ +int +config_from_file (struct vty *vty, FILE *fp) +{ + int ret; + vector vline; + + while (fgets (vty->buf, VTY_BUFSIZ, fp)) + { + vline = cmd_make_strvec (vty->buf); + + /* In case of comment line */ + if (vline == NULL) + continue; + /* Execute configuration command : this is strict match */ + ret = cmd_execute_command_strict (vline, vty, NULL); + + /* Try again with setting node to CONFIG_NODE */ + if (ret != CMD_SUCCESS && ret != CMD_WARNING) + { + if (vty->node == KEYCHAIN_KEY_NODE) + { + vty->node = KEYCHAIN_NODE; + + ret = cmd_execute_command_strict (vline, vty, NULL); + + if (ret != CMD_SUCCESS && ret != CMD_WARNING) + { + vty->node = CONFIG_NODE; + ret = cmd_execute_command_strict (vline, vty, NULL); + } + } + else + { + vty->node = CONFIG_NODE; + ret = cmd_execute_command_strict (vline, vty, NULL); + } + } + + cmd_free_strvec (vline); + + if (ret != CMD_SUCCESS && ret != CMD_WARNING) + return ret; + } + return CMD_SUCCESS; +} + +/* Configration from terminal */ +DEFUN (config_terminal, + config_terminal_cmd, + "configure terminal", + "Configuration from vty interface\n" + "Configuration terminal\n") +{ + if (vty_config_lock (vty)) + vty->node = CONFIG_NODE; + else + { + vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +/* Enable command */ +DEFUN (enable, + config_enable_cmd, + "enable", + "Turn on privileged mode command\n") +{ + /* If enable password is NULL, change to ENABLE_NODE */ + if ((host.enable == NULL && host.enable_encrypt == NULL) || + vty->type == VTY_SHELL_SERV) + vty->node = ENABLE_NODE; + else + vty->node = AUTH_ENABLE_NODE; + + return CMD_SUCCESS; +} + +/* Disable command */ +DEFUN (disable, + config_disable_cmd, + "disable", + "Turn off privileged mode command\n") +{ + if (vty->node == ENABLE_NODE) + vty->node = VIEW_NODE; + return CMD_SUCCESS; +} + +/* Down vty node level. */ +DEFUN (config_exit, + config_exit_cmd, + "exit", + "Exit current mode and down to previous mode\n") +{ + switch (vty->node) + { + case VIEW_NODE: + case ENABLE_NODE: + if (vty_shell (vty)) + exit (0); + else + vty->status = VTY_CLOSE; + break; + case CONFIG_NODE: + vty->node = ENABLE_NODE; + vty_config_unlock (vty); + break; + case INTERFACE_NODE: + case ZEBRA_NODE: + case BGP_NODE: + case RIP_NODE: + case RIPNG_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case KEYCHAIN_NODE: + case MASC_NODE: + case RMAP_NODE: + case VTY_NODE: + vty->node = CONFIG_NODE; + break; + case BGP_VPNV4_NODE: + case BGP_IPV4_NODE: + case BGP_IPV4M_NODE: + case BGP_IPV6_NODE: + vty->node = BGP_NODE; + break; + case KEYCHAIN_KEY_NODE: + vty->node = KEYCHAIN_NODE; + break; + default: + break; + } + return CMD_SUCCESS; +} + +/* quit is alias of exit. */ +ALIAS (config_exit, + config_quit_cmd, + "quit", + "Exit current mode and down to previous mode\n"); + +/* End of configuration. */ +DEFUN (config_end, + config_end_cmd, + "end", + "End current mode and change to enable mode.") +{ + switch (vty->node) + { + case VIEW_NODE: + case ENABLE_NODE: + /* Nothing to do. */ + break; + case CONFIG_NODE: + case INTERFACE_NODE: + case ZEBRA_NODE: + case RIP_NODE: + case RIPNG_NODE: + case BGP_NODE: + case BGP_VPNV4_NODE: + case BGP_IPV4_NODE: + case BGP_IPV4M_NODE: + case BGP_IPV6_NODE: + case RMAP_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case KEYCHAIN_NODE: + case KEYCHAIN_KEY_NODE: + case MASC_NODE: + case VTY_NODE: + vty_config_unlock (vty); + vty->node = ENABLE_NODE; + break; + default: + break; + } + return CMD_SUCCESS; +} + +/* Show version. */ +DEFUN (show_version, + show_version_cmd, + "show version", + SHOW_STR + "Displays zebra version\n") +{ + vty_out (vty, "Zebra %s (%s).%s", ZEBRA_VERSION, + host_name, + VTY_NEWLINE); + vty_out (vty, "Copyright 1996-2004, Kunihiro Ishiguro.%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +/* Help display function for all node. */ +DEFUN (config_help, + config_help_cmd, + "help", + "Description of the interactive help system\n") +{ + vty_out (vty, + "Zebra VTY provides advanced help feature. When you need help,%s\ +anytime at the command line please press '?'.%s\ +%s\ +If nothing matches, the help list will be empty and you must backup%s\ + until entering a '?' shows the available options.%s\ +Two styles of help are provided:%s\ +1. Full help is available when you are ready to enter a%s\ +command argument (e.g. 'show ?') and describes each possible%s\ +argument.%s\ +2. Partial help is provided when an abbreviated argument is entered%s\ + and you want to know what arguments match the input%s\ + (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + return CMD_SUCCESS; +} + +/* Help display function for all node. */ +DEFUN (config_list, + config_list_cmd, + "list", + "Print command list\n") +{ + int i; + struct cmd_node *cnode = vector_slot (cmdvec, vty->node); + struct cmd_element *cmd; + + for (i = 0; i < vector_max (cnode->cmd_vector); i++) + if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL) + vty_out (vty, " %s%s", cmd->string, + VTY_NEWLINE); + return CMD_SUCCESS; +} + +/* Write current configuration into file. */ +DEFUN (config_write_file, + config_write_file_cmd, + "write file", + "Write running configuration to memory, network, or terminal\n" + "Write to configuration file\n") +{ + int i; + int fd; + struct cmd_node *node; + char *config_file; + char *config_file_tmp = NULL; + char *config_file_sav = NULL; + struct vty *file_vty; + + /* Check and see if we are operating under vtysh configuration */ + if (host.config == NULL) + { + vty_out (vty, "Can't save to configuration file, using vtysh.%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get filename. */ + config_file = host.config; + + config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1); + strcpy (config_file_sav, config_file); + strcat (config_file_sav, CONF_BACKUP_EXT); + + + config_file_tmp = malloc (strlen (config_file) + 8); + sprintf (config_file_tmp, "%s.XXXXXX", config_file); + + /* Open file to configuration write. */ + fd = mkstemp (config_file_tmp); + if (fd < 0) + { + vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp, + VTY_NEWLINE); + free (config_file_tmp); + free (config_file_sav); + return CMD_WARNING; + } + + /* Make vty for configuration file. */ + file_vty = vty_new (); + file_vty->fd = fd; + file_vty->type = VTY_FILE; + + /* Config file header print. */ + vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! "); + vty_time_print (file_vty, 1); + vty_out (file_vty, "!\n"); + + for (i = 0; i < vector_max (cmdvec); i++) + if ((node = vector_slot (cmdvec, i)) && node->func) + { + if ((*node->func) (file_vty)) + vty_out (file_vty, "!\n"); + } + vty_close (file_vty); + + if (unlink (config_file_sav) != 0) + if (errno != ENOENT) + { + vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav, + VTY_NEWLINE); + free (config_file_sav); + free (config_file_tmp); + unlink (config_file_tmp); + return CMD_WARNING; + } + if (link (config_file, config_file_sav) != 0) + { + vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav, + VTY_NEWLINE); + free (config_file_sav); + free (config_file_tmp); + unlink (config_file_tmp); + return CMD_WARNING; + } + sync (); + if (unlink (config_file) != 0) + { + vty_out (vty, "Can't unlink configuration file %s.%s", config_file, + VTY_NEWLINE); + free (config_file_sav); + free (config_file_tmp); + unlink (config_file_tmp); + return CMD_WARNING; + } + if (link (config_file_tmp, config_file) != 0) + { + vty_out (vty, "Can't save configuration file %s.%s", config_file, + VTY_NEWLINE); + free (config_file_sav); + free (config_file_tmp); + unlink (config_file_tmp); + return CMD_WARNING; + } + unlink (config_file_tmp); + sync (); + + free (config_file_sav); + free (config_file_tmp); + vty_out (vty, "Configuration saved to %s%s", config_file, + VTY_NEWLINE); + return CMD_SUCCESS; +} + +ALIAS (config_write_file, + config_write_cmd, + "write", + "Write running configuration to memory, network, or terminal\n"); + +ALIAS (config_write_file, + config_write_memory_cmd, + "write memory", + "Write running configuration to memory, network, or terminal\n" + "Write configuration to the file (same as write file)\n"); + +ALIAS (config_write_file, + copy_runningconfig_startupconfig_cmd, + "copy running-config startup-config", + "Copy configuration\n" + "Copy running config to... \n" + "Copy running config to startup config (same as write file)\n"); + +/* Write current configuration into the terminal. */ +DEFUN (config_write_terminal, + config_write_terminal_cmd, + "write terminal", + "Write running configuration to memory, network, or terminal\n" + "Write to terminal\n") +{ + int i; + struct cmd_node *node; + + if (vty->type == VTY_SHELL_SERV) + { + for (i = 0; i < vector_max (cmdvec); i++) + if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh) + { + if ((*node->func) (vty)) + vty_out (vty, "!%s", VTY_NEWLINE); + } + } + else + { + vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE, + VTY_NEWLINE); + vty_out (vty, "!%s", VTY_NEWLINE); + + for (i = 0; i < vector_max (cmdvec); i++) + if ((node = vector_slot (cmdvec, i)) && node->func) + { + if ((*node->func) (vty)) + vty_out (vty, "!%s", VTY_NEWLINE); + } + vty_out (vty, "end%s",VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +/* Write current configuration into the terminal. */ +ALIAS (config_write_terminal, + show_running_config_cmd, + "show running-config", + SHOW_STR + "running configuration\n"); + +/* Write startup configuration into the terminal. */ +DEFUN (show_startup_config, + show_startup_config_cmd, + "show startup-config", + SHOW_STR + "Contentes of startup configuration\n") +{ + char buf[BUFSIZ]; + FILE *confp; + + confp = fopen (host.config, "r"); + if (confp == NULL) + { + vty_out (vty, "Can't open configuration file [%s]%s", + host.config, VTY_NEWLINE); + return CMD_WARNING; + } + + while (fgets (buf, BUFSIZ, confp)) + { + char *cp = buf; + + while (*cp != '\r' && *cp != '\n' && *cp != '\0') + cp++; + *cp = '\0'; + + vty_out (vty, "%s%s", buf, VTY_NEWLINE); + } + + fclose (confp); + + return CMD_SUCCESS; +} + +/* Hostname configuration */ +DEFUN (config_hostname, + hostname_cmd, + "hostname WORD", + "Set system's network name\n" + "This system's network name\n") +{ + if (!isalpha((int) *argv[0])) + { + vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (host.name) + XFREE (0, host.name); + + host.name = strdup (argv[0]); + return CMD_SUCCESS; +} + +DEFUN (config_no_hostname, + no_hostname_cmd, + "no hostname [HOSTNAME]", + NO_STR + "Reset system's network name\n" + "Host name of this router\n") +{ + if (host.name) + XFREE (0, host.name); + host.name = NULL; + return CMD_SUCCESS; +} + +/* VTY interface password set. */ +DEFUN (config_password, password_cmd, + "password (8|) WORD", + "Assign the terminal connection password\n" + "Specifies a HIDDEN password will follow\n" + "dummy string \n" + "The HIDDEN line password string\n") +{ + /* Argument check. */ + if (argc == 0) + { + vty_out (vty, "Please specify password.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 2) + { + if (*argv[0] == '8') + { + if (host.password) + XFREE (0, host.password); + host.password = NULL; + if (host.password_encrypt) + XFREE (0, host.password_encrypt); + host.password_encrypt = XSTRDUP (0, strdup (argv[1])); + return CMD_SUCCESS; + } + else + { + vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (!isalnum ((int) *argv[0])) + { + vty_out (vty, + "Please specify string starting with alphanumeric%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (host.password) + XFREE (0, host.password); + host.password = NULL; + + if (host.password_encrypt) + XFREE (0, host.password_encrypt); + host.password_encrypt = NULL; + + if (host.encrypt) + host.password_encrypt = XSTRDUP (0, zencrypt (argv[0])); + else + host.password = XSTRDUP (0, argv[0]); + + return CMD_SUCCESS; +} + +ALIAS (config_password, password_text_cmd, + "password LINE", + "Assign the terminal connection password\n" + "The UNENCRYPTED (cleartext) line password\n"); + +/* VTY enable password set. */ +DEFUN (config_enable_password, enable_password_cmd, + "enable password (8|) WORD", + "Modify enable password parameters\n" + "Assign the privileged level password\n" + "Specifies a HIDDEN password will follow\n" + "dummy string \n" + "The HIDDEN 'enable' password string\n") +{ + /* Argument check. */ + if (argc == 0) + { + vty_out (vty, "Please specify password.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Crypt type is specified. */ + if (argc == 2) + { + if (*argv[0] == '8') + { + if (host.enable) + XFREE (0, host.enable); + host.enable = NULL; + + if (host.enable_encrypt) + XFREE (0, host.enable_encrypt); + host.enable_encrypt = XSTRDUP (0, argv[1]); + + return CMD_SUCCESS; + } + else + { + vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (!isalnum ((int) *argv[0])) + { + vty_out (vty, + "Please specify string starting with alphanumeric%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (host.enable) + XFREE (0, host.enable); + host.enable = NULL; + + if (host.enable_encrypt) + XFREE (0, host.enable_encrypt); + host.enable_encrypt = NULL; + + /* Plain password input. */ + if (host.encrypt) + host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0])); + else + host.enable = XSTRDUP (0, argv[0]); + + return CMD_SUCCESS; +} + +ALIAS (config_enable_password, + enable_password_text_cmd, + "enable password LINE", + "Modify enable password parameters\n" + "Assign the privileged level password\n" + "The UNENCRYPTED (cleartext) 'enable' password\n"); + +/* VTY enable password delete. */ +DEFUN (no_config_enable_password, no_enable_password_cmd, + "no enable password", + NO_STR + "Modify enable password parameters\n" + "Assign the privileged level password\n") +{ + if (host.enable) + XFREE (0, host.enable); + host.enable = NULL; + + if (host.enable_encrypt) + XFREE (0, host.enable_encrypt); + host.enable_encrypt = NULL; + + return CMD_SUCCESS; +} + +DEFUN (service_password_encrypt, + service_password_encrypt_cmd, + "service password-encryption", + "Set up miscellaneous service\n" + "Enable encrypted passwords\n") +{ + if (host.encrypt) + return CMD_SUCCESS; + + host.encrypt = 1; + + if (host.password) + { + if (host.password_encrypt) + XFREE (0, host.password_encrypt); + host.password_encrypt = XSTRDUP (0, zencrypt (host.password)); + } + if (host.enable) + { + if (host.enable_encrypt) + XFREE (0, host.enable_encrypt); + host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable)); + } + + return CMD_SUCCESS; +} + +DEFUN (no_service_password_encrypt, + no_service_password_encrypt_cmd, + "no service password-encryption", + NO_STR + "Set up miscellaneous service\n" + "Enable encrypted passwords\n") +{ + if (! host.encrypt) + return CMD_SUCCESS; + + host.encrypt = 0; + + if (host.password) + { + if (host.password_encrypt) + XFREE (0, host.password_encrypt); + host.password_encrypt = NULL; + } + + if (host.enable) + { + if (host.enable_encrypt) + XFREE (0, host.enable_encrypt); + host.enable_encrypt = NULL; + } + + return CMD_SUCCESS; +} + +DEFUN (config_terminal_length, config_terminal_length_cmd, + "terminal length <0-512>", + "Set terminal line parameters\n" + "Set number of lines on a screen\n" + "Number of lines on screen (0 for no pausing)\n") +{ + int lines; + char *endptr = NULL; + + lines = strtol (argv[0], &endptr, 10); + if (lines < 0 || lines > 512 || *endptr != '\0') + { + vty_out (vty, "length is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + vty->lines = lines; + + return CMD_SUCCESS; +} + +DEFUN (config_terminal_no_length, config_terminal_no_length_cmd, + "terminal no length", + "Set terminal line parameters\n" + NO_STR + "Set number of lines on a screen\n") +{ + vty->lines = -1; + return CMD_SUCCESS; +} + +DEFUN (service_terminal_length, service_terminal_length_cmd, + "service terminal-length <0-512>", + "Set up miscellaneous service\n" + "System wide terminal length configuration\n" + "Number of lines of VTY (0 means no line control)\n") +{ + int lines; + char *endptr = NULL; + + lines = strtol (argv[0], &endptr, 10); + if (lines < 0 || lines > 512 || *endptr != '\0') + { + vty_out (vty, "length is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + host.lines = lines; + + return CMD_SUCCESS; +} + +DEFUN (no_service_terminal_length, no_service_terminal_length_cmd, + "no service terminal-length [<0-512>]", + NO_STR + "Set up miscellaneous service\n" + "System wide terminal length configuration\n" + "Number of lines of VTY (0 means no line control)\n") +{ + host.lines = -1; + return CMD_SUCCESS; +} + +DEFUN (config_log_stdout, + config_log_stdout_cmd, + "log stdout", + "Logging control\n" + "Logging goes to stdout\n") +{ + zlog_set_flag (NULL, ZLOG_STDOUT); + host.log_stdout = 1; + return CMD_SUCCESS; +} + +DEFUN (no_config_log_stdout, + no_config_log_stdout_cmd, + "no log stdout", + NO_STR + "Logging control\n" + "Cancel logging to stdout\n") +{ + zlog_reset_flag (NULL, ZLOG_STDOUT); + host.log_stdout = 0; + return CMD_SUCCESS; +} + +DEFUN (config_log_file, + config_log_file_cmd, + "log file FILENAME", + "Logging control\n" + "Logging to file\n" + "Logging filename\n") +{ + int ret; + char *cwd; + char *fullpath; + + /* Path detection. */ + if (! IS_DIRECTORY_SEP (*argv[0])) + { + cwd = getcwd (NULL, MAXPATHLEN); + fullpath = XMALLOC (MTYPE_TMP, + strlen (cwd) + strlen (argv[0]) + 2); + sprintf (fullpath, "%s/%s", cwd, argv[0]); + } + else + fullpath = argv[0]; + + ret = zlog_set_file (NULL, ZLOG_FILE, fullpath); + + if (!ret) + { + vty_out (vty, "can't open logfile %s\n", argv[0]); + return CMD_WARNING; + } + + if (host.logfile) + XFREE (MTYPE_TMP, host.logfile); + + host.logfile = strdup (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_config_log_file, + no_config_log_file_cmd, + "no log file [FILENAME]", + NO_STR + "Logging control\n" + "Cancel logging to file\n" + "Logging file name\n") +{ + zlog_reset_file (NULL); + + if (host.logfile) + XFREE (MTYPE_TMP, host.logfile); + + host.logfile = NULL; + + return CMD_SUCCESS; +} + +DEFUN (config_log_syslog, + config_log_syslog_cmd, + "log syslog", + "Logging control\n" + "Logging goes to syslog\n") +{ + zlog_set_flag (NULL, ZLOG_SYSLOG); + host.log_syslog = 1; + zlog_default->facility = LOG_DAEMON; + return CMD_SUCCESS; +} + +DEFUN (config_log_syslog_facility, + config_log_syslog_facility_cmd, + "log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)", + "Logging control\n" + "Logging goes to syslog\n" + "Facility parameter for syslog messages\n" + "Kernel\n" + "User process\n" + "Mail system\n" + "System daemons\n" + "Authorization system\n" + "Syslog itself\n" + "Line printer system\n" + "USENET news\n" + "Unix-to-Unix copy system\n" + "Cron/at facility\n" + "Local use\n" + "Local use\n" + "Local use\n" + "Local use\n" + "Local use\n" + "Local use\n" + "Local use\n" + "Local use\n") +{ + int facility = LOG_DAEMON; + + zlog_set_flag (NULL, ZLOG_SYSLOG); + host.log_syslog = 1; + + if (strncmp (argv[0], "kern", 1) == 0) + facility = LOG_KERN; + else if (strncmp (argv[0], "user", 2) == 0) + facility = LOG_USER; + else if (strncmp (argv[0], "mail", 1) == 0) + facility = LOG_MAIL; + else if (strncmp (argv[0], "daemon", 1) == 0) + facility = LOG_DAEMON; + else if (strncmp (argv[0], "auth", 1) == 0) + facility = LOG_AUTH; + else if (strncmp (argv[0], "syslog", 1) == 0) + facility = LOG_SYSLOG; + else if (strncmp (argv[0], "lpr", 2) == 0) + facility = LOG_LPR; + else if (strncmp (argv[0], "news", 1) == 0) + facility = LOG_NEWS; + else if (strncmp (argv[0], "uucp", 2) == 0) + facility = LOG_UUCP; + else if (strncmp (argv[0], "cron", 1) == 0) + facility = LOG_CRON; + else if (strncmp (argv[0], "local0", 6) == 0) + facility = LOG_LOCAL0; + else if (strncmp (argv[0], "local1", 6) == 0) + facility = LOG_LOCAL1; + else if (strncmp (argv[0], "local2", 6) == 0) + facility = LOG_LOCAL2; + else if (strncmp (argv[0], "local3", 6) == 0) + facility = LOG_LOCAL3; + else if (strncmp (argv[0], "local4", 6) == 0) + facility = LOG_LOCAL4; + else if (strncmp (argv[0], "local5", 6) == 0) + facility = LOG_LOCAL5; + else if (strncmp (argv[0], "local6", 6) == 0) + facility = LOG_LOCAL6; + else if (strncmp (argv[0], "local7", 6) == 0) + facility = LOG_LOCAL7; + + zlog_default->facility = facility; + + return CMD_SUCCESS; +} + +DEFUN (no_config_log_syslog, + no_config_log_syslog_cmd, + "no log syslog", + NO_STR + "Logging control\n" + "Cancel logging to syslog\n") +{ + zlog_reset_flag (NULL, ZLOG_SYSLOG); + host.log_syslog = 0; + zlog_default->facility = LOG_DAEMON; + return CMD_SUCCESS; +} + +ALIAS (no_config_log_syslog, + no_config_log_syslog_facility_cmd, + "no log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)", + NO_STR + "Logging control\n" + "Logging goes to syslog\n" + "Facility parameter for syslog messages\n" + "Kernel\n" + "User process\n" + "Mail system\n" + "System daemons\n" + "Authorization system\n" + "Syslog itself\n" + "Line printer system\n" + "USENET news\n" + "Unix-to-Unix copy system\n" + "Cron/at facility\n" + "Local use\n" + "Local use\n" + "Local use\n" + "Local use\n" + "Local use\n" + "Local use\n" + "Local use\n" + "Local use\n"); + +DEFUN (config_log_trap, + config_log_trap_cmd, + "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)", + "Logging control\n" + "Limit logging to specifed level\n") +{ + int new_level ; + + for ( new_level = 0 ; zlog_priority [new_level] != NULL ; new_level ++ ) + { + if ( strcmp ( argv[0], zlog_priority [new_level] ) == 0 ) + /* found new logging level */ + { + zlog_default->maskpri = new_level; + return CMD_SUCCESS; + } + } + return CMD_ERR_NO_MATCH; +} + +DEFUN (no_config_log_trap, + no_config_log_trap_cmd, + "no log trap", + NO_STR + "Logging control\n" + "Permit all logging information\n") +{ + zlog_default->maskpri = LOG_DEBUG; + return CMD_SUCCESS; +} + +DEFUN (config_log_record_priority, + config_log_record_priority_cmd, + "log record-priority", + "Logging control\n" + "Log the priority of the message within the message\n") +{ + zlog_default->record_priority = 1 ; + return CMD_SUCCESS; +} + +DEFUN (no_config_log_record_priority, + no_config_log_record_priority_cmd, + "no log record-priority", + NO_STR + "Logging control\n" + "Do not log the priority of the message within the message\n") +{ + zlog_default->record_priority = 0 ; + return CMD_SUCCESS; +} + + +DEFUN (banner_motd_default, + banner_motd_default_cmd, + "banner motd default", + "Set banner string\n" + "Strings for motd\n" + "Default string\n") +{ + host.motd = default_motd; + return CMD_SUCCESS; +} + +DEFUN (no_banner_motd, + no_banner_motd_cmd, + "no banner motd", + NO_STR + "Set banner string\n" + "Strings for motd\n") +{ + host.motd = NULL; + return CMD_SUCCESS; +} + +/* Set config filename. Called from vty.c */ +void +host_config_set (char *filename) +{ + host.config = strdup (filename); +} + +void +install_default (enum node_type node) +{ + install_element (node, &config_exit_cmd); + install_element (node, &config_quit_cmd); + install_element (node, &config_end_cmd); + install_element (node, &config_help_cmd); + install_element (node, &config_list_cmd); + + install_element (node, &config_write_terminal_cmd); + install_element (node, &config_write_file_cmd); + install_element (node, &config_write_memory_cmd); + install_element (node, &config_write_cmd); + install_element (node, &show_running_config_cmd); +} + +/* Initialize command interface. Install basic nodes and commands. */ +void +cmd_init (int terminal) +{ + /* Allocate initial top vector of commands. */ + cmdvec = vector_init (VECTOR_MIN_SIZE); + + /* Default host value settings. */ + host.name = NULL; + host.password = NULL; + host.enable = NULL; + host.logfile = NULL; + host.config = NULL; + host.lines = -1; + host.motd = default_motd; + + /* Install top nodes. */ + install_node (&view_node, NULL); + install_node (&enable_node, NULL); + install_node (&auth_node, NULL); + install_node (&auth_enable_node, NULL); + install_node (&config_node, config_write_host); + + /* Each node's basic commands. */ + install_element (VIEW_NODE, &show_version_cmd); + if (terminal) + { + install_element (VIEW_NODE, &config_list_cmd); + install_element (VIEW_NODE, &config_exit_cmd); + install_element (VIEW_NODE, &config_quit_cmd); + install_element (VIEW_NODE, &config_help_cmd); + install_element (VIEW_NODE, &config_enable_cmd); + install_element (VIEW_NODE, &config_terminal_length_cmd); + install_element (VIEW_NODE, &config_terminal_no_length_cmd); + } + + if (terminal) + { + install_default (ENABLE_NODE); + install_element (ENABLE_NODE, &config_disable_cmd); + install_element (ENABLE_NODE, &config_terminal_cmd); + install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd); + } + install_element (ENABLE_NODE, &show_startup_config_cmd); + install_element (ENABLE_NODE, &show_version_cmd); + install_element (ENABLE_NODE, &config_terminal_length_cmd); + install_element (ENABLE_NODE, &config_terminal_no_length_cmd); + + if (terminal) + install_default (CONFIG_NODE); + install_element (CONFIG_NODE, &hostname_cmd); + install_element (CONFIG_NODE, &no_hostname_cmd); + install_element (CONFIG_NODE, &password_cmd); + install_element (CONFIG_NODE, &password_text_cmd); + install_element (CONFIG_NODE, &enable_password_cmd); + install_element (CONFIG_NODE, &enable_password_text_cmd); + install_element (CONFIG_NODE, &no_enable_password_cmd); + if (terminal) + { + install_element (CONFIG_NODE, &config_log_stdout_cmd); + install_element (CONFIG_NODE, &no_config_log_stdout_cmd); + install_element (CONFIG_NODE, &config_log_file_cmd); + install_element (CONFIG_NODE, &no_config_log_file_cmd); + install_element (CONFIG_NODE, &config_log_syslog_cmd); + install_element (CONFIG_NODE, &config_log_syslog_facility_cmd); + install_element (CONFIG_NODE, &no_config_log_syslog_cmd); + install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd); + install_element (CONFIG_NODE, &config_log_trap_cmd); + install_element (CONFIG_NODE, &no_config_log_trap_cmd); + install_element (CONFIG_NODE, &config_log_record_priority_cmd); + install_element (CONFIG_NODE, &no_config_log_record_priority_cmd); + install_element (CONFIG_NODE, &service_password_encrypt_cmd); + install_element (CONFIG_NODE, &no_service_password_encrypt_cmd); + install_element (CONFIG_NODE, &banner_motd_default_cmd); + install_element (CONFIG_NODE, &no_banner_motd_cmd); + install_element (CONFIG_NODE, &service_terminal_length_cmd); + install_element (CONFIG_NODE, &no_service_terminal_length_cmd); + } + + srand(time(NULL)); +} diff --git a/lib/command.h b/lib/command.h new file mode 100644 index 0000000..3009b26 --- /dev/null +++ b/lib/command.h @@ -0,0 +1,308 @@ +/* + * Zebra configuration command interface routine + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_COMMAND_H +#define _ZEBRA_COMMAND_H + +#include "vector.h" +#include "vty.h" + +/* Host configuration variable */ +struct host +{ + /* Host name of this router. */ + char *name; + + /* Password for vty interface. */ + char *password; + char *password_encrypt; + + /* Enable password */ + char *enable; + char *enable_encrypt; + + /* System wide terminal lines. */ + int lines; + + /* Log filename. */ + char *logfile; + + /* Log stdout. */ + u_char log_stdout; + + /* Log syslog. */ + u_char log_syslog; + + /* config file name of this host */ + char *config; + + /* Flags for services */ + int advanced; + int encrypt; + + /* Banner configuration. */ + char *motd; +}; + +/* There are some command levels which called from command node. */ +enum node_type +{ + AUTH_NODE, /* Authentication mode of vty interface. */ + VIEW_NODE, /* View node. Default mode of vty interface. */ + AUTH_ENABLE_NODE, /* Authentication mode for change enable. */ + ENABLE_NODE, /* Enable node. */ + CONFIG_NODE, /* Config node. Default mode of config file. */ + DEBUG_NODE, /* Debug node. */ + AAA_NODE, /* AAA node. */ + KEYCHAIN_NODE, /* Key-chain node. */ + KEYCHAIN_KEY_NODE, /* Key-chain key node. */ + INTERFACE_NODE, /* Interface mode node. */ + ZEBRA_NODE, /* zebra connection node. */ + TABLE_NODE, /* rtm_table selection node. */ + RIP_NODE, /* RIP protocol mode node. */ + RIPNG_NODE, /* RIPng protocol mode node. */ + BGP_NODE, /* BGP protocol mode which includes BGP4+ */ + BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */ + BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */ + BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */ + BGP_IPV6_NODE, /* BGP IPv6 address family */ + OSPF_NODE, /* OSPF protocol mode */ + OSPF6_NODE, /* OSPF protocol for IPv6 mode */ + MASC_NODE, /* MASC for multicast. */ + IRDP_NODE, /* ICMP Router Discovery Protocol mode. */ + IP_NODE, /* Static ip route node. */ + ACCESS_NODE, /* Access list node. */ + PREFIX_NODE, /* Prefix list node. */ + ACCESS_IPV6_NODE, /* Access list node. */ + PREFIX_IPV6_NODE, /* Prefix list node. */ + AS_LIST_NODE, /* AS list node. */ + COMMUNITY_LIST_NODE, /* Community list node. */ + RMAP_NODE, /* Route map node. */ + SMUX_NODE, /* SNMP configuration node. */ + DUMP_NODE, /* Packet dump node. */ + FORWARDING_NODE, /* IP forwarding node. */ + VTY_NODE /* Vty node. */ +}; + +/* Node which has some commands and prompt string and configuration + function pointer . */ +struct cmd_node +{ + /* Node index. */ + enum node_type node; + + /* Prompt character at vty interface. */ + char *prompt; + + /* Is this node's configuration goes to vtysh ? */ + int vtysh; + + /* Node's configuration write function */ + int (*func) (struct vty *); + + /* Vector of this node's command list. */ + vector cmd_vector; +}; + +/* Structure of command element. */ +struct cmd_element +{ + char *string; /* Command specification by string. */ + int (*func) (struct cmd_element *, struct vty *, int, char **); + char *doc; /* Documentation of this command. */ + int daemon; /* Daemon to which this command belong. */ + vector strvec; /* Pointing out each description vector. */ + int cmdsize; /* Command index count. */ + char *config; /* Configuration string */ + vector subconfig; /* Sub configuration string */ +}; + +/* Command description structure. */ +struct desc +{ + char *cmd; /* Command string. */ + char *str; /* Command's description. */ +}; + +/* Return value of the commands. */ +#define CMD_SUCCESS 0 +#define CMD_WARNING 1 +#define CMD_ERR_NO_MATCH 2 +#define CMD_ERR_AMBIGUOUS 3 +#define CMD_ERR_INCOMPLETE 4 +#define CMD_ERR_EXEED_ARGC_MAX 5 +#define CMD_ERR_NOTHING_TODO 6 +#define CMD_COMPLETE_FULL_MATCH 7 +#define CMD_COMPLETE_MATCH 8 +#define CMD_COMPLETE_LIST_MATCH 9 +#define CMD_SUCCESS_DAEMON 10 + +/* Argc max counts. */ +#define CMD_ARGC_MAX 25 + +/* Turn off these macros when uisng cpp with extract.pl */ +#ifndef VTYSH_EXTRACT_PL + +/* DEFUN for vty command interafce. Little bit hacky ;-). */ +#define DEFUN(funcname, cmdname, cmdstr, helpstr) \ + int funcname (struct cmd_element *, struct vty *, int, char **); \ + struct cmd_element cmdname = \ + { \ + cmdstr, \ + funcname, \ + helpstr \ + }; \ + int funcname \ + (struct cmd_element *self, struct vty *vty, int argc, char **argv) + +/* DEFUN_NOSH for commands that vtysh should ignore */ +#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \ + DEFUN(funcname, cmdname, cmdstr, helpstr) + +/* DEFSH for vtysh. */ +#define DEFSH(daemon, cmdname, cmdstr, helpstr) \ + struct cmd_element cmdname = \ + { \ + cmdstr, \ + NULL, \ + helpstr, \ + daemon \ + }; \ + +/* DEFUN + DEFSH */ +#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \ + int funcname (struct cmd_element *, struct vty *, int, char **); \ + struct cmd_element cmdname = \ + { \ + cmdstr, \ + funcname, \ + helpstr, \ + daemon \ + }; \ + int funcname \ + (struct cmd_element *self, struct vty *vty, int argc, char **argv) + +/* ALIAS macro which define existing command's alias. */ +#define ALIAS(funcname, cmdname, cmdstr, helpstr) \ + struct cmd_element cmdname = \ + { \ + cmdstr, \ + funcname, \ + helpstr \ + }; + +#endif /* VTYSH_EXTRACT_PL */ + +/* Some macroes */ +#define CMD_OPTION(S) ((S[0]) == '[') +#define CMD_VARIABLE(S) (((S[0]) >= 'A' && (S[0]) <= 'Z') || ((S[0]) == '<')) +#define CMD_VARARG(S) ((S[0]) == '.') +#define CMD_RANGE(S) ((S[0] == '<')) + +#define CMD_IPV4(S) ((strcmp ((S), "A.B.C.D") == 0)) +#define CMD_IPV4_PREFIX(S) ((strcmp ((S), "A.B.C.D/M") == 0)) +#define CMD_IPV6(S) ((strcmp ((S), "X:X::X:X") == 0)) +#define CMD_IPV6_PREFIX(S) ((strcmp ((S), "X:X::X:X/M") == 0)) + +/* Common descriptions. */ +#define SHOW_STR "Show running system information\n" +#define IP_STR "IP information\n" +#define IPV6_STR "IPv6 information\n" +#define NO_STR "Negate a command or set its defaults\n" +#define CLEAR_STR "Reset functions\n" +#define RIP_STR "RIP information\n" +#define BGP_STR "BGP information\n" +#define OSPF_STR "OSPF information\n" +#define NEIGHBOR_STR "Specify neighbor router\n" +#define DEBUG_STR "Debugging functions (see also 'undebug')\n" +#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n" +#define ROUTER_STR "Enable a routing process\n" +#define AS_STR "AS number\n" +#define MBGP_STR "MBGP information\n" +#define MATCH_STR "Match values from routing table\n" +#define SET_STR "Set values in destination routing protocol\n" +#define OUT_STR "Filter outgoing routing updates\n" +#define IN_STR "Filter incoming routing updates\n" +#define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n" +#define OSPF6_NUMBER_STR "Specify by number\n" +#define INTERFACE_STR "Interface infomation\n" +#define IFNAME_STR "Interface name(e.g. ep0)\n" +#define IP6_STR "IPv6 Information\n" +#define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n" +#define OSPF6_ROUTER_STR "Enable a routing process\n" +#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n" +#define SECONDS_STR "<1-65535> Seconds\n" +#define ROUTE_STR "Routing Table\n" +#define PREFIX_LIST_STR "Build a prefix list\n" +#define OSPF6_DUMP_TYPE_LIST \ +"(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)" + +#define CONF_BACKUP_EXT ".sav" + +/* IPv4 only machine should not accept IPv6 address for peer's IP + address. So we replace VTY command string like below. */ +#ifdef HAVE_IPV6 +#define NEIGHBOR_CMD "neighbor (A.B.C.D|X:X::X:X) " +#define NO_NEIGHBOR_CMD "no neighbor (A.B.C.D|X:X::X:X) " +#define NEIGHBOR_ADDR_STR "Neighbor address\nIPv6 address\n" +#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|X:X::X:X|WORD) " +#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|X:X::X:X|WORD) " +#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" +#else +#define NEIGHBOR_CMD "neighbor A.B.C.D " +#define NO_NEIGHBOR_CMD "no neighbor A.B.C.D " +#define NEIGHBOR_ADDR_STR "Neighbor address\n" +#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|WORD) " +#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|WORD) " +#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor tag\n" +#endif /* HAVE_IPV6 */ + +/* Prototypes. */ +void install_node (struct cmd_node *, int (*) (struct vty *)); +void install_default (enum node_type); +void install_element (enum node_type, struct cmd_element *); +void sort_node (); + +char *argv_concat (char **, int, int); +vector cmd_make_strvec (char *); +void cmd_free_strvec (vector); +vector cmd_describe_command (); +char **cmd_complete_command (); +char *cmd_prompt (enum node_type); +int config_from_file (struct vty *, FILE *); +int cmd_execute_command (vector, struct vty *, struct cmd_element **); +int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **); +void config_replace_string (struct cmd_element *, char *, ...); +void cmd_init (int); + +/* Export typical functions. */ +extern struct cmd_element config_end_cmd; +extern struct cmd_element config_exit_cmd; +extern struct cmd_element config_quit_cmd; +extern struct cmd_element config_help_cmd; +extern struct cmd_element config_list_cmd; +int config_exit (struct cmd_element *, struct vty *, int, char **); +int config_help (struct cmd_element *, struct vty *, int, char **); +char *host_config_file (); +void host_config_set (char *); + +#endif /* _ZEBRA_COMMAND_H */ diff --git a/lib/daemon.c b/lib/daemon.c new file mode 100644 index 0000000..dfd26b3 --- /dev/null +++ b/lib/daemon.c @@ -0,0 +1,80 @@ +/* + * Daemonize routine + * Copyright (C) 1997, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#ifndef HAVE_DAEMON + +/* Daemonize myself. */ +int +daemon (int nochdir, int noclose) +{ + pid_t pid; + + pid = fork (); + + /* In case of fork is error. */ + if (pid < 0) + { + perror ("fork"); + return -1; + } + + /* In case of this is parent process. */ + if (pid != 0) + exit (0); + + /* Become session leader and get pid. */ + pid = setsid(); + + if (pid < -1) + { + perror ("setsid"); + return -1; + } + + /* Change directory to root. */ + if (! nochdir) + chdir ("/"); + + /* File descriptor close. */ + if (! noclose) + { + int fd; + + fd = open ("/dev/null", O_RDWR, 0); + if (fd != -1) + { + dup2 (fd, STDIN_FILENO); + dup2 (fd, STDOUT_FILENO); + dup2 (fd, STDERR_FILENO); + if (fd > 2) + close (fd); + } + } + + umask (0027); + + return 0; +} + +#endif /* HAVE_DAEMON */ diff --git a/lib/distribute.c b/lib/distribute.c new file mode 100644 index 0000000..6da3902 --- /dev/null +++ b/lib/distribute.c @@ -0,0 +1,798 @@ +/* Distribute list functions + * Copyright (C) 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "hash.h" +#include "if.h" +#include "filter.h" +#include "command.h" +#include "distribute.h" +#include "memory.h" + +/* Hash of distribute list. */ +struct hash *disthash; + +/* Hook functions. */ +void (*distribute_add_hook) (struct distribute *); +void (*distribute_delete_hook) (struct distribute *); + +struct distribute * +distribute_new () +{ + struct distribute *new; + + new = XMALLOC (MTYPE_DISTRIBUTE, sizeof (struct distribute)); + memset (new, 0, sizeof (struct distribute)); + + return new; +} + +/* Free distribute object. */ +void +distribute_free (struct distribute *dist) +{ + if (dist->ifname) + free (dist->ifname); + + if (dist->list[DISTRIBUTE_IN]) + free (dist->list[DISTRIBUTE_IN]); + if (dist->list[DISTRIBUTE_OUT]) + free (dist->list[DISTRIBUTE_OUT]); + + if (dist->prefix[DISTRIBUTE_IN]) + free (dist->prefix[DISTRIBUTE_IN]); + if (dist->prefix[DISTRIBUTE_OUT]) + free (dist->prefix[DISTRIBUTE_OUT]); + + XFREE (MTYPE_DISTRIBUTE, dist); +} + +/* Lookup interface's distribute list. */ +struct distribute * +distribute_lookup (char *ifname) +{ + struct distribute key; + struct distribute *dist; + + key.ifname = ifname; + + dist = hash_lookup (disthash, &key); + + return dist; +} + +void +distribute_list_add_hook (void (*func) (struct distribute *)) +{ + distribute_add_hook = func; +} + +void +distribute_list_delete_hook (void (*func) (struct distribute *)) +{ + distribute_delete_hook = func; +} + +void * +distribute_hash_alloc (struct distribute *arg) +{ + struct distribute *dist; + + dist = distribute_new (); + if (arg->ifname) + dist->ifname = strdup (arg->ifname); + else + dist->ifname = NULL; + return dist; +} + +/* Make new distribute list and push into hash. */ +struct distribute * +distribute_get (char *ifname) +{ + struct distribute key; + + key.ifname = ifname; + + return hash_get (disthash, &key, distribute_hash_alloc); +} + +unsigned int +distribute_hash_make (struct distribute *dist) +{ + unsigned int key; + int i; + + key = 0; + if (dist->ifname) + for (i = 0; i < strlen (dist->ifname); i++) + key += dist->ifname[i]; + + return key; +} + +/* If two distribute-list have same value then return 1 else return + 0. This function is used by hash package. */ +int +distribute_cmp (struct distribute *dist1, struct distribute *dist2) +{ + if (dist1->ifname && dist2->ifname) + if (strcmp (dist1->ifname, dist2->ifname) == 0) + return 1; + if (! dist1->ifname && ! dist2->ifname) + return 1; + return 0; +} + +/* Set access-list name to the distribute list. */ +struct distribute * +distribute_list_set (char *ifname, enum distribute_type type, char *alist_name) +{ + struct distribute *dist; + + dist = distribute_get (ifname); + + if (type == DISTRIBUTE_IN) + { + if (dist->list[DISTRIBUTE_IN]) + free (dist->list[DISTRIBUTE_IN]); + dist->list[DISTRIBUTE_IN] = strdup (alist_name); + } + if (type == DISTRIBUTE_OUT) + { + if (dist->list[DISTRIBUTE_OUT]) + free (dist->list[DISTRIBUTE_OUT]); + dist->list[DISTRIBUTE_OUT] = strdup (alist_name); + } + + /* Apply this distribute-list to the interface. */ + (*distribute_add_hook) (dist); + + return dist; +} + +/* Unset distribute-list. If matched distribute-list exist then + return 1. */ +int +distribute_list_unset (char *ifname, enum distribute_type type, + char *alist_name) +{ + struct distribute *dist; + + dist = distribute_lookup (ifname); + if (!dist) + return 0; + + if (type == DISTRIBUTE_IN) + { + if (!dist->list[DISTRIBUTE_IN]) + return 0; + if (strcmp (dist->list[DISTRIBUTE_IN], alist_name) != 0) + return 0; + + free (dist->list[DISTRIBUTE_IN]); + dist->list[DISTRIBUTE_IN] = NULL; + } + + if (type == DISTRIBUTE_OUT) + { + if (!dist->list[DISTRIBUTE_OUT]) + return 0; + if (strcmp (dist->list[DISTRIBUTE_OUT], alist_name) != 0) + return 0; + + free (dist->list[DISTRIBUTE_OUT]); + dist->list[DISTRIBUTE_OUT] = NULL; + } + + /* Apply this distribute-list to the interface. */ + (*distribute_delete_hook) (dist); + + /* If both out and in is NULL then free distribute list. */ + if (dist->list[DISTRIBUTE_IN] == NULL && + dist->list[DISTRIBUTE_OUT] == NULL && + dist->prefix[DISTRIBUTE_IN] == NULL && + dist->prefix[DISTRIBUTE_OUT] == NULL) + { + hash_release (disthash, dist); + distribute_free (dist); + } + + return 1; +} + +/* Set access-list name to the distribute list. */ +struct distribute * +distribute_list_prefix_set (char *ifname, enum distribute_type type, + char *plist_name) +{ + struct distribute *dist; + + dist = distribute_get (ifname); + + if (type == DISTRIBUTE_IN) + { + if (dist->prefix[DISTRIBUTE_IN]) + free (dist->prefix[DISTRIBUTE_IN]); + dist->prefix[DISTRIBUTE_IN] = strdup (plist_name); + } + if (type == DISTRIBUTE_OUT) + { + if (dist->prefix[DISTRIBUTE_OUT]) + free (dist->prefix[DISTRIBUTE_OUT]); + dist->prefix[DISTRIBUTE_OUT] = strdup (plist_name); + } + + /* Apply this distribute-list to the interface. */ + (*distribute_add_hook) (dist); + + return dist; +} + +/* Unset distribute-list. If matched distribute-list exist then + return 1. */ +int +distribute_list_prefix_unset (char *ifname, enum distribute_type type, + char *plist_name) +{ + struct distribute *dist; + + dist = distribute_lookup (ifname); + if (!dist) + return 0; + + if (type == DISTRIBUTE_IN) + { + if (!dist->prefix[DISTRIBUTE_IN]) + return 0; + if (strcmp (dist->prefix[DISTRIBUTE_IN], plist_name) != 0) + return 0; + + free (dist->prefix[DISTRIBUTE_IN]); + dist->prefix[DISTRIBUTE_IN] = NULL; + } + + if (type == DISTRIBUTE_OUT) + { + if (!dist->prefix[DISTRIBUTE_OUT]) + return 0; + if (strcmp (dist->prefix[DISTRIBUTE_OUT], plist_name) != 0) + return 0; + + free (dist->prefix[DISTRIBUTE_OUT]); + dist->prefix[DISTRIBUTE_OUT] = NULL; + } + + /* Apply this distribute-list to the interface. */ + (*distribute_delete_hook) (dist); + + /* If both out and in is NULL then free distribute list. */ + if (dist->list[DISTRIBUTE_IN] == NULL && + dist->list[DISTRIBUTE_OUT] == NULL && + dist->prefix[DISTRIBUTE_IN] == NULL && + dist->prefix[DISTRIBUTE_OUT] == NULL) + { + hash_release (disthash, dist); + distribute_free (dist); + } + + return 1; +} + +DEFUN (distribute_list_all, + distribute_list_all_cmd, + "distribute-list WORD (in|out)", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") +{ + enum distribute_type type; + struct distribute *dist; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get interface name corresponding distribute list. */ + dist = distribute_list_set (NULL, type, argv[0]); + + return CMD_SUCCESS; +} + +ALIAS (distribute_list_all, + ipv6_distribute_list_all_cmd, + "distribute-list WORD (in|out)", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n"); + +DEFUN (no_distribute_list_all, + no_distribute_list_all_cmd, + "no distribute-list WORD (in|out)", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") +{ + int ret; + enum distribute_type type; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = distribute_list_unset (NULL, type, argv[0]); + if (! ret) + { + vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +ALIAS (no_distribute_list_all, + no_ipv6_distribute_list_all_cmd, + "no distribute-list WORD (in|out)", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n"); + +DEFUN (distribute_list, + distribute_list_cmd, + "distribute-list WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + enum distribute_type type; + struct distribute *dist; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get interface name corresponding distribute list. */ + dist = distribute_list_set (argv[2], type, argv[0]); + + return CMD_SUCCESS; +} + +ALIAS (distribute_list, + ipv6_distribute_list_cmd, + "distribute-list WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n"); + +DEFUN (no_districute_list, + no_distribute_list_cmd, + "no distribute-list WORD (in|out) WORD", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + int ret; + enum distribute_type type; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = distribute_list_unset (argv[2], type, argv[0]); + if (! ret) + { + vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +ALIAS (no_districute_list, + no_ipv6_distribute_list_cmd, + "no distribute-list WORD (in|out) WORD", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n"); + +DEFUN (districute_list_prefix_all, + distribute_list_prefix_all_cmd, + "distribute-list prefix WORD (in|out)", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") +{ + enum distribute_type type; + struct distribute *dist; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get interface name corresponding distribute list. */ + dist = distribute_list_prefix_set (NULL, type, argv[0]); + + return CMD_SUCCESS; +} + +ALIAS (districute_list_prefix_all, + ipv6_distribute_list_prefix_all_cmd, + "distribute-list prefix WORD (in|out)", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n"); + +DEFUN (no_districute_list_prefix_all, + no_distribute_list_prefix_all_cmd, + "no distribute-list prefix WORD (in|out)", + NO_STR + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") +{ + int ret; + enum distribute_type type; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = distribute_list_prefix_unset (NULL, type, argv[0]); + if (! ret) + { + vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +ALIAS (no_districute_list_prefix_all, + no_ipv6_distribute_list_prefix_all_cmd, + "no distribute-list prefix WORD (in|out)", + NO_STR + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n"); + +DEFUN (districute_list_prefix, distribute_list_prefix_cmd, + "distribute-list prefix WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + enum distribute_type type; + struct distribute *dist; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get interface name corresponding distribute list. */ + dist = distribute_list_prefix_set (argv[2], type, argv[0]); + + return CMD_SUCCESS; +} + +ALIAS (districute_list_prefix, + ipv6_distribute_list_prefix_cmd, + "distribute-list prefix WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n"); + +DEFUN (no_districute_list_prefix, + no_distribute_list_prefix_cmd, + "no distribute-list prefix WORD (in|out) WORD", + NO_STR + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + int ret; + enum distribute_type type; + + /* Check of distribute list type. */ + if (strncmp (argv[1], "i", 1) == 0) + type = DISTRIBUTE_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = DISTRIBUTE_OUT; + else + { + vty_out (vty, "distribute list direction must be [in|out]%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = distribute_list_prefix_unset (argv[2], type, argv[0]); + if (! ret) + { + vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +ALIAS (no_districute_list_prefix, + no_ipv6_distribute_list_prefix_cmd, + "no distribute-list prefix WORD (in|out) WORD", + NO_STR + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n"); + +int +config_show_distribute (struct vty *vty) +{ + int i; + struct hash_backet *mp; + struct distribute *dist; + + /* Output filter configuration. */ + dist = distribute_lookup (NULL); + if (dist && (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT])) + { + vty_out (vty, " Outgoing update filter list for all interface is"); + if (dist->list[DISTRIBUTE_OUT]) + vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]); + if (dist->prefix[DISTRIBUTE_OUT]) + vty_out (vty, "%s (prefix-list) %s", + dist->list[DISTRIBUTE_OUT] ? "," : "", + dist->prefix[DISTRIBUTE_OUT]); + vty_out (vty, "%s", VTY_NEWLINE); + } + else + vty_out (vty, " Outgoing update filter list for all interface is not set%s", VTY_NEWLINE); + + for (i = 0; i < disthash->size; i++) + for (mp = disthash->index[i]; mp; mp = mp->next) + { + dist = mp->data; + if (dist->ifname) + if (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT]) + { + vty_out (vty, " %s filtered by", dist->ifname); + if (dist->list[DISTRIBUTE_OUT]) + vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]); + if (dist->prefix[DISTRIBUTE_OUT]) + vty_out (vty, "%s (prefix-list) %s", + dist->list[DISTRIBUTE_OUT] ? "," : "", + dist->prefix[DISTRIBUTE_OUT]); + vty_out (vty, "%s", VTY_NEWLINE); + } + } + + + /* Input filter configuration. */ + dist = distribute_lookup (NULL); + if (dist && (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN])) + { + vty_out (vty, " Incoming update filter list for all interface is"); + if (dist->list[DISTRIBUTE_IN]) + vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]); + if (dist->prefix[DISTRIBUTE_IN]) + vty_out (vty, "%s (prefix-list) %s", + dist->list[DISTRIBUTE_IN] ? "," : "", + dist->prefix[DISTRIBUTE_IN]); + vty_out (vty, "%s", VTY_NEWLINE); + } + else + vty_out (vty, " Incoming update filter list for all interface is not set%s", VTY_NEWLINE); + + for (i = 0; i < disthash->size; i++) + for (mp = disthash->index[i]; mp; mp = mp->next) + { + dist = mp->data; + if (dist->ifname) + if (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN]) + { + vty_out (vty, " %s filtered by", dist->ifname); + if (dist->list[DISTRIBUTE_IN]) + vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]); + if (dist->prefix[DISTRIBUTE_IN]) + vty_out (vty, "%s (prefix-list) %s", + dist->list[DISTRIBUTE_IN] ? "," : "", + dist->prefix[DISTRIBUTE_IN]); + vty_out (vty, "%s", VTY_NEWLINE); + } + } + return 0; +} + +/* Configuration write function. */ +int +config_write_distribute (struct vty *vty) +{ + int i; + struct hash_backet *mp; + int write = 0; + + for (i = 0; i < disthash->size; i++) + for (mp = disthash->index[i]; mp; mp = mp->next) + { + struct distribute *dist; + + dist = mp->data; + + if (dist->list[DISTRIBUTE_IN]) + { + vty_out (vty, " distribute-list %s in %s%s", + dist->list[DISTRIBUTE_IN], + dist->ifname ? dist->ifname : "", + VTY_NEWLINE); + write++; + } + + if (dist->list[DISTRIBUTE_OUT]) + { + vty_out (vty, " distribute-list %s out %s%s", + + dist->list[DISTRIBUTE_OUT], + dist->ifname ? dist->ifname : "", + VTY_NEWLINE); + write++; + } + + if (dist->prefix[DISTRIBUTE_IN]) + { + vty_out (vty, " distribute-list prefix %s in %s%s", + dist->prefix[DISTRIBUTE_IN], + dist->ifname ? dist->ifname : "", + VTY_NEWLINE); + write++; + } + + if (dist->prefix[DISTRIBUTE_OUT]) + { + vty_out (vty, " distribute-list prefix %s out %s%s", + dist->prefix[DISTRIBUTE_OUT], + dist->ifname ? dist->ifname : "", + VTY_NEWLINE); + write++; + } + } + return write; +} + +/* Clear all distribute list. */ +void +distribute_list_reset () +{ + hash_clean (disthash, (void (*) (void *)) distribute_free); +} + +/* Initialize distribute list related hash. */ +void +distribute_list_init (int node) +{ + disthash = hash_create (distribute_hash_make, distribute_cmp); + + if (node == RIP_NODE) + { + install_element (RIP_NODE, &distribute_list_all_cmd); + install_element (RIP_NODE, &no_distribute_list_all_cmd); + install_element (RIP_NODE, &distribute_list_cmd); + install_element (RIP_NODE, &no_distribute_list_cmd); + install_element (RIP_NODE, &distribute_list_prefix_all_cmd); + install_element (RIP_NODE, &no_distribute_list_prefix_all_cmd); + install_element (RIP_NODE, &distribute_list_prefix_cmd); + install_element (RIP_NODE, &no_distribute_list_prefix_cmd); + } + else + { + install_element (RIPNG_NODE, &ipv6_distribute_list_all_cmd); + install_element (RIPNG_NODE, &no_ipv6_distribute_list_all_cmd); + install_element (RIPNG_NODE, &ipv6_distribute_list_cmd); + install_element (RIPNG_NODE, &no_ipv6_distribute_list_cmd); + install_element (RIPNG_NODE, &ipv6_distribute_list_prefix_all_cmd); + install_element (RIPNG_NODE, &no_ipv6_distribute_list_prefix_all_cmd); + install_element (RIPNG_NODE, &ipv6_distribute_list_prefix_cmd); + install_element (RIPNG_NODE, &no_ipv6_distribute_list_prefix_cmd); + } +} diff --git a/lib/distribute.h b/lib/distribute.h new file mode 100644 index 0000000..330126b --- /dev/null +++ b/lib/distribute.h @@ -0,0 +1,57 @@ +/* Distribute list functions header + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_DISTRIBUTE_H +#define _ZEBRA_DISTRIBUTE_H + +/* Disctirubte list types. */ +enum distribute_type +{ + DISTRIBUTE_IN, + DISTRIBUTE_OUT, + DISTRIBUTE_MAX +}; + +struct distribute +{ + /* Name of the interface. */ + char *ifname; + + /* Filter name of `in' and `out' */ + char *list[DISTRIBUTE_MAX]; + + /* prefix-list name of `in' and `out' */ + char *prefix[DISTRIBUTE_MAX]; +}; + +/* Prototypes for distribute-list. */ +void distribute_list_init (int); +void distribute_list_reset (void); +void distribute_list_add_hook (void (*) (struct distribute *)); +void distribute_list_delete_hook (void (*) (struct distribute *)); +struct distribute *distribute_lookup (char *); +int config_write_distribute (struct vty *); +int config_show_distribute (struct vty *); + +enum filter_type distribute_apply_in (struct interface *, struct prefix *); +enum filter_type distribute_apply_out (struct interface *, struct prefix *); + +#endif /* _ZEBRA_DISTRIBUTE_H */ diff --git a/lib/filter.c b/lib/filter.c new file mode 100644 index 0000000..a5c01b6 --- /dev/null +++ b/lib/filter.c @@ -0,0 +1,2058 @@ +/* Route filtering function. + * Copyright (C) 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "filter.h" +#include "memory.h" +#include "command.h" +#include "sockunion.h" +#include "buffer.h" + +struct filter_cisco +{ + /* Cisco access-list */ + int extended; + struct in_addr addr; + struct in_addr addr_mask; + struct in_addr mask; + struct in_addr mask_mask; +}; + +struct filter_zebra +{ + /* If this filter is "exact" match then this flag is set. */ + int exact; + + /* Prefix information. */ + struct prefix prefix; +}; + +/* Filter element of access list */ +struct filter +{ + /* For doubly linked list. */ + struct filter *next; + struct filter *prev; + + /* Filter type information. */ + enum filter_type type; + + /* Cisco access-list */ + int cisco; + + union + { + struct filter_cisco cfilter; + struct filter_zebra zfilter; + } u; +}; + +/* List of access_list. */ +struct access_list_list +{ + struct access_list *head; + struct access_list *tail; +}; + +/* Master structure of access_list. */ +struct access_master +{ + /* List of access_list which name is number. */ + struct access_list_list num; + + /* List of access_list which name is string. */ + struct access_list_list str; + + /* Hook function which is executed when new access_list is added. */ + void (*add_hook) (); + + /* Hook function which is executed when access_list is deleted. */ + void (*delete_hook) (); +}; + +/* Static structure for IPv4 access_list's master. */ +static struct access_master access_master_ipv4 = +{ + {NULL, NULL}, + {NULL, NULL}, + NULL, + NULL, +}; + +#ifdef HAVE_IPV6 +/* Static structure for IPv6 access_list's master. */ +static struct access_master access_master_ipv6 = +{ + {NULL, NULL}, + {NULL, NULL}, + NULL, + NULL, +}; +#endif /* HAVE_IPV6 */ + +struct access_master * +access_master_get (afi_t afi) +{ + if (afi == AFI_IP) + return &access_master_ipv4; +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + return &access_master_ipv6; +#endif /* HAVE_IPV6 */ + return NULL; +} + +/* Allocate new filter structure. */ +struct filter * +filter_new () +{ + return (struct filter *) XCALLOC (MTYPE_ACCESS_FILTER, + sizeof (struct filter)); +} + +void +filter_free (struct filter *filter) +{ + XFREE (MTYPE_ACCESS_FILTER, filter); +} + +/* Return string of filter_type. */ +static char * +filter_type_str (struct filter *filter) +{ + switch (filter->type) + { + case FILTER_PERMIT: + return "permit"; + break; + case FILTER_DENY: + return "deny"; + break; + case FILTER_DYNAMIC: + return "dynamic"; + break; + default: + return ""; + break; + } +} + +/* If filter match to the prefix then return 1. */ +static int +filter_match_cisco (struct filter *mfilter, struct prefix *p) +{ + struct filter_cisco *filter; + struct in_addr mask; + u_int32_t check_addr; + u_int32_t check_mask; + + filter = &mfilter->u.cfilter; + check_addr = p->u.prefix4.s_addr & ~filter->addr_mask.s_addr; + + if (filter->extended) + { + masklen2ip (p->prefixlen, &mask); + check_mask = mask.s_addr & ~filter->mask_mask.s_addr; + + if (memcmp (&check_addr, &filter->addr.s_addr, 4) == 0 + && memcmp (&check_mask, &filter->mask.s_addr, 4) == 0) + return 1; + } + else if (memcmp (&check_addr, &filter->addr.s_addr, 4) == 0) + return 1; + + return 0; +} + +/* If filter match to the prefix then return 1. */ +static int +filter_match_zebra (struct filter *mfilter, struct prefix *p) +{ + struct filter_zebra *filter; + + filter = &mfilter->u.zfilter; + + if (filter->prefix.family == p->family) + { + if (filter->exact) + { + if (filter->prefix.prefixlen == p->prefixlen) + return prefix_match (&filter->prefix, p); + else + return 0; + } + else + return prefix_match (&filter->prefix, p); + } + else + return 0; +} + +/* Allocate new access list structure. */ +struct access_list * +access_list_new () +{ + return (struct access_list *) XCALLOC (MTYPE_ACCESS_LIST, + sizeof (struct access_list)); +} + +/* Free allocated access_list. */ +void +access_list_free (struct access_list *access) +{ + XFREE (MTYPE_ACCESS_LIST, access); +} + +/* Delete access_list from access_master and free it. */ +void +access_list_delete (struct access_list *access) +{ + struct filter *filter; + struct filter *next; + struct access_list_list *list; + struct access_master *master; + + for (filter = access->head; filter; filter = next) + { + next = filter->next; + filter_free (filter); + } + + master = access->master; + + if (access->type == ACCESS_TYPE_NUMBER) + list = &master->num; + else + list = &master->str; + + if (access->next) + access->next->prev = access->prev; + else + list->tail = access->prev; + + if (access->prev) + access->prev->next = access->next; + else + list->head = access->next; + + if (access->name) + XFREE (MTYPE_ACCESS_LIST_STR, access->name); + + if (access->remark) + XFREE (MTYPE_TMP, access->remark); + + access_list_free (access); +} + +/* Insert new access list to list of access_list. Each acceess_list + is sorted by the name. */ +struct access_list * +access_list_insert (afi_t afi, char *name) +{ + int i; + long number; + struct access_list *access; + struct access_list *point; + struct access_list_list *alist; + struct access_master *master; + + master = access_master_get (afi); + if (master == NULL) + return NULL; + + /* Allocate new access_list and copy given name. */ + access = access_list_new (); + access->name = XSTRDUP (MTYPE_ACCESS_LIST_STR, name); + access->master = master; + + /* If name is made by all digit character. We treat it as + number. */ + for (number = 0, i = 0; i < strlen (name); i++) + { + if (isdigit ((int) name[i])) + number = (number * 10) + (name[i] - '0'); + else + break; + } + + /* In case of name is all digit character */ + if (i == strlen (name)) + { + access->type = ACCESS_TYPE_NUMBER; + + /* Set access_list to number list. */ + alist = &master->num; + + for (point = alist->head; point; point = point->next) + if (atol (point->name) >= number) + break; + } + else + { + access->type = ACCESS_TYPE_STRING; + + /* Set access_list to string list. */ + alist = &master->str; + + /* Set point to insertion point. */ + for (point = alist->head; point; point = point->next) + if (strcmp (point->name, name) >= 0) + break; + } + + /* In case of this is the first element of master. */ + if (alist->head == NULL) + { + alist->head = alist->tail = access; + return access; + } + + /* In case of insertion is made at the tail of access_list. */ + if (point == NULL) + { + access->prev = alist->tail; + alist->tail->next = access; + alist->tail = access; + return access; + } + + /* In case of insertion is made at the head of access_list. */ + if (point == alist->head) + { + access->next = alist->head; + alist->head->prev = access; + alist->head = access; + return access; + } + + /* Insertion is made at middle of the access_list. */ + access->next = point; + access->prev = point->prev; + + if (point->prev) + point->prev->next = access; + point->prev = access; + + return access; +} + +/* Lookup access_list from list of access_list by name. */ +struct access_list * +access_list_lookup (afi_t afi, char *name) +{ + struct access_list *access; + struct access_master *master; + + if (name == NULL) + return NULL; + + master = access_master_get (afi); + if (master == NULL) + return NULL; + + for (access = master->num.head; access; access = access->next) + if (strcmp (access->name, name) == 0) + return access; + + for (access = master->str.head; access; access = access->next) + if (strcmp (access->name, name) == 0) + return access; + + return NULL; +} + +/* Get access list from list of access_list. If there isn't matched + access_list create new one and return it. */ +struct access_list * +access_list_get (afi_t afi, char *name) +{ + struct access_list *access; + + access = access_list_lookup (afi, name); + if (access == NULL) + access = access_list_insert (afi, name); + return access; +} + +/* Apply access list to object (which should be struct prefix *). */ +enum filter_type +access_list_apply (struct access_list *access, void *object) +{ + struct filter *filter; + struct prefix *p; + + p = (struct prefix *) object; + + if (access == NULL) + return FILTER_DENY; + + for (filter = access->head; filter; filter = filter->next) + { + if (filter->cisco) + { + if (filter_match_cisco (filter, p)) + return filter->type; + } + else + { + if (filter_match_zebra (filter, p)) + return filter->type; + } + } + + return FILTER_DENY; +} + +/* Add hook function. */ +void +access_list_add_hook (void (*func) (struct access_list *access)) +{ + access_master_ipv4.add_hook = func; +#ifdef HAVE_IPV6 + access_master_ipv6.add_hook = func; +#endif /* HAVE_IPV6 */ +} + +/* Delete hook function. */ +void +access_list_delete_hook (void (*func) (struct access_list *access)) +{ + access_master_ipv4.delete_hook = func; +#ifdef HAVE_IPV6 + access_master_ipv6.delete_hook = func; +#endif /* HAVE_IPV6 */ +} + +/* Add new filter to the end of specified access_list. */ +void +access_list_filter_add (struct access_list *access, struct filter *filter) +{ + filter->next = NULL; + filter->prev = access->tail; + + if (access->tail) + access->tail->next = filter; + else + access->head = filter; + access->tail = filter; + + /* Run hook function. */ + if (access->master->add_hook) + (*access->master->add_hook) (access); +} + +/* If access_list has no filter then return 1. */ +static int +access_list_empty (struct access_list *access) +{ + if (access->head == NULL && access->tail == NULL) + return 1; + else + return 0; +} + +/* Delete filter from specified access_list. If there is hook + function execute it. */ +void +access_list_filter_delete (struct access_list *access, struct filter *filter) +{ + struct access_master *master; + + master = access->master; + + if (filter->next) + filter->next->prev = filter->prev; + else + access->tail = filter->prev; + + if (filter->prev) + filter->prev->next = filter->next; + else + access->head = filter->next; + + filter_free (filter); + + /* If access_list becomes empty delete it from access_master. */ + if (access_list_empty (access)) + access_list_delete (access); + + /* Run hook function. */ + if (master->delete_hook) + (*master->delete_hook) (access); +} + +/* + deny Specify packets to reject + permit Specify packets to forward + dynamic ? +*/ + +/* + Hostname or A.B.C.D Address to match + any Any source host + host A single host address +*/ + +struct filter * +filter_lookup_cisco (struct access_list *access, struct filter *mnew) +{ + struct filter *mfilter; + struct filter_cisco *filter; + struct filter_cisco *new; + + new = &mnew->u.cfilter; + + for (mfilter = access->head; mfilter; mfilter = mfilter->next) + { + filter = &mfilter->u.cfilter; + + if (filter->extended) + { + if (mfilter->type == mnew->type + && filter->addr.s_addr == new->addr.s_addr + && filter->addr_mask.s_addr == new->addr_mask.s_addr + && filter->mask.s_addr == new->mask.s_addr + && filter->mask_mask.s_addr == new->mask_mask.s_addr) + return mfilter; + } + else + { + if (mfilter->type == mnew->type + && filter->addr.s_addr == new->addr.s_addr + && filter->addr_mask.s_addr == new->addr_mask.s_addr) + return mfilter; + } + } + + return NULL; +} + +struct filter * +filter_lookup_zebra (struct access_list *access, struct filter *mnew) +{ + struct filter *mfilter; + struct filter_zebra *filter; + struct filter_zebra *new; + + new = &mnew->u.zfilter; + + for (mfilter = access->head; mfilter; mfilter = mfilter->next) + { + filter = &mfilter->u.zfilter; + + if (filter->exact == new->exact + && mfilter->type == mnew->type + && prefix_same (&filter->prefix, &new->prefix)) + return mfilter; + } + return NULL; +} + +int +vty_access_list_remark_unset (struct vty *vty, afi_t afi, char *name) +{ + struct access_list *access; + + access = access_list_lookup (afi, name); + if (! access) + { + vty_out (vty, "%% access-list %s doesn't exist%s", name, + VTY_NEWLINE); + return CMD_WARNING; + } + + if (access->remark) + { + XFREE (MTYPE_TMP, access->remark); + access->remark = NULL; + } + + if (access->head == NULL && access->tail == NULL && access->remark == NULL) + access_list_delete (access); + + return CMD_SUCCESS; +} + +int +filter_set_cisco (struct vty *vty, char *name_str, char *type_str, + char *addr_str, char *addr_mask_str, + char *mask_str, char *mask_mask_str, + int extended, int set) +{ + int ret; + enum filter_type type; + struct filter *mfilter; + struct filter_cisco *filter; + struct access_list *access; + struct in_addr addr; + struct in_addr addr_mask; + struct in_addr mask; + struct in_addr mask_mask; + + /* Check of filter type. */ + if (strncmp (type_str, "p", 1) == 0) + type = FILTER_PERMIT; + else if (strncmp (type_str, "d", 1) == 0) + type = FILTER_DENY; + else + { + vty_out (vty, "%% filter type must be permit or deny%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = inet_aton (addr_str, &addr); + if (ret <= 0) + { + vty_out (vty, "%%Inconsistent address and mask%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = inet_aton (addr_mask_str, &addr_mask); + if (ret <= 0) + { + vty_out (vty, "%%Inconsistent address and mask%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (extended) + { + ret = inet_aton (mask_str, &mask); + if (ret <= 0) + { + vty_out (vty, "%%Inconsistent address and mask%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ret = inet_aton (mask_mask_str, &mask_mask); + if (ret <= 0) + { + vty_out (vty, "%%Inconsistent address and mask%s", + VTY_NEWLINE); + return CMD_WARNING; + } + } + + mfilter = filter_new(); + mfilter->type = type; + mfilter->cisco = 1; + filter = &mfilter->u.cfilter; + filter->extended = extended; + filter->addr.s_addr = addr.s_addr & ~addr_mask.s_addr; + filter->addr_mask.s_addr = addr_mask.s_addr; + + if (extended) + { + filter->mask.s_addr = mask.s_addr & ~mask_mask.s_addr; + filter->mask_mask.s_addr = mask_mask.s_addr; + } + + /* Install new filter to the access_list. */ + access = access_list_get (AFI_IP, name_str); + + if (set) + { + if (filter_lookup_cisco (access, mfilter)) + filter_free (mfilter); + else + access_list_filter_add (access, mfilter); + } + else + { + struct filter *delete_filter; + + delete_filter = filter_lookup_cisco (access, mfilter); + if (delete_filter) + access_list_filter_delete (access, delete_filter); + + filter_free (mfilter); + } + + return CMD_SUCCESS; +} + +/* Standard access-list */ +DEFUN (access_list_standard, + access_list_standard_cmd, + "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D", + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Address to match\n" + "Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], argv[3], + NULL, NULL, 0, 1); +} + +DEFUN (access_list_standard_nomask, + access_list_standard_nomask_cmd, + "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D", + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Address to match\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0", + NULL, NULL, 0, 1); +} + +DEFUN (access_list_standard_host, + access_list_standard_host_cmd, + "access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D", + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "A single host address\n" + "Address to match\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0", + NULL, NULL, 0, 1); +} + +DEFUN (access_list_standard_any, + access_list_standard_any_cmd, + "access-list (<1-99>|<1300-1999>) (deny|permit) any", + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any source host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", NULL, NULL, 0, 1); +} + +DEFUN (no_access_list_standard, + no_access_list_standard_cmd, + "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Address to match\n" + "Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], argv[3], + NULL, NULL, 0, 0); +} + +DEFUN (no_access_list_standard_nomask, + no_access_list_standard_nomask_cmd, + "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Address to match\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0", + NULL, NULL, 0, 0); +} + +DEFUN (no_access_list_standard_host, + no_access_list_standard_host_cmd, + "no access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "A single host address\n" + "Address to match\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0", + NULL, NULL, 0, 0); +} + +DEFUN (no_access_list_standard_any, + no_access_list_standard_any_cmd, + "no access-list (<1-99>|<1300-1999>) (deny|permit) any", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any source host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", NULL, NULL, 0, 0); +} + +/* Extended access-list */ +DEFUN (access_list_extended, + access_list_extended_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "Destination address\n" + "Destination Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], 1 ,1); +} + +DEFUN (access_list_extended_mask_any, + access_list_extended_mask_any_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "Any destination host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + argv[3], "0.0.0.0", + "255.255.255.255", 1, 1); +} + +DEFUN (access_list_extended_any_mask, + access_list_extended_any_mask_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "Destination address\n" + "Destination Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", argv[2], + argv[3], 1, 1); +} + +DEFUN (access_list_extended_any_any, + access_list_extended_any_any_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip any any", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "Any destination host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", "0.0.0.0", + "255.255.255.255", 1, 1); +} + +DEFUN (access_list_extended_mask_host, + access_list_extended_mask_host_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "A single destination host\n" + "Destination address\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + argv[3], argv[4], + "0.0.0.0", 1, 1); +} + +DEFUN (access_list_extended_host_mask, + access_list_extended_host_mask_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "Destination address\n" + "Destination Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + "0.0.0.0", argv[3], + argv[4], 1, 1); +} + +DEFUN (access_list_extended_host_host, + access_list_extended_host_host_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "A single destination host\n" + "Destination address\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + "0.0.0.0", argv[3], + "0.0.0.0", 1, 1); +} + +DEFUN (access_list_extended_any_host, + access_list_extended_any_host_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "A single destination host\n" + "Destination address\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", argv[2], + "0.0.0.0", 1, 1); +} + +DEFUN (access_list_extended_host_any, + access_list_extended_host_any_cmd, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "Any destination host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + "0.0.0.0", "0.0.0.0", + "255.255.255.255", 1, 1); +} + +DEFUN (no_access_list_extended, + no_access_list_extended_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "Destination address\n" + "Destination Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], 1, 0); +} + +DEFUN (no_access_list_extended_mask_any, + no_access_list_extended_mask_any_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "Any destination host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + argv[3], "0.0.0.0", + "255.255.255.255", 1, 0); +} + +DEFUN (no_access_list_extended_any_mask, + no_access_list_extended_any_mask_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "Destination address\n" + "Destination Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", argv[2], + argv[3], 1, 0); +} + +DEFUN (no_access_list_extended_any_any, + no_access_list_extended_any_any_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any any", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "Any destination host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", "0.0.0.0", + "255.255.255.255", 1, 0); +} + +DEFUN (no_access_list_extended_mask_host, + no_access_list_extended_mask_host_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "A single destination host\n" + "Destination address\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + argv[3], argv[4], + "0.0.0.0", 1, 0); +} + +DEFUN (no_access_list_extended_host_mask, + no_access_list_extended_host_mask_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "Destination address\n" + "Destination Wildcard bits\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + "0.0.0.0", argv[3], + argv[4], 1, 0); +} + +DEFUN (no_access_list_extended_host_host, + no_access_list_extended_host_host_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "A single destination host\n" + "Destination address\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + "0.0.0.0", argv[3], + "0.0.0.0", 1, 0); +} + +DEFUN (no_access_list_extended_any_host, + no_access_list_extended_any_host_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "A single destination host\n" + "Destination address\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0", + "255.255.255.255", argv[2], + "0.0.0.0", 1, 0); +} + +DEFUN (no_access_list_extended_host_any, + no_access_list_extended_host_any_cmd, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any", + NO_STR + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "Any destination host\n") +{ + return filter_set_cisco (vty, argv[0], argv[1], argv[2], + "0.0.0.0", "0.0.0.0", + "255.255.255.255", 1, 0); +} + +int +filter_set_zebra (struct vty *vty, char *name_str, char *type_str, + afi_t afi, char *prefix_str, int exact, int set) +{ + int ret; + enum filter_type type; + struct filter *mfilter; + struct filter_zebra *filter; + struct access_list *access; + struct prefix p; + + /* Check of filter type. */ + if (strncmp (type_str, "p", 1) == 0) + type = FILTER_PERMIT; + else if (strncmp (type_str, "d", 1) == 0) + type = FILTER_DENY; + else + { + vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check string format of prefix and prefixlen. */ + if (afi == AFI_IP) + { + ret = str2prefix_ipv4 (prefix_str, (struct prefix_ipv4 *)&p); + if (ret <= 0) + { + vty_out (vty, "IP address prefix/prefixlen is malformed%s", + VTY_NEWLINE); + return CMD_WARNING; + } + } +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + { + ret = str2prefix_ipv6 (prefix_str, (struct prefix_ipv6 *) &p); + if (ret <= 0) + { + vty_out (vty, "IPv6 address prefix/prefixlen is malformed%s", + VTY_NEWLINE); + return CMD_WARNING; + } + } +#endif /* HAVE_IPV6 */ + else + return CMD_WARNING; + + mfilter = filter_new (); + mfilter->type = type; + filter = &mfilter->u.zfilter; + prefix_copy (&filter->prefix, &p); + + /* "exact-match" */ + if (exact) + filter->exact = 1; + + /* Install new filter to the access_list. */ + access = access_list_get (afi, name_str); + + if (set) + { + if (filter_lookup_zebra (access, mfilter)) + filter_free (mfilter); + else + access_list_filter_add (access, mfilter); + } + else + { + struct filter *delete_filter; + + delete_filter = filter_lookup_zebra (access, mfilter); + if (delete_filter) + access_list_filter_delete (access, delete_filter); + + filter_free (mfilter); + } + + return CMD_SUCCESS; +} + +/* Zebra access-list */ +DEFUN (access_list, + access_list_cmd, + "access-list WORD (deny|permit) A.B.C.D/M", + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 0, 1); +} + +DEFUN (access_list_exact, + access_list_exact_cmd, + "access-list WORD (deny|permit) A.B.C.D/M exact-match", + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n" + "Exact match of the prefixes\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 1, 1); +} + +DEFUN (access_list_any, + access_list_any_cmd, + "access-list WORD (deny|permit) any", + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, "0.0.0.0/0", 0, 1); +} + +DEFUN (no_access_list, + no_access_list_cmd, + "no access-list WORD (deny|permit) A.B.C.D/M", + NO_STR + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 0, 0); +} + +DEFUN (no_access_list_exact, + no_access_list_exact_cmd, + "no access-list WORD (deny|permit) A.B.C.D/M exact-match", + NO_STR + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n" + "Exact match of the prefixes\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 1, 0); +} + +DEFUN (no_access_list_any, + no_access_list_any_cmd, + "no access-list WORD (deny|permit) any", + NO_STR + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, "0.0.0.0/0", 0, 0); +} + +DEFUN (no_access_list_all, + no_access_list_all_cmd, + "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list name\n") +{ + struct access_list *access; + struct access_master *master; + + /* Looking up access_list. */ + access = access_list_lookup (AFI_IP, argv[0]); + if (access == NULL) + { + vty_out (vty, "%% access-list %s doesn't exist%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + master = access->master; + + /* Delete all filter from access-list. */ + access_list_delete (access); + + /* Run hook function. */ + if (master->delete_hook) + (*master->delete_hook) (access); + + return CMD_SUCCESS; +} + +DEFUN (access_list_remark, + access_list_remark_cmd, + "access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE", + "Add an access list entry\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list\n" + "Access list entry comment\n" + "Comment up to 100 characters\n") +{ + struct access_list *access; + struct buffer *b; + int i; + + access = access_list_get (AFI_IP, argv[0]); + + if (access->remark) + { + XFREE (MTYPE_TMP, access->remark); + access->remark = NULL; + } + + /* Below is remark get codes. */ + b = buffer_new (1024); + for (i = 1; i < argc; i++) + { + buffer_putstr (b, (u_char *)argv[i]); + buffer_putc (b, ' '); + } + buffer_putc (b, '\0'); + + access->remark = buffer_getstr (b); + + buffer_free (b); + + return CMD_SUCCESS; +} + +DEFUN (no_access_list_remark, + no_access_list_remark_cmd, + "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list\n" + "Access list entry comment\n") +{ + return vty_access_list_remark_unset (vty, AFI_IP, argv[0]); +} + +ALIAS (no_access_list_remark, + no_access_list_remark_arg_cmd, + "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE", + NO_STR + "Add an access list entry\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list\n" + "Access list entry comment\n" + "Comment up to 100 characters\n"); + +#ifdef HAVE_IPV6 +DEFUN (ipv6_access_list, + ipv6_access_list_cmd, + "ipv6 access-list WORD (deny|permit) X:X::X:X/M", + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 3ffe:506::/32\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 0, 1); +} + +DEFUN (ipv6_access_list_exact, + ipv6_access_list_exact_cmd, + "ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match", + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 3ffe:506::/32\n" + "Exact match of the prefixes\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 1, 1); +} + +DEFUN (ipv6_access_list_any, + ipv6_access_list_any_cmd, + "ipv6 access-list WORD (deny|permit) any", + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any prefixi to match\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, "::/0", 0, 1); +} + +DEFUN (no_ipv6_access_list, + no_ipv6_access_list_cmd, + "no ipv6 access-list WORD (deny|permit) X:X::X:X/M", + NO_STR + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 3ffe:506::/32\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 0, 0); +} + +DEFUN (no_ipv6_access_list_exact, + no_ipv6_access_list_exact_cmd, + "no ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match", + NO_STR + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 3ffe:506::/32\n" + "Exact match of the prefixes\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 1, 0); +} + +DEFUN (no_ipv6_access_list_any, + no_ipv6_access_list_any_cmd, + "no ipv6 access-list WORD (deny|permit) any", + NO_STR + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any prefixi to match\n") +{ + return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, "::/0", 0, 0); +} + + +DEFUN (no_ipv6_access_list_all, + no_ipv6_access_list_all_cmd, + "no ipv6 access-list WORD", + NO_STR + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n") +{ + struct access_list *access; + struct access_master *master; + + /* Looking up access_list. */ + access = access_list_lookup (AFI_IP6, argv[0]); + if (access == NULL) + { + vty_out (vty, "%% access-list %s doesn't exist%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + master = access->master; + + /* Delete all filter from access-list. */ + access_list_delete (access); + + /* Run hook function. */ + if (master->delete_hook) + (*master->delete_hook) (access); + + return CMD_SUCCESS; +} + +DEFUN (ipv6_access_list_remark, + ipv6_access_list_remark_cmd, + "ipv6 access-list WORD remark .LINE", + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Access list entry comment\n" + "Comment up to 100 characters\n") +{ + struct access_list *access; + struct buffer *b; + int i; + + access = access_list_get (AFI_IP6, argv[0]); + + if (access->remark) + { + XFREE (MTYPE_TMP, access->remark); + access->remark = NULL; + } + + /* Below is remark get codes. */ + b = buffer_new (1024); + for (i = 1; i < argc; i++) + { + buffer_putstr (b, (u_char *)argv[i]); + buffer_putc (b, ' '); + } + buffer_putc (b, '\0'); + + access->remark = buffer_getstr (b); + + buffer_free (b); + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_access_list_remark, + no_ipv6_access_list_remark_cmd, + "no ipv6 access-list WORD remark", + NO_STR + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Access list entry comment\n") +{ + return vty_access_list_remark_unset (vty, AFI_IP6, argv[0]); +} + +ALIAS (no_ipv6_access_list_remark, + no_ipv6_access_list_remark_arg_cmd, + "no ipv6 access-list WORD remark .LINE", + NO_STR + IPV6_STR + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Access list entry comment\n" + "Comment up to 100 characters\n"); +#endif /* HAVE_IPV6 */ + +void config_write_access_zebra (struct vty *, struct filter *); +void config_write_access_cisco (struct vty *, struct filter *); + +/* show access-list command. */ +int +filter_show (struct vty *vty, char *name, afi_t afi) +{ + struct access_list *access; + struct access_master *master; + struct filter *mfilter; + struct filter_cisco *filter; + int write = 0; + + master = access_master_get (afi); + if (master == NULL) + return 0; + + for (access = master->num.head; access; access = access->next) + { + if (name && strcmp (access->name, name) != 0) + continue; + + write = 1; + + for (mfilter = access->head; mfilter; mfilter = mfilter->next) + { + filter = &mfilter->u.cfilter; + + if (write) + { + vty_out (vty, "%s IP%s access list %s%s", + mfilter->cisco ? + (filter->extended ? "Extended" : "Standard") : "Zebra", + afi == AFI_IP6 ? "v6" : "", + access->name, VTY_NEWLINE); + write = 0; + } + + vty_out (vty, " %s%s", filter_type_str (mfilter), + mfilter->type == FILTER_DENY ? " " : ""); + + if (! mfilter->cisco) + config_write_access_zebra (vty, mfilter); + else if (filter->extended) + config_write_access_cisco (vty, mfilter); + else + { + if (filter->addr_mask.s_addr == 0xffffffff) + vty_out (vty, " any%s", VTY_NEWLINE); + else + { + vty_out (vty, " %s", inet_ntoa (filter->addr)); + if (filter->addr_mask.s_addr != 0) + vty_out (vty, ", wildcard bits %s", inet_ntoa (filter->addr_mask)); + vty_out (vty, "%s", VTY_NEWLINE); + } + } + } + } + + for (access = master->str.head; access; access = access->next) + { + if (name && strcmp (access->name, name) != 0) + continue; + + write = 1; + + for (mfilter = access->head; mfilter; mfilter = mfilter->next) + { + filter = &mfilter->u.cfilter; + + if (write) + { + vty_out (vty, "%s IP%s access list %s%s", + mfilter->cisco ? + (filter->extended ? "Extended" : "Standard") : "Zebra", + afi == AFI_IP6 ? "v6" : "", + access->name, VTY_NEWLINE); + write = 0; + } + + vty_out (vty, " %s%s", filter_type_str (mfilter), + mfilter->type == FILTER_DENY ? " " : ""); + + if (! mfilter->cisco) + config_write_access_zebra (vty, mfilter); + else if (filter->extended) + config_write_access_cisco (vty, mfilter); + else + { + if (filter->addr_mask.s_addr == 0xffffffff) + vty_out (vty, " any%s", VTY_NEWLINE); + else + { + vty_out (vty, " %s", inet_ntoa (filter->addr)); + if (filter->addr_mask.s_addr != 0) + vty_out (vty, ", wildcard bits %s", inet_ntoa (filter->addr_mask)); + vty_out (vty, "%s", VTY_NEWLINE); + } + } + } + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_access_list, + show_ip_access_list_cmd, + "show ip access-list", + SHOW_STR + IP_STR + "List IP access lists\n") +{ + return filter_show (vty, NULL, AFI_IP); +} + +DEFUN (show_ip_access_list_name, + show_ip_access_list_name_cmd, + "show ip access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)", + SHOW_STR + IP_STR + "List IP access lists\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list\n") +{ + return filter_show (vty, argv[0], AFI_IP); +} + +#ifdef HAVE_IPV6 +DEFUN (show_ipv6_access_list, + show_ipv6_access_list_cmd, + "show ipv6 access-list", + SHOW_STR + IPV6_STR + "List IPv6 access lists\n") +{ + return filter_show (vty, NULL, AFI_IP6); +} + +DEFUN (show_ipv6_access_list_name, + show_ipv6_access_list_name_cmd, + "show ipv6 access-list WORD", + SHOW_STR + IPV6_STR + "List IPv6 access lists\n" + "IPv6 zebra access-list\n") +{ + return filter_show (vty, argv[0], AFI_IP6); +} +#endif /* HAVE_IPV6 */ + +void +config_write_access_cisco (struct vty *vty, struct filter *mfilter) +{ + struct filter_cisco *filter; + + filter = &mfilter->u.cfilter; + + if (filter->extended) + { + vty_out (vty, " ip"); + if (filter->addr_mask.s_addr == 0xffffffff) + vty_out (vty, " any"); + else if (filter->addr_mask.s_addr == 0) + vty_out (vty, " host %s", inet_ntoa (filter->addr)); + else + { + vty_out (vty, " %s", inet_ntoa (filter->addr)); + vty_out (vty, " %s", inet_ntoa (filter->addr_mask)); + } + + if (filter->mask_mask.s_addr == 0xffffffff) + vty_out (vty, " any"); + else if (filter->mask_mask.s_addr == 0) + vty_out (vty, " host %s", inet_ntoa (filter->mask)); + else + { + vty_out (vty, " %s", inet_ntoa (filter->mask)); + vty_out (vty, " %s", inet_ntoa (filter->mask_mask)); + } + vty_out (vty, "%s", VTY_NEWLINE); + } + else + { + if (filter->addr_mask.s_addr == 0xffffffff) + vty_out (vty, " any%s", VTY_NEWLINE); + else + { + vty_out (vty, " %s", inet_ntoa (filter->addr)); + if (filter->addr_mask.s_addr != 0) + vty_out (vty, " %s", inet_ntoa (filter->addr_mask)); + vty_out (vty, "%s", VTY_NEWLINE); + } + } +} + +void +config_write_access_zebra (struct vty *vty, struct filter *mfilter) +{ + struct filter_zebra *filter; + struct prefix *p; + char buf[BUFSIZ]; + + filter = &mfilter->u.zfilter; + p = &filter->prefix; + + if (p->prefixlen == 0 && ! filter->exact) + vty_out (vty, " any"); + else + vty_out (vty, " %s/%d%s", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen, + filter->exact ? " exact-match" : ""); + + vty_out (vty, "%s", VTY_NEWLINE); +} + +int +config_write_access (struct vty *vty, afi_t afi) +{ + struct access_list *access; + struct access_master *master; + struct filter *mfilter; + int write = 0; + + master = access_master_get (afi); + if (master == NULL) + return 0; + + for (access = master->num.head; access; access = access->next) + { + if (access->remark) + { + vty_out (vty, "%saccess-list %s remark %s%s", + afi == AFI_IP ? "" : "ipv6 ", + access->name, access->remark, + VTY_NEWLINE); + write++; + } + + for (mfilter = access->head; mfilter; mfilter = mfilter->next) + { + vty_out (vty, "%saccess-list %s %s", + afi == AFI_IP ? "" : "ipv6 ", + access->name, + filter_type_str (mfilter)); + + if (mfilter->cisco) + config_write_access_cisco (vty, mfilter); + else + config_write_access_zebra (vty, mfilter); + + write++; + } + } + + for (access = master->str.head; access; access = access->next) + { + if (access->remark) + { + vty_out (vty, "%saccess-list %s remark %s%s", + afi == AFI_IP ? "" : "ipv6 ", + access->name, access->remark, + VTY_NEWLINE); + write++; + } + + for (mfilter = access->head; mfilter; mfilter = mfilter->next) + { + vty_out (vty, "%saccess-list %s %s", + afi == AFI_IP ? "" : "ipv6 ", + access->name, + filter_type_str (mfilter)); + + if (mfilter->cisco) + config_write_access_cisco (vty, mfilter); + else + config_write_access_zebra (vty, mfilter); + + write++; + } + } + return write; +} + +/* Access-list node. */ +struct cmd_node access_node = +{ + ACCESS_NODE, + "", /* Access list has no interface. */ + 1 +}; + +int +config_write_access_ipv4 (struct vty *vty) +{ + return config_write_access (vty, AFI_IP); +} + +void +access_list_reset_ipv4 () +{ + struct access_list *access; + struct access_list *next; + struct access_master *master; + + master = access_master_get (AFI_IP); + if (master == NULL) + return; + + for (access = master->num.head; access; access = next) + { + next = access->next; + access_list_delete (access); + } + for (access = master->str.head; access; access = next) + { + next = access->next; + access_list_delete (access); + } + + assert (master->num.head == NULL); + assert (master->num.tail == NULL); + + assert (master->str.head == NULL); + assert (master->str.tail == NULL); +} + +/* Install vty related command. */ +void +access_list_init_ipv4 () +{ + install_node (&access_node, config_write_access_ipv4); + + install_element (ENABLE_NODE, &show_ip_access_list_cmd); + install_element (ENABLE_NODE, &show_ip_access_list_name_cmd); + + /* Zebra access-list */ + install_element (CONFIG_NODE, &access_list_cmd); + install_element (CONFIG_NODE, &access_list_exact_cmd); + install_element (CONFIG_NODE, &access_list_any_cmd); + install_element (CONFIG_NODE, &no_access_list_cmd); + install_element (CONFIG_NODE, &no_access_list_exact_cmd); + install_element (CONFIG_NODE, &no_access_list_any_cmd); + + /* Standard access-list */ + install_element (CONFIG_NODE, &access_list_standard_cmd); + install_element (CONFIG_NODE, &access_list_standard_nomask_cmd); + install_element (CONFIG_NODE, &access_list_standard_host_cmd); + install_element (CONFIG_NODE, &access_list_standard_any_cmd); + install_element (CONFIG_NODE, &no_access_list_standard_cmd); + install_element (CONFIG_NODE, &no_access_list_standard_nomask_cmd); + install_element (CONFIG_NODE, &no_access_list_standard_host_cmd); + install_element (CONFIG_NODE, &no_access_list_standard_any_cmd); + + /* Extended access-list */ + install_element (CONFIG_NODE, &access_list_extended_cmd); + install_element (CONFIG_NODE, &access_list_extended_any_mask_cmd); + install_element (CONFIG_NODE, &access_list_extended_mask_any_cmd); + install_element (CONFIG_NODE, &access_list_extended_any_any_cmd); + install_element (CONFIG_NODE, &access_list_extended_host_mask_cmd); + install_element (CONFIG_NODE, &access_list_extended_mask_host_cmd); + install_element (CONFIG_NODE, &access_list_extended_host_host_cmd); + install_element (CONFIG_NODE, &access_list_extended_any_host_cmd); + install_element (CONFIG_NODE, &access_list_extended_host_any_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_any_mask_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_mask_any_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_any_any_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_host_mask_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_mask_host_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_host_host_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_any_host_cmd); + install_element (CONFIG_NODE, &no_access_list_extended_host_any_cmd); + + install_element (CONFIG_NODE, &access_list_remark_cmd); + install_element (CONFIG_NODE, &no_access_list_all_cmd); + install_element (CONFIG_NODE, &no_access_list_remark_cmd); + install_element (CONFIG_NODE, &no_access_list_remark_arg_cmd); +} + +#ifdef HAVE_IPV6 +struct cmd_node access_ipv6_node = +{ + ACCESS_IPV6_NODE, + "", + 1 +}; + +int +config_write_access_ipv6 (struct vty *vty) +{ + return config_write_access (vty, AFI_IP6); +} + +void +access_list_reset_ipv6 () +{ + struct access_list *access; + struct access_list *next; + struct access_master *master; + + master = access_master_get (AFI_IP6); + if (master == NULL) + return; + + for (access = master->num.head; access; access = next) + { + next = access->next; + access_list_delete (access); + } + for (access = master->str.head; access; access = next) + { + next = access->next; + access_list_delete (access); + } + + assert (master->num.head == NULL); + assert (master->num.tail == NULL); + + assert (master->str.head == NULL); + assert (master->str.tail == NULL); +} + +void +access_list_init_ipv6 () +{ + install_node (&access_ipv6_node, config_write_access_ipv6); + + install_element (ENABLE_NODE, &show_ipv6_access_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_access_list_name_cmd); + + install_element (CONFIG_NODE, &ipv6_access_list_cmd); + install_element (CONFIG_NODE, &ipv6_access_list_exact_cmd); + install_element (CONFIG_NODE, &ipv6_access_list_any_cmd); + install_element (CONFIG_NODE, &no_ipv6_access_list_exact_cmd); + install_element (CONFIG_NODE, &no_ipv6_access_list_cmd); + install_element (CONFIG_NODE, &no_ipv6_access_list_any_cmd); + + install_element (CONFIG_NODE, &no_ipv6_access_list_all_cmd); + install_element (CONFIG_NODE, &ipv6_access_list_remark_cmd); + install_element (CONFIG_NODE, &no_ipv6_access_list_remark_cmd); + install_element (CONFIG_NODE, &no_ipv6_access_list_remark_arg_cmd); +} +#endif /* HAVE_IPV6 */ + +void +access_list_init () +{ + access_list_init_ipv4 (); +#ifdef HAVE_IPV6 + access_list_init_ipv6(); +#endif /* HAVE_IPV6 */ +} + +void +access_list_reset () +{ + access_list_reset_ipv4 (); +#ifdef HAVE_IPV6 + access_list_reset_ipv6(); +#endif /* HAVE_IPV6 */ +} diff --git a/lib/filter.h b/lib/filter.h new file mode 100644 index 0000000..077ac2f --- /dev/null +++ b/lib/filter.h @@ -0,0 +1,67 @@ +/* + * Route filtering function. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_FILTER_H +#define _ZEBRA_FILTER_H + +#include "if.h" + +/* Filter type is made by `permit', `deny' and `dynamic'. */ +enum filter_type +{ + FILTER_DENY, + FILTER_PERMIT, + FILTER_DYNAMIC +}; + +enum access_type +{ + ACCESS_TYPE_STRING, + ACCESS_TYPE_NUMBER +}; + +/* Access list */ +struct access_list +{ + char *name; + char *remark; + + struct access_master *master; + + enum access_type type; + + struct access_list *next; + struct access_list *prev; + + struct filter *head; + struct filter *tail; +}; + +/* Prototypes for access-list. */ +void access_list_init (void); +void access_list_reset (void); +void access_list_add_hook (void (*func)(struct access_list *)); +void access_list_delete_hook (void (*func)(struct access_list *)); +struct access_list *access_list_lookup (afi_t, char *); +enum filter_type access_list_apply (struct access_list *, void *); + +#endif /* _ZEBRA_FILTER_H */ diff --git a/lib/getopt.c b/lib/getopt.c new file mode 100644 index 0000000..426b29b --- /dev/null +++ b/lib/getopt.c @@ -0,0 +1,1054 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98 + Free Software Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@gnu.org. + + 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, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +# ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include +# define my_index strchr +#else + +# if HAVE_STRING_H +# include +# else +# include +# endif + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv (); +#endif + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +# ifdef text_set_element +text_set_element (__libc_subinit, store_args_and_env); +# endif /* text_set_element */ + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + } + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/lib/getopt.h b/lib/getopt.h new file mode 100644 index 0000000..fb30719 --- /dev/null +++ b/lib/getopt.h @@ -0,0 +1,133 @@ +/* Declarations for getopt. + Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@gnu.org. + + 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, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (__STDC__) && __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* getopt.h */ diff --git a/lib/getopt1.c b/lib/getopt1.c new file mode 100644 index 0000000..ff25737 --- /dev/null +++ b/lib/getopt1.c @@ -0,0 +1,190 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 + Free Software Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@gnu.org. + + 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, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "getopt.h" + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/lib/hash.c b/lib/hash.c new file mode 100644 index 0000000..4097507 --- /dev/null +++ b/lib/hash.c @@ -0,0 +1,182 @@ +/* Hash routine. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "hash.h" +#include "memory.h" + +/* Allocate a new hash. */ +struct hash * +hash_create_size (unsigned int size, + unsigned int (*hash_key) (), int (*hash_cmp) ()) +{ + struct hash *hash; + + hash = XMALLOC (MTYPE_HASH, sizeof (struct hash)); + hash->index = XMALLOC (MTYPE_HASH_INDEX, + sizeof (struct hash_backet *) * size); + memset (hash->index, 0, sizeof (struct hash_backet *) * size); + hash->size = size; + hash->hash_key = hash_key; + hash->hash_cmp = hash_cmp; + hash->count = 0; + + return hash; +} + +/* Allocate a new hash with default hash size. */ +struct hash * +hash_create (unsigned int (*hash_key) (), int (*hash_cmp) ()) +{ + return hash_create_size (HASHTABSIZE, hash_key, hash_cmp); +} + +/* Utility function for hash_get(). When this function is specified + as alloc_func, return arugment as it is. This function is used for + intern already allocated value. */ +void * +hash_alloc_intern (void *arg) +{ + return arg; +} + +/* Lookup and return hash backet in hash. If there is no + corresponding hash backet and alloc_func is specified, create new + hash backet. */ +void * +hash_get (struct hash *hash, void *data, void * (*alloc_func) ()) +{ + unsigned int key; + unsigned int index; + void *newdata; + struct hash_backet *backet; + + key = (*hash->hash_key) (data); + index = key % hash->size; + + for (backet = hash->index[index]; backet != NULL; backet = backet->next) + if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) + return backet->data; + + if (alloc_func) + { + newdata = (*alloc_func) (data); + if (newdata == NULL) + return NULL; + + backet = XMALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet)); + backet->data = newdata; + backet->key = key; + backet->next = hash->index[index]; + hash->index[index] = backet; + hash->count++; + return backet->data; + } + return NULL; +} + +/* Hash lookup. */ +void * +hash_lookup (struct hash *hash, void *data) +{ + return hash_get (hash, data, NULL); +} + +/* This function release registered value from specified hash. When + release is successfully finished, return the data pointer in the + hash backet. */ +void * +hash_release (struct hash *hash, void *data) +{ + void *ret; + unsigned int key; + unsigned int index; + struct hash_backet *backet; + struct hash_backet *pp; + + key = (*hash->hash_key) (data); + index = key % hash->size; + + for (backet = pp = hash->index[index]; backet; backet = backet->next) + { + if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) + { + if (backet == pp) + hash->index[index] = backet->next; + else + pp->next = backet->next; + + ret = backet->data; + XFREE (MTYPE_HASH_BACKET, backet); + hash->count--; + return ret; + } + pp = backet; + } + return NULL; +} + +/* Iterator function for hash. */ +void +hash_iterate (struct hash *hash, + void (*func) (struct hash_backet *, void *), void *arg) +{ + int i; + struct hash_backet *hb; + + for (i = 0; i < hash->size; i++) + for (hb = hash->index[i]; hb; hb = hb->next) + (*func) (hb, arg); +} + +/* Clean up hash. */ +void +hash_clean (struct hash *hash, void (*free_func) (void *)) +{ + int i; + struct hash_backet *hb; + struct hash_backet *next; + + for (i = 0; i < hash->size; i++) + { + for (hb = hash->index[i]; hb; hb = next) + { + next = hb->next; + + if (free_func) + (*free_func) (hb->data); + + XFREE (MTYPE_HASH_BACKET, hb); + hash->count--; + } + hash->index[i] = NULL; + } +} + +/* Free hash memory. You may call hash_clean before call this + function. */ +void +hash_free (struct hash *hash) +{ + XFREE (MTYPE_HASH_INDEX, hash->index); + XFREE (MTYPE_HASH, hash); +} diff --git a/lib/hash.h b/lib/hash.h new file mode 100644 index 0000000..715e53b --- /dev/null +++ b/lib/hash.h @@ -0,0 +1,71 @@ +/* Hash routine. + Copyright (C) 1998 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your +option) any later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef _ZEBRA_HASH_H +#define _ZEBRA_HASH_H + +/* Default hash table size. */ +#define HASHTABSIZE 1024 + +struct hash_backet +{ + /* Linked list. */ + struct hash_backet *next; + + /* Hash key. */ + unsigned int key; + + /* Data. */ + void *data; +}; + +struct hash +{ + /* Hash backet. */ + struct hash_backet **index; + + /* Hash table size. */ + unsigned int size; + + /* Key make function. */ + unsigned int (*hash_key) (); + + /* Data compare function. */ + int (*hash_cmp) (); + + /* Backet alloc. */ + unsigned long count; +}; + +struct hash *hash_create (unsigned int (*) (), int (*) ()); +struct hash *hash_create_size (unsigned int, unsigned int (*) (), int (*) ()); + +void *hash_get (struct hash *, void *, void * (*) ()); +void *hash_alloc_intern (void *); +void *hash_lookup (struct hash *, void *); +void *hash_release (struct hash *, void *); + +void hash_iterate (struct hash *, + void (*) (struct hash_backet *, void *), void *); + +void hash_clean (struct hash *, void (*) (void *)); +void hash_free (struct hash *); + +#endif /* _ZEBRA_HASH_H */ diff --git a/lib/if.c b/lib/if.c new file mode 100644 index 0000000..bbf22ab --- /dev/null +++ b/lib/if.c @@ -0,0 +1,713 @@ +/* + * Interface functions. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "if.h" +#include "sockunion.h" +#include "prefix.h" +#include "zebra/connected.h" +#include "memory.h" +#include "table.h" +#include "buffer.h" +#include "str.h" +#include "log.h" + +/* Master list of interfaces. */ +struct list *iflist; + +/* One for each program. This structure is needed to store hooks. */ +struct if_master +{ + int (*if_new_hook) (struct interface *); + int (*if_delete_hook) (struct interface *); +} if_master; + +/* Create new interface structure. */ +struct interface * +if_new () +{ + struct interface *ifp; + + ifp = XMALLOC (MTYPE_IF, sizeof (struct interface)); + memset (ifp, 0, sizeof (struct interface)); + return ifp; +} + +struct interface * +if_create () +{ + struct interface *ifp; + + ifp = if_new (); + + listnode_add (iflist, ifp); + ifp->connected = list_new (); + ifp->connected->del = (void (*) (void *)) connected_free; + + if (if_master.if_new_hook) + (*if_master.if_new_hook) (ifp); + + return ifp; +} + +/* Delete and free interface structure. */ +void +if_delete (struct interface *ifp) +{ + listnode_delete (iflist, ifp); + + if (if_master.if_delete_hook) + (*if_master.if_delete_hook) (ifp); + + /* Free connected address list */ + list_delete (ifp->connected); + + XFREE (MTYPE_IF, ifp); +} + +/* Add hook to interface master. */ +void +if_add_hook (int type, int (*func)(struct interface *ifp)) +{ + switch (type) { + case IF_NEW_HOOK: + if_master.if_new_hook = func; + break; + case IF_DELETE_HOOK: + if_master.if_delete_hook = func; + break; + default: + break; + } +} + +/* Interface existance check by index. */ +struct interface * +if_lookup_by_index (unsigned int index) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + if (ifp->ifindex == index) + return ifp; + } + return NULL; +} + +char * +ifindex2ifname (unsigned int index) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + if (ifp->ifindex == index) + return ifp->name; + } + return "unknown"; +} + +/* Interface existance check by interface name. */ +struct interface * +if_lookup_by_name (char *name) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + if (strncmp (name, ifp->name, sizeof ifp->name) == 0) + return ifp; + } + return NULL; +} + +/* Lookup interface by IPv4 address. */ +struct interface * +if_lookup_exact_address (struct in_addr src) +{ + listnode node; + listnode cnode; + struct interface *ifp; + struct prefix *p; + struct connected *c; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + c = getdata (cnode); + + p = c->address; + + if (p && p->family == AF_INET) + { + if (IPV4_ADDR_SAME (&p->u.prefix4, &src)) + return ifp; + } + } + } + return NULL; +} + +/* Lookup interface by IPv4 address. */ +struct interface * +if_lookup_address (struct in_addr src) +{ + listnode node; + struct prefix addr; + struct prefix best; + listnode cnode; + struct interface *ifp; + struct prefix *p; + struct connected *c; + struct interface *match; + + /* Zero structures - get rid of rubbish from stack */ + memset(&addr, 0, sizeof(addr)); + memset(&best, 0, sizeof(best)); + + addr.family = AF_INET; + addr.u.prefix4 = src; + addr.prefixlen = IPV4_MAX_BITLEN; + + match = NULL; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + c = getdata (cnode); + + if (if_is_pointopoint (ifp)) + { + p = c->address; + + if (p && p->family == AF_INET) + { +#ifdef OLD_RIB /* PTP links are conventionally identified + by the address of the far end - MAG */ + if (IPV4_ADDR_SAME (&p->u.prefix4, &src)) + return ifp; +#endif + p = c->destination; + if (p && IPV4_ADDR_SAME (&p->u.prefix4, &src)) + return ifp; + } + } + else + { + p = c->address; + + if (p->family == AF_INET) + { + if (prefix_match (p, &addr) && p->prefixlen > best.prefixlen) + { + best = *p; + match = ifp; + } + } + } + } + } + return match; +} + +/* Get interface by name if given name interface doesn't exist create + one. */ +struct interface * +if_get_by_name (char *name) +{ + struct interface *ifp; + + ifp = if_lookup_by_name (name); + if (ifp == NULL) + { + ifp = if_create (); + strncpy (ifp->name, name, IFNAMSIZ); + } + return ifp; +} + +/* Does interface up ? */ +int +if_is_up (struct interface *ifp) +{ + return ifp->flags & IFF_UP; +} + +/* Is this loopback interface ? */ +int +if_is_loopback (struct interface *ifp) +{ + return ifp->flags & IFF_LOOPBACK; +} + +/* Does this interface support broadcast ? */ +int +if_is_broadcast (struct interface *ifp) +{ + return ifp->flags & IFF_BROADCAST; +} + +/* Does this interface support broadcast ? */ +int +if_is_pointopoint (struct interface *ifp) +{ + return ifp->flags & IFF_POINTOPOINT; +} + +/* Does this interface support multicast ? */ +int +if_is_multicast (struct interface *ifp) +{ + return ifp->flags & IFF_MULTICAST; +} + +/* Printout flag information into log */ +const char * +if_flag_dump (unsigned long flag) +{ + int separator = 0; + static char logbuf[BUFSIZ]; + +#define IFF_OUT_LOG(X,STR) \ + if ((X) && (flag & (X))) \ + { \ + if (separator) \ + strlcat (logbuf, ",", BUFSIZ); \ + else \ + separator = 1; \ + strlcat (logbuf, STR, BUFSIZ); \ + } + + strlcpy (logbuf, " <", BUFSIZ); + IFF_OUT_LOG (IFF_UP, "UP"); + IFF_OUT_LOG (IFF_BROADCAST, "BROADCAST"); + IFF_OUT_LOG (IFF_DEBUG, "DEBUG"); + IFF_OUT_LOG (IFF_LOOPBACK, "LOOPBACK"); + IFF_OUT_LOG (IFF_POINTOPOINT, "POINTOPOINT"); + IFF_OUT_LOG (IFF_NOTRAILERS, "NOTRAILERS"); + IFF_OUT_LOG (IFF_RUNNING, "RUNNING"); + IFF_OUT_LOG (IFF_NOARP, "NOARP"); + IFF_OUT_LOG (IFF_PROMISC, "PROMISC"); + IFF_OUT_LOG (IFF_ALLMULTI, "ALLMULTI"); + IFF_OUT_LOG (IFF_OACTIVE, "OACTIVE"); + IFF_OUT_LOG (IFF_SIMPLEX, "SIMPLEX"); + IFF_OUT_LOG (IFF_LINK0, "LINK0"); + IFF_OUT_LOG (IFF_LINK1, "LINK1"); + IFF_OUT_LOG (IFF_LINK2, "LINK2"); + IFF_OUT_LOG (IFF_MULTICAST, "MULTICAST"); + + strlcat (logbuf, ">", BUFSIZ); + + return logbuf; +} + +/* For debugging */ +void +if_dump (struct interface *ifp) +{ + listnode node; + + zlog_info ("Interface %s index %d metric %d mtu %d %s", + ifp->name, ifp->ifindex, ifp->metric, ifp->mtu, + if_flag_dump (ifp->flags)); + + for (node = listhead (ifp->connected); node; nextnode (node)) + ; +} + +/* Interface printing for all interface. */ +void +if_dump_all () +{ + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + if_dump (getdata (node)); +} + +DEFUN (interface_desc, + interface_desc_cmd, + "description .LINE", + "Interface specific description\n" + "Characters describing this interface\n") +{ + int i; + struct interface *ifp; + struct buffer *b; + + if (argc == 0) + return CMD_SUCCESS; + + ifp = vty->index; + if (ifp->desc) + XFREE (0, ifp->desc); + + b = buffer_new (1024); + for (i = 0; i < argc; i++) + { + buffer_putstr (b, (u_char *)argv[i]); + buffer_putc (b, ' '); + } + buffer_putc (b, '\0'); + + ifp->desc = buffer_getstr (b); + buffer_free (b); + + return CMD_SUCCESS; +} + +DEFUN (no_interface_desc, + no_interface_desc_cmd, + "no description", + NO_STR + "Interface specific description\n") +{ + struct interface *ifp; + + ifp = vty->index; + if (ifp->desc) + XFREE (0, ifp->desc); + ifp->desc = NULL; + + return CMD_SUCCESS; +} + + +/* See also wrapper function zebra_interface() in zebra/interface.c */ +DEFUN (interface, + interface_cmd, + "interface IFNAME", + "Select an interface to configure\n" + "Interface's name\n") +{ + struct interface *ifp; + + ifp = if_lookup_by_name (argv[0]); + + if (ifp == NULL) + { + ifp = if_create (); + strncpy (ifp->name, argv[0], INTERFACE_NAMSIZ); + } + vty->index = ifp; + vty->node = INTERFACE_NODE; + + return CMD_SUCCESS; +} + +/* For debug purpose. */ +DEFUN (show_address, + show_address_cmd, + "show address", + SHOW_STR + "address\n") +{ + listnode node; + listnode node2; + struct interface *ifp; + struct connected *ifc; + struct prefix *p; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + for (node2 = listhead (ifp->connected); node2; nextnode (node2)) + { + ifc = getdata (node2); + p = ifc->address; + + if (p->family == AF_INET) + vty_out (vty, "%s/%d%s", inet_ntoa (p->u.prefix4), p->prefixlen, + VTY_NEWLINE); + } + } + return CMD_SUCCESS; +} + +/* Allocate connected structure. */ +struct connected * +connected_new () +{ + struct connected *new = XMALLOC (MTYPE_CONNECTED, sizeof (struct connected)); + memset (new, 0, sizeof (struct connected)); + return new; +} + +/* Free connected structure. */ +void +connected_free (struct connected *connected) +{ + if (connected->address) + prefix_free (connected->address); + + if (connected->destination) + prefix_free (connected->destination); + + if (connected->label) + free (connected->label); + + XFREE (MTYPE_CONNECTED, connected); +} + +/* Print if_addr structure. */ +void +connected_log (struct connected *connected, char *str) +{ + struct prefix *p; + struct interface *ifp; + char logbuf[BUFSIZ]; + char buf[BUFSIZ]; + + ifp = connected->ifp; + p = connected->address; + + snprintf (logbuf, BUFSIZ, "%s interface %s %s %s/%d ", + str, ifp->name, prefix_family_str (p), + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + p = connected->destination; + if (p) + { + strncat (logbuf, inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + BUFSIZ - strlen(logbuf)); + } + zlog (NULL, LOG_INFO, logbuf); +} + +/* If two connected address has same prefix return 1. */ +int +connected_same_prefix (struct prefix *p1, struct prefix *p2) +{ + if (p1->family == p2->family) + { + if (p1->family == AF_INET && + IPV4_ADDR_SAME (&p1->u.prefix4, &p2->u.prefix4)) + return 1; +#ifdef HAVE_IPV6 + if (p1->family == AF_INET6 && + IPV6_ADDR_SAME (&p1->u.prefix6, &p2->u.prefix6)) + return 1; +#endif /* HAVE_IPV6 */ + } + return 0; +} + +struct connected * +connected_delete_by_prefix (struct interface *ifp, struct prefix *p) +{ + struct listnode *node; + struct listnode *next; + struct connected *ifc; + + /* In case of same prefix come, replace it with new one. */ + for (node = listhead (ifp->connected); node; node = next) + { + ifc = getdata (node); + next = node->next; + + if (connected_same_prefix (ifc->address, p)) + { + listnode_delete (ifp->connected, ifc); + return ifc; + } + } + return NULL; +} + +/* Check the connected information is PtP style or not. */ +int +ifc_pointopoint (struct connected *ifc) +{ + struct prefix *p; + int ptp = 0; + + /* When interface has PtP flag. */ + if (if_is_pointopoint (ifc->ifp)) + return 1; + + /* RFC3021 PtP check. */ + p = ifc->address; + + if (p->family == AF_INET) + ptp = (p->prefixlen >= IPV4_MAX_PREFIXLEN - 1); +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + ptp = (p->prefixlen >= IPV6_MAX_PREFIXLEN - 1); +#endif /* HAVE_IPV6 */ + + return ptp; +} + +#ifndef HAVE_IF_NAMETOINDEX +unsigned int +if_nametoindex (const char *name) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + if (strcmp (ifp->name, name) == 0) + return ifp->ifindex; + } + return 0; +} +#endif + +#ifndef HAVE_IF_INDEXTONAME +char * +if_indextoname (unsigned int ifindex, char *name) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + if (ifp->ifindex == ifindex) + { + memcpy (name, ifp->name, IFNAMSIZ); + return ifp->name; + } + } + return NULL; +} +#endif + +/* Interface looking up by interface's address. */ + +/* Interface's IPv4 address reverse lookup table. */ +struct route_table *ifaddr_ipv4_table; +/* struct route_table *ifaddr_ipv6_table; */ + +void +ifaddr_ipv4_add (struct in_addr *ifaddr, struct interface *ifp) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = *ifaddr; + + rn = route_node_get (ifaddr_ipv4_table, (struct prefix *) &p); + if (rn) + { + route_unlock_node (rn); + zlog_info ("ifaddr_ipv4_add(): address %s is already added", + inet_ntoa (*ifaddr)); + return; + } + rn->info = ifp; +} + +void +ifaddr_ipv4_delete (struct in_addr *ifaddr, struct interface *ifp) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = *ifaddr; + + rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p); + if (! rn) + { + zlog_info ("ifaddr_ipv4_delete(): can't find address %s", + inet_ntoa (*ifaddr)); + return; + } + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); +} + +/* Lookup interface by interface's IP address or interface index. */ +struct interface * +ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex) +{ + struct prefix_ipv4 p; + struct route_node *rn; + struct interface *ifp; + listnode node; + + if (addr) + { + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = *addr; + + rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p); + if (! rn) + return NULL; + + ifp = rn->info; + route_unlock_node (rn); + return ifp; + } + else + { + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + if (ifp->ifindex == ifindex) + return ifp; + } + } + return NULL; +} + +/* Initialize interface list. */ +void +if_init () +{ + iflist = list_new (); + ifaddr_ipv4_table = route_table_init (); + + if (iflist) + return; + + memset (&if_master, 0, sizeof if_master); +} diff --git a/lib/if.h b/lib/if.h new file mode 100644 index 0000000..3896d18 --- /dev/null +++ b/lib/if.h @@ -0,0 +1,222 @@ +/* Interface related header. + Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your +option) any later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef _ZEBRA_IF_H +#define _ZEBRA_IF_H + +#include "linklist.h" + +/* + Interface name length. + + Linux define value in /usr/include/linux/if.h. + #define IFNAMSIZ 16 + + FreeBSD define value in /usr/include/net/if.h. + #define IFNAMSIZ 16 +*/ + +#define INTERFACE_NAMSIZ 20 +#define INTERFACE_HWADDR_MAX 20 + +/* Internal If indexes start at 0xFFFFFFFF and go down to 1 greater + than this */ +#define IFINDEX_INTERNBASE 0x80000000 + +#ifdef HAVE_PROC_NET_DEV +struct if_stats +{ + unsigned long rx_packets; /* total packets received */ + unsigned long tx_packets; /* total packets transmitted */ + unsigned long rx_bytes; /* total bytes received */ + unsigned long tx_bytes; /* total bytes transmitted */ + unsigned long rx_errors; /* bad packets received */ + unsigned long tx_errors; /* packet transmit problems */ + unsigned long rx_dropped; /* no space in linux buffers */ + unsigned long tx_dropped; /* no space available in linux */ + unsigned long rx_multicast; /* multicast packets received */ + unsigned long rx_compressed; + unsigned long tx_compressed; + unsigned long collisions; + + /* detailed rx_errors: */ + unsigned long rx_length_errors; + unsigned long rx_over_errors; /* receiver ring buff overflow */ + unsigned long rx_crc_errors; /* recved pkt with crc error */ + unsigned long rx_frame_errors; /* recv'd frame alignment error */ + unsigned long rx_fifo_errors; /* recv'r fifo overrun */ + unsigned long rx_missed_errors; /* receiver missed packet */ + /* detailed tx_errors */ + unsigned long tx_aborted_errors; + unsigned long tx_carrier_errors; + unsigned long tx_fifo_errors; + unsigned long tx_heartbeat_errors; + unsigned long tx_window_errors; +}; +#endif /* HAVE_PROC_NET_DEV */ + +/* Interface structure */ +struct interface +{ + /* Interface name. */ + char name[INTERFACE_NAMSIZ + 1]; + + /* Interface index. */ + unsigned int ifindex; + + /* Zebra internal interface status */ + u_char status; +#define ZEBRA_INTERFACE_ACTIVE (1 << 0) +#define ZEBRA_INTERFACE_SUB (1 << 1) + + /* Interface flags. */ + unsigned long flags; + + /* Interface metric */ + int metric; + + /* Interface MTU. */ + int mtu; + + /* Hardware address. */ +#ifdef HAVE_SOCKADDR_DL + struct sockaddr_dl sdl; +#else + unsigned short hw_type; + u_char hw_addr[INTERFACE_HWADDR_MAX]; + int hw_addr_len; +#endif /* HAVE_SOCKADDR_DL */ + + /* interface bandwidth, kbits */ + unsigned int bandwidth; + + /* description of the interface. */ + char *desc; + + /* Distribute list. */ + void *distribute_in; + void *distribute_out; + + /* Connected address list. */ + list connected; + + /* Daemon specific interface data pointer. */ + void *info; + + /* Statistics fileds. */ +#ifdef HAVE_PROC_NET_DEV + struct if_stats stats; +#endif /* HAVE_PROC_NET_DEV */ +#ifdef HAVE_NET_RT_IFLIST + struct if_data stats; +#endif /* HAVE_NET_RT_IFLIST */ +}; + +/* Connected address structure. */ +struct connected +{ + /* Attached interface. */ + struct interface *ifp; + + /* Flags for configuration. */ + u_char conf; +#define ZEBRA_IFC_REAL (1 << 0) +#define ZEBRA_IFC_CONFIGURED (1 << 1) + + /* Flags for connected address. */ + u_char flags; +#define ZEBRA_IFA_SECONDARY (1 << 0) + + /* Address of connected network. */ + struct prefix *address; + struct prefix *destination; + + /* Label for Linux 2.2.X and upper. */ + char *label; +}; + +/* Interface hook sort. */ +#define IF_NEW_HOOK 0 +#define IF_DELETE_HOOK 1 + +/* There are some interface flags which are only supported by some + operating system. */ + +#ifndef IFF_NOTRAILERS +#define IFF_NOTRAILERS 0x0 +#endif /* IFF_NOTRAILERS */ +#ifndef IFF_OACTIVE +#define IFF_OACTIVE 0x0 +#endif /* IFF_OACTIVE */ +#ifndef IFF_SIMPLEX +#define IFF_SIMPLEX 0x0 +#endif /* IFF_SIMPLEX */ +#ifndef IFF_LINK0 +#define IFF_LINK0 0x0 +#endif /* IFF_LINK0 */ +#ifndef IFF_LINK1 +#define IFF_LINK1 0x0 +#endif /* IFF_LINK1 */ +#ifndef IFF_LINK2 +#define IFF_LINK2 0x0 +#endif /* IFF_LINK2 */ + +/* Prototypes. */ +struct interface *if_new (void); +struct interface *if_create (void); +struct interface *if_lookup_by_index (unsigned int); +struct interface *if_lookup_by_name (char *); +struct interface *if_lookup_exact_address (struct in_addr); +struct interface *if_lookup_address (struct in_addr); +struct interface *if_get_by_name (char *); +void if_delete (struct interface *); +int if_is_up (struct interface *); +int if_is_loopback (struct interface *); +int if_is_broadcast (struct interface *); +int if_is_pointopoint (struct interface *); +int if_is_multicast (struct interface *); +void if_add_hook (int, int (*)(struct interface *)); +void if_init (); +void if_dump_all (); +char *ifindex2ifname (unsigned int); + +/* Connected address functions. */ +struct connected *connected_new (); +void connected_free (struct connected *); +void connected_add (struct interface *, struct connected *); +struct connected *connected_delete_by_prefix (struct interface *, struct prefix *); +int ifc_pointopoint (struct connected *); + +#ifndef HAVE_IF_NAMETOINDEX +unsigned int if_nametoindex (const char *); +#endif +#ifndef HAVE_IF_INDEXTONAME +char *if_indextoname (unsigned int, char *); +#endif + +/* Exported variables. */ +extern list iflist; +extern struct cmd_element interface_desc_cmd; +extern struct cmd_element no_interface_desc_cmd; +extern struct cmd_element interface_cmd; +extern struct cmd_element interface_pseudo_cmd; +extern struct cmd_element no_interface_pseudo_cmd; + +#endif /* _ZEBRA_IF_H */ diff --git a/lib/keychain.c b/lib/keychain.c new file mode 100644 index 0000000..dbf431a --- /dev/null +++ b/lib/keychain.c @@ -0,0 +1,1001 @@ +/* key-chain for authentication. + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your +option) any later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include + +#include "command.h" +#include "memory.h" +#include "linklist.h" +#include "keychain.h" + +/* Master list of key chain. */ +struct list *keychain_list; + +struct keychain * +keychain_new () +{ + struct keychain *new; + new = XMALLOC (MTYPE_KEYCHAIN, sizeof (struct keychain)); + memset (new, 0, sizeof (struct keychain)); + return new; +} + +void +keychain_free (struct keychain *keychain) +{ + XFREE (MTYPE_KEYCHAIN, keychain); +} + +struct key * +key_new () +{ + struct key *new; + new = XMALLOC (MTYPE_KEY, sizeof (struct key)); + memset (new, 0, sizeof (struct key)); + return new; +} + +void +key_free (struct key *key) +{ + XFREE (MTYPE_KEY, key); +} + +struct keychain * +keychain_lookup (char *name) +{ + struct listnode *nn; + struct keychain *keychain; + + if (name == NULL) + return NULL; + + LIST_LOOP (keychain_list, keychain, nn) + { + if (strcmp (keychain->name, name) == 0) + return keychain; + } + return NULL; +} + +int +key_cmp_func (struct key *k1, struct key *k2) +{ + if (k1->index > k2->index) + return 1; + if (k1->index < k2->index) + return -1; + return 0; +} + +void +key_delete_func (struct key *key) +{ + if (key->string) + free (key->string); + key_free (key); +} + +struct keychain * +keychain_get (char *name) +{ + struct keychain *keychain; + + keychain = keychain_lookup (name); + + if (keychain) + return keychain; + + keychain = keychain_new (); + keychain->name = strdup (name); + keychain->key = list_new (); + keychain->key->cmp = (int (*)(void *, void *)) key_cmp_func; + keychain->key->del = (void (*)(void *)) key_delete_func; + listnode_add (keychain_list, keychain); + + return keychain; +} + +void +keychain_delete (struct keychain *keychain) +{ + if (keychain->name) + free (keychain->name); + + list_delete (keychain->key); + listnode_delete (keychain_list, keychain); + keychain_free (keychain); +} + +struct key * +key_lookup (struct keychain *keychain, u_int32_t index) +{ + struct listnode *nn; + struct key *key; + + LIST_LOOP (keychain->key, key, nn) + { + if (key->index == index) + return key; + } + return NULL; +} + +struct key * +key_lookup_for_accept (struct keychain *keychain, u_int32_t index) +{ + struct listnode *nn; + struct key *key; + time_t now; + + now = time (NULL); + + LIST_LOOP (keychain->key, key, nn) + { + if (key->index >= index) + { + if (key->accept.start == 0) + return key; + + if (key->accept.start <= now) + if (key->accept.end >= now || key->accept.end == -1) + return key; + } + } + return NULL; +} + +struct key * +key_match_for_accept (struct keychain *keychain, char *auth_str) +{ + struct listnode *nn; + struct key *key; + time_t now; + + now = time (NULL); + + LIST_LOOP (keychain->key, key, nn) + { + if (key->accept.start == 0 || + (key->accept.start <= now && + (key->accept.end >= now || key->accept.end == -1))) + if (strncmp (key->string, auth_str, 16) == 0) + return key; + } + return NULL; +} + +struct key * +key_lookup_for_send (struct keychain *keychain) +{ + struct listnode *nn; + struct key *key; + time_t now; + + now = time (NULL); + + LIST_LOOP (keychain->key, key, nn) + { + if (key->send.start == 0) + return key; + + if (key->send.start <= now) + if (key->send.end >= now || key->send.end == -1) + return key; + } + return NULL; +} + +struct key * +key_get (struct keychain *keychain, u_int32_t index) +{ + struct key *key; + + key = key_lookup (keychain, index); + + if (key) + return key; + + key = key_new (); + key->index = index; + listnode_add_sort (keychain->key, key); + + return key; +} + +void +key_delete (struct keychain *keychain, struct key *key) +{ + listnode_delete (keychain->key, key); + + if (key->string) + free (key->string); + key_free (key); +} + +DEFUN (key_chain, + key_chain_cmd, + "key chain WORD", + "Authentication key management\n" + "Key-chain management\n" + "Key-chain name\n") +{ + struct keychain *keychain; + + keychain = keychain_get (argv[0]); + vty->index = keychain; + vty->node = KEYCHAIN_NODE; + + return CMD_SUCCESS; +} + +DEFUN (no_key_chain, + no_key_chain_cmd, + "no key chain WORD", + NO_STR + "Authentication key management\n" + "Key-chain management\n" + "Key-chain name\n") +{ + struct keychain *keychain; + + keychain = keychain_lookup (argv[0]); + + if (! keychain) + { + vty_out (vty, "Can't find keychain %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + keychain_delete (keychain); + + return CMD_SUCCESS; +} + +DEFUN (key, + key_cmd, + "key <0-2147483647>", + "Configure a key\n" + "Key identifier number\n") +{ + struct keychain *keychain; + struct key *key; + u_int32_t index; + char *endptr = NULL; + + keychain = vty->index; + + index = strtoul (argv[0], &endptr, 10); + if (index == ULONG_MAX || *endptr != '\0') + { + vty_out (vty, "Key identifier number error%s", VTY_NEWLINE); + return CMD_WARNING; + } + key = key_get (keychain, index); + vty->index_sub = key; + vty->node = KEYCHAIN_KEY_NODE; + + return CMD_SUCCESS; +} + +DEFUN (no_key, + no_key_cmd, + "no key <0-2147483647>", + NO_STR + "Delete a key\n" + "Key identifier number\n") +{ + struct keychain *keychain; + struct key *key; + u_int32_t index; + char *endptr = NULL; + + keychain = vty->index; + + index = strtoul (argv[0], &endptr, 10); + if (index == ULONG_MAX || *endptr != '\0') + { + vty_out (vty, "Key identifier number error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + key = key_lookup (keychain, index); + if (! key) + { + vty_out (vty, "Can't find key %d%s", index, VTY_NEWLINE); + return CMD_WARNING; + } + + key_delete (keychain, key); + + vty->node = KEYCHAIN_NODE; + + return CMD_SUCCESS; +} + +DEFUN (key_string, + key_string_cmd, + "key-string LINE", + "Set key string\n" + "The key\n") +{ + struct key *key; + + key = vty->index_sub; + + if (key->string) + free (key->string); + key->string = strdup (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_key_string, + no_key_string_cmd, + "no key-string [LINE]", + NO_STR + "Unset key string\n" + "The key\n") +{ + struct key *key; + + key = vty->index_sub; + + if (key->string) + { + free (key->string); + key->string = NULL; + } + + return CMD_SUCCESS; +} + +/* Convert HH:MM:SS MON DAY YEAR to time_t value. -1 is returned when + given string is malformed. */ +time_t +key_str2time(char *time_str, char *day_str, char *month_str, char *year_str) +{ + int i = 0; + char *colon; + struct tm tm; + time_t time; + int sec, min, hour; + int day, month, year; + char *endptr = NULL; + + char *month_name[] = + { + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + NULL + }; + + /* Check hour field of time_str. */ + colon = strchr (time_str, ':'); + if (colon == NULL) + return -1; + *colon = '\0'; + + /* Hour must be between 0 and 23. */ + hour = strtoul (time_str, &endptr, 10); + if (hour == ULONG_MAX || *endptr != '\0' || hour < 0 || hour > 23) + return -1; + + /* Check min field of time_str. */ + time_str = colon + 1; + colon = strchr (time_str, ':'); + if (*time_str == '\0' || colon == NULL) + return -1; + *colon = '\0'; + + /* Min must be between 0 and 59. */ + min = strtoul (time_str, &endptr, 10); + if (min == ULONG_MAX || *endptr != '\0' || min < 0 || min > 59) + return -1; + + /* Check sec field of time_str. */ + time_str = colon + 1; + if (*time_str == '\0') + return -1; + + /* Sec must be between 0 and 59. */ + sec = strtoul (time_str, &endptr, 10); + if (sec == ULONG_MAX || *endptr != '\0' || sec < 0 || sec > 59) + return -1; + + /* Check day_str. Day must be <1-31>. */ + day = strtoul (day_str, &endptr, 10); + if (day == ULONG_MAX || *endptr != '\0' || day < 0 || day > 31) + return -1; + + /* Check month_str. Month must match month_name. */ + month = 0; + if (strlen (month_str) >= 3) + for (i = 0; month_name[i]; i++) + if (strncmp (month_str, month_name[i], strlen (month_str)) == 0) + { + month = i; + break; + } + if (! month_name[i]) + return -1; + + /* Check year_str. Year must be <1993-2035>. */ + year = strtoul (year_str, &endptr, 10); + if (year == ULONG_MAX || *endptr != '\0' || year < 1993 || year > 2035) + return -1; + + memset (&tm, 0, sizeof (struct tm)); + tm.tm_sec = sec; + tm.tm_min = min; + tm.tm_hour = hour; + tm.tm_mon = month; + tm.tm_mday = day; + tm.tm_year = year - 1900; + + time = mktime (&tm); + + return time; +} + +int +key_lifetime_set (struct vty *vty, struct key_range *krange, char *stime_str, + char *sday_str, char *smonth_str, char *syear_str, + char *etime_str, char *eday_str, char *emonth_str, + char *eyear_str) +{ + time_t time_start; + time_t time_end; + + time_start = key_str2time (stime_str, sday_str, smonth_str, syear_str); + if (time_start < 0) + { + vty_out (vty, "Malformed time value%s", VTY_NEWLINE); + return CMD_WARNING; + } + time_end = key_str2time (etime_str, eday_str, emonth_str, eyear_str); + + if (time_end < 0) + { + vty_out (vty, "Malformed time value%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (time_end <= time_start) + { + vty_out (vty, "Expire time is not later than start time%s", VTY_NEWLINE); + return CMD_WARNING; + } + + krange->start = time_start; + krange->end = time_end; + + return CMD_SUCCESS; +} + +int +key_lifetime_duration_set (struct vty *vty, struct key_range *krange, + char *stime_str, char *sday_str, char *smonth_str, + char *syear_str, char *duration_str) +{ + time_t time_start; + u_int32_t duration; + char *endptr = NULL; + + time_start = key_str2time (stime_str, sday_str, smonth_str, syear_str); + if (time_start < 0) + { + vty_out (vty, "Malformed time value%s", VTY_NEWLINE); + return CMD_WARNING; + } + krange->start = time_start; + + duration = strtoul (duration_str, &endptr, 10); + if (duration == ULONG_MAX || *endptr != '\0') + { + vty_out (vty, "Malformed duration%s", VTY_NEWLINE); + return CMD_WARNING; + } + krange->duration = 1; + krange->end = time_start + duration; + + return CMD_SUCCESS; +} + +int +key_lifetime_infinite_set (struct vty *vty, struct key_range *krange, + char *stime_str, char *sday_str, char *smonth_str, + char *syear_str) +{ + time_t time_start; + + time_start = key_str2time (stime_str, sday_str, smonth_str, syear_str); + if (time_start < 0) + { + vty_out (vty, "Malformed time value%s", VTY_NEWLINE); + return CMD_WARNING; + } + krange->start = time_start; + + krange->end = -1; + + return CMD_SUCCESS; +} + +DEFUN (accept_lifetime_day_month_day_month, + accept_lifetime_day_month_day_month_cmd, + "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->accept, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], argv[6], argv[7]); +} + +DEFUN (accept_lifetime_day_month_month_day, + accept_lifetime_day_month_month_day_cmd, + "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->accept, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[6], argv[5], argv[7]); +} + +DEFUN (accept_lifetime_month_day_day_month, + accept_lifetime_month_day_day_month_cmd, + "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->accept, argv[0], argv[2], argv[1], + argv[3], argv[4], argv[5], argv[6], argv[7]); +} + +DEFUN (accept_lifetime_month_day_month_day, + accept_lifetime_month_day_month_day_cmd, + "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->accept, argv[0], argv[2], argv[1], + argv[3], argv[4], argv[6], argv[5], argv[7]); +} + +DEFUN (accept_lifetime_infinite_day_month, + accept_lifetime_infinite_day_month_cmd, + "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Never expires") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_infinite_set (vty, &key->accept, argv[0], argv[1], + argv[2], argv[3]); +} + +DEFUN (accept_lifetime_infinite_month_day, + accept_lifetime_infinite_month_day_cmd, + "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Never expires") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_infinite_set (vty, &key->accept, argv[0], argv[2], + argv[1], argv[3]); +} + +DEFUN (accept_lifetime_duration_day_month, + accept_lifetime_duration_day_month_cmd, + "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_duration_set (vty, &key->accept, argv[0], argv[1], + argv[2], argv[3], argv[4]); +} + +DEFUN (accept_lifetime_duration_month_day, + accept_lifetime_duration_month_day_cmd, + "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_duration_set (vty, &key->accept, argv[0], argv[2], + argv[1], argv[3], argv[4]); +} + +DEFUN (send_lifetime_day_month_day_month, + send_lifetime_day_month_day_month_cmd, + "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->send, argv[0], argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6], argv[7]); +} + +DEFUN (send_lifetime_day_month_month_day, + send_lifetime_day_month_month_day_cmd, + "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->send, argv[0], argv[1], argv[2], argv[3], + argv[4], argv[6], argv[5], argv[7]); +} + +DEFUN (send_lifetime_month_day_day_month, + send_lifetime_month_day_day_month_cmd, + "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->send, argv[0], argv[2], argv[1], argv[3], + argv[4], argv[5], argv[6], argv[7]); +} + +DEFUN (send_lifetime_month_day_month_day, + send_lifetime_month_day_month_day_cmd, + "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_set (vty, &key->send, argv[0], argv[2], argv[1], argv[3], + argv[4], argv[6], argv[5], argv[7]); +} + +DEFUN (send_lifetime_infinite_day_month, + send_lifetime_infinite_day_month_cmd, + "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Never expires") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_infinite_set (vty, &key->send, argv[0], argv[1], argv[2], + argv[3]); +} + +DEFUN (send_lifetime_infinite_month_day, + send_lifetime_infinite_month_day_cmd, + "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Never expires") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_infinite_set (vty, &key->send, argv[0], argv[2], argv[1], + argv[3]); +} + +DEFUN (send_lifetime_duration_day_month, + send_lifetime_duration_day_month_cmd, + "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_duration_set (vty, &key->send, argv[0], argv[1], argv[2], + argv[3], argv[4]); +} + +DEFUN (send_lifetime_duration_month_day, + send_lifetime_duration_month_day_cmd, + "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") +{ + struct key *key; + + key = vty->index_sub; + + return key_lifetime_duration_set (vty, &key->send, argv[0], argv[2], argv[1], + argv[3], argv[4]); +} + +struct cmd_node keychain_node = +{ + KEYCHAIN_NODE, + "%s(config-keychain)# ", + 1 +}; + +struct cmd_node keychain_key_node = +{ + KEYCHAIN_KEY_NODE, + "%s(config-keychain-key)# ", + 1 +}; + +int +keychain_strftime (char *buf, int bufsiz, time_t *time) +{ + struct tm *tm; + size_t len; + + tm = localtime (time); + + len = strftime (buf, bufsiz, "%T %b %d %Y", tm); + + return len; +} + +int +keychain_config_write (struct vty *vty) +{ + struct keychain *keychain; + struct key *key; + struct listnode *nn; + struct listnode *nm; + char buf[BUFSIZ]; + + LIST_LOOP (keychain_list, keychain, nn) + { + vty_out (vty, "key chain %s%s", keychain->name, VTY_NEWLINE); + + LIST_LOOP (keychain->key, key, nm) + { + vty_out (vty, " key %d%s", key->index, VTY_NEWLINE); + + if (key->string) + vty_out (vty, " key-string %s%s", key->string, VTY_NEWLINE); + + if (key->accept.start) + { + keychain_strftime (buf, BUFSIZ, &key->accept.start); + vty_out (vty, " accept-lifetime %s", buf); + + if (key->accept.end == -1) + vty_out (vty, " infinite"); + else if (key->accept.duration) + vty_out (vty, " duration %ld", + key->accept.end - key->accept.start); + else + { + keychain_strftime (buf, BUFSIZ, &key->accept.end); + vty_out (vty, " %s", buf); + } + vty_out (vty, "%s", VTY_NEWLINE); + } + + if (key->send.start) + { + keychain_strftime (buf, BUFSIZ, &key->send.start); + vty_out (vty, " send-lifetime %s", buf); + + if (key->send.end == -1) + vty_out (vty, " infinite"); + else if (key->send.duration) + vty_out (vty, " duration %ld", key->send.end - key->send.start); + else + { + keychain_strftime (buf, BUFSIZ, &key->send.end); + vty_out (vty, " %s", buf); + } + vty_out (vty, "%s", VTY_NEWLINE); + } + } + vty_out (vty, "!%s", VTY_NEWLINE); + } + + return 0; +} + +void +keychain_init () +{ + keychain_list = list_new (); + + install_node (&keychain_node, keychain_config_write); + install_node (&keychain_key_node, NULL); + + install_default (KEYCHAIN_NODE); + install_default (KEYCHAIN_KEY_NODE); + + install_element (CONFIG_NODE, &key_chain_cmd); + install_element (CONFIG_NODE, &no_key_chain_cmd); + install_element (KEYCHAIN_NODE, &key_cmd); + install_element (KEYCHAIN_NODE, &no_key_cmd); + + install_element (KEYCHAIN_NODE, &key_chain_cmd); + install_element (KEYCHAIN_NODE, &no_key_chain_cmd); + + install_element (KEYCHAIN_KEY_NODE, &key_string_cmd); + install_element (KEYCHAIN_KEY_NODE, &no_key_string_cmd); + + install_element (KEYCHAIN_KEY_NODE, &key_chain_cmd); + install_element (KEYCHAIN_KEY_NODE, &no_key_chain_cmd); + + install_element (KEYCHAIN_KEY_NODE, &key_cmd); + install_element (KEYCHAIN_KEY_NODE, &no_key_cmd); + + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_month_day_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_month_day_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_month_day_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_month_day_cmd); + + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_month_day_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_month_day_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_month_day_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_day_month_cmd); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_month_day_cmd); +} diff --git a/lib/keychain.h b/lib/keychain.h new file mode 100644 index 0000000..0cfa3d5 --- /dev/null +++ b/lib/keychain.h @@ -0,0 +1,56 @@ +/* key-chain for authentication. + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_KEYCHAIN_H +#define _ZEBRA_KEYCHAIN_H + +struct keychain +{ + char *name; + + struct list *key; +}; + +struct key_range +{ + time_t start; + time_t end; + + u_char duration; +}; + +struct key +{ + u_int32_t index; + + char *string; + + struct key_range send; + struct key_range accept; +}; + +void keychain_init (); +struct keychain *keychain_lookup (char *); +struct key *key_lookup_for_accept (struct keychain *, u_int32_t); +struct key *key_match_for_accept (struct keychain *, char *); +struct key *key_lookup_for_send (struct keychain *); + +#endif /* _ZEBRA_KEYCHAIN_H */ diff --git a/lib/linklist.c b/lib/linklist.c new file mode 100644 index 0000000..5a2b696 --- /dev/null +++ b/lib/linklist.c @@ -0,0 +1,312 @@ +/* Generic linked list routine. + * Copyright (C) 1997, 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "memory.h" + +/* Allocate new list. */ +struct list * +list_new () +{ + struct list *new; + + new = XMALLOC (MTYPE_LINK_LIST, sizeof (struct list)); + memset (new, 0, sizeof (struct list)); + return new; +} + +/* Free list. */ +void +list_free (struct list *l) +{ + XFREE (MTYPE_LINK_LIST, l); +} + +/* Allocate new listnode. Internal use only. */ +static struct listnode * +listnode_new () +{ + struct listnode *node; + + node = XMALLOC (MTYPE_LINK_NODE, sizeof (struct listnode)); + memset (node, 0, sizeof (struct listnode)); + return node; +} + +/* Free listnode. */ +static void +listnode_free (struct listnode *node) +{ + XFREE (MTYPE_LINK_NODE, node); +} + +/* Add new data to the list. */ +void +listnode_add (struct list *list, void *val) +{ + struct listnode *node; + + node = listnode_new (); + + node->prev = list->tail; + node->data = val; + + if (list->head == NULL) + list->head = node; + else + list->tail->next = node; + list->tail = node; + + list->count++; +} + +/* Add new node with sort function. */ +void +listnode_add_sort (struct list *list, void *val) +{ + struct listnode *n; + struct listnode *new; + + new = listnode_new (); + new->data = val; + + if (list->cmp) + { + for (n = list->head; n; n = n->next) + { + if ((*list->cmp) (val, n->data) < 0) + { + new->next = n; + new->prev = n->prev; + + if (n->prev) + n->prev->next = new; + else + list->head = new; + n->prev = new; + list->count++; + return; + } + } + } + + new->prev = list->tail; + + if (list->tail) + list->tail->next = new; + else + list->head = new; + + list->tail = new; + list->count++; +} + +void +listnode_add_after (struct list *list, struct listnode *pp, void *val) +{ + struct listnode *nn; + + nn = listnode_new (); + nn->data = val; + + if (pp == NULL) + { + if (list->head) + list->head->prev = nn; + else + list->tail = nn; + + nn->next = list->head; + nn->prev = pp; + + list->head = nn; + } + else + { + if (pp->next) + pp->next->prev = nn; + else + list->tail = nn; + + nn->next = pp->next; + nn->prev = pp; + + pp->next = nn; + } +} + + +/* Delete specific date pointer from the list. */ +void +listnode_delete (struct list *list, void *val) +{ + struct listnode *node; + + for (node = list->head; node; node = node->next) + { + if (node->data == val) + { + if (node->prev) + node->prev->next = node->next; + else + list->head = node->next; + + if (node->next) + node->next->prev = node->prev; + else + list->tail = node->prev; + + list->count--; + listnode_free (node); + return; + } + } +} + +/* Return first node's data if it is there. */ +void * +listnode_head (struct list *list) +{ + struct listnode *node; + + node = list->head; + + if (node) + return node->data; + return NULL; +} + +/* Delete all listnode from the list. */ +void +list_delete_all_node (struct list *list) +{ + struct listnode *node; + struct listnode *next; + + for (node = list->head; node; node = next) + { + next = node->next; + if (list->del) + (*list->del) (node->data); + listnode_free (node); + } + list->head = list->tail = NULL; + list->count = 0; +} + +/* Delete all listnode then free list itself. */ +void +list_delete (struct list *list) +{ + struct listnode *node; + struct listnode *next; + + for (node = list->head; node; node = next) + { + next = node->next; + if (list->del) + (*list->del) (node->data); + listnode_free (node); + } + list_free (list); +} + +/* Lookup the node which has given data. */ +struct listnode * +listnode_lookup (struct list *list, void *data) +{ + listnode node; + + for (node = list->head; node; nextnode (node)) + if (data == getdata (node)) + return node; + return NULL; +} + +/* Delete the node from list. For ospfd and ospf6d. */ +void +list_delete_node (list list, listnode node) +{ + if (node->prev) + node->prev->next = node->next; + else + list->head = node->next; + if (node->next) + node->next->prev = node->prev; + else + list->tail = node->prev; + list->count--; + listnode_free (node); +} + +/* ospf_spf.c */ +void +list_add_node_prev (list list, listnode current, void *val) +{ + struct listnode *node; + + node = listnode_new (); + node->next = current; + node->data = val; + + if (current->prev == NULL) + list->head = node; + else + current->prev->next = node; + + node->prev = current->prev; + current->prev = node; + + list->count++; +} + +/* ospf_spf.c */ +void +list_add_node_next (list list, listnode current, void *val) +{ + struct listnode *node; + + node = listnode_new (); + node->prev = current; + node->data = val; + + if (current->next == NULL) + list->tail = node; + else + current->next->prev = node; + + node->next = current->next; + current->next = node; + + list->count++; +} + +/* ospf_spf.c */ +void +list_add_list (struct list *l, struct list *m) +{ + struct listnode *n; + + for (n = listhead (m); n; nextnode (n)) + listnode_add (l, n->data); +} diff --git a/lib/linklist.h b/lib/linklist.h new file mode 100644 index 0000000..a91947c --- /dev/null +++ b/lib/linklist.h @@ -0,0 +1,101 @@ +/* Generic linked list + * Copyright (C) 1997, 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_LINKLIST_H +#define _ZEBRA_LINKLIST_H + +typedef struct list *list; +typedef struct listnode *listnode; + +struct listnode +{ + struct listnode *next; + struct listnode *prev; + void *data; +}; + +struct list +{ + struct listnode *head; + struct listnode *tail; + unsigned int count; + int (*cmp) (void *val1, void *val2); + void (*del) (void *val); +}; + +#define nextnode(X) ((X) = (X)->next) +#define listhead(X) ((X)->head) +#define listcount(X) ((X)->count) +#define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL) +#define getdata(X) ((X)->data) + +/* Prototypes. */ +struct list *list_new(); +void list_free (struct list *); + +void listnode_add (struct list *, void *); +void listnode_add_sort (struct list *, void *); +void listnode_add_after (struct list *, struct listnode *, void *); +void listnode_delete (struct list *, void *); +struct listnode *listnode_lookup (struct list *, void *); +void *listnode_head (struct list *); + +void list_delete (struct list *); +void list_delete_all_node (struct list *); + +/* For ospfd and ospf6d. */ +void list_delete_node (list, listnode); + +/* For ospf_spf.c */ +void list_add_node_prev (list, listnode, void *); +void list_add_node_next (list, listnode, void *); +void list_add_list (list, list); + +/* List iteration macro. */ +#define LIST_LOOP(L,V,N) \ + for ((N) = (L)->head; (N); (N) = (N)->next) \ + if (((V) = (N)->data) != NULL) + +/* List node add macro. */ +#define LISTNODE_ADD(L,N) \ + do { \ + (N)->prev = (L)->tail; \ + if ((L)->head == NULL) \ + (L)->head = (N); \ + else \ + (L)->tail->next = (N); \ + (L)->tail = (N); \ + } while (0) + +/* List node delete macro. */ +#define LISTNODE_DELETE(L,N) \ + do { \ + if ((N)->prev) \ + (N)->prev->next = (N)->next; \ + else \ + (L)->head = (N)->next; \ + if ((N)->next) \ + (N)->next->prev = (N)->prev; \ + else \ + (L)->tail = (N)->prev; \ + } while (0) + +#endif /* _ZEBRA_LINKLIST_H */ diff --git a/lib/log.c b/lib/log.c new file mode 100644 index 0000000..88e1dbf --- /dev/null +++ b/lib/log.c @@ -0,0 +1,483 @@ +/* Logging of zebra + * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "memory.h" +#include "command.h" + +struct zlog *zlog_default = NULL; + +const char *zlog_proto_names[] = +{ + "NONE", + "DEFAULT", + "ZEBRA", + "RIP", + "BGP", + "OSPF", + "RIPNG", + "OSPF6", + "MASC", + NULL, +}; + +const char *zlog_priority[] = +{ + "emergencies", + "alerts", + "critical", + "errors", + "warnings", + "notifications", + "informational", + "debugging", + NULL, +}; + + + +/* For time string format. */ +#define TIME_BUF 27 + +/* Utility routine for current time printing. */ +static void +time_print (FILE *fp) +{ + int ret; + char buf [TIME_BUF]; + time_t clock; + struct tm *tm; + + time (&clock); + tm = localtime (&clock); + + ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm); + if (ret == 0) { + zlog_warn ("strftime error"); + } + + fprintf (fp, "%s ", buf); +} + +/* va_list version of zlog. */ +void +vzlog (struct zlog *zl, int priority, const char *format, va_list *args) +{ + /* If zlog is not specified, use default one. */ + if (zl == NULL) + zl = zlog_default; + + /* When zlog_default is also NULL, use stderr for logging. */ + if (zl == NULL) + { + time_print (stderr); + fprintf (stderr, "%s: ", "unknown"); + vfprintf (stderr, format, args[ZLOG_NOLOG_INDEX]); + fprintf (stderr, "\n"); + fflush (stderr); + + /* In this case we return at here. */ + return; + } + + /* only log this information if it has not been masked out */ + if ( priority > zl->maskpri ) + return ; + + /* Syslog output */ + if (zl->flags & ZLOG_SYSLOG) + vsyslog (priority|zlog_default->facility, format, args[ZLOG_SYSLOG_INDEX]); + + /* File output. */ + if (zl->flags & ZLOG_FILE) + { + time_print (zl->fp); + if (zl->record_priority) fprintf (zl->fp, "%s: ", zlog_priority[priority]); + fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]); + vfprintf (zl->fp, format, args[ZLOG_FILE_INDEX]); + fprintf (zl->fp, "\n"); + fflush (zl->fp); + } + + /* stdout output. */ + if (zl->flags & ZLOG_STDOUT) + { + time_print (stdout); + if (zl->record_priority) fprintf (stdout, "%s: ", zlog_priority[priority]); + fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]); + vfprintf (stdout, format, args[ZLOG_STDOUT_INDEX]); + fprintf (stdout, "\n"); + fflush (stdout); + } + + /* stderr output. */ + if (zl->flags & ZLOG_STDERR) + { + time_print (stderr); + if (zl->record_priority) fprintf (stderr, "%s: ", zlog_priority[priority]); + fprintf (stderr, "%s: ", zlog_proto_names[zl->protocol]); + vfprintf (stderr, format, args[ZLOG_STDERR_INDEX]); + fprintf (stderr, "\n"); + fflush (stderr); + } + + /* Terminal monitor. */ + vty_log (zlog_proto_names[zl->protocol], format, args[ZLOG_NOLOG_INDEX]); +} + +void +zlog (struct zlog *zl, int priority, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, priority, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_err (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_ERR, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_warn (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_WARNING, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_info (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_INFO, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_notice (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_NOTICE, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_debug (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_DEBUG, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_err (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_ERR, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_warn (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_WARNING, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_info (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_INFO, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_notice (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_NOTICE, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_debug (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_DEBUG, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + + +/* Open log stream */ +struct zlog * +openzlog (const char *progname, int flags, zlog_proto_t protocol, + int syslog_flags, int syslog_facility) +{ + struct zlog *zl; + + zl = XMALLOC(MTYPE_ZLOG, sizeof (struct zlog)); + memset (zl, 0, sizeof (struct zlog)); + + zl->ident = progname; + zl->flags = flags; + zl->protocol = protocol; + zl->facility = syslog_facility; + zl->maskpri = LOG_DEBUG; + zl->record_priority = 0; + + openlog (progname, syslog_flags, zl->facility); + + return zl; +} + +void +closezlog (struct zlog *zl) +{ + closelog(); + fclose (zl->fp); + + XFREE (MTYPE_ZLOG, zl); +} + +/* Called from command.c. */ +void +zlog_set_flag (struct zlog *zl, int flags) +{ + if (zl == NULL) + zl = zlog_default; + + zl->flags |= flags; +} + +void +zlog_reset_flag (struct zlog *zl, int flags) +{ + if (zl == NULL) + zl = zlog_default; + + zl->flags &= ~flags; +} + +int +zlog_set_file (struct zlog *zl, int flags, char *filename) +{ + FILE *fp; + + /* There is opend file. */ + zlog_reset_file (zl); + + /* Set default zl. */ + if (zl == NULL) + zl = zlog_default; + + /* Open file. */ + fp = fopen (filename, "a"); + if (fp == NULL) + return 0; + + /* Set flags. */ + zl->filename = strdup (filename); + zl->flags |= ZLOG_FILE; + zl->fp = fp; + + return 1; +} + +/* Reset opend file. */ +int +zlog_reset_file (struct zlog *zl) +{ + if (zl == NULL) + zl = zlog_default; + + zl->flags &= ~ZLOG_FILE; + + if (zl->fp) + fclose (zl->fp); + zl->fp = NULL; + + if (zl->filename) + free (zl->filename); + zl->filename = NULL; + + return 1; +} + +/* Reopen log file. */ +int +zlog_rotate (struct zlog *zl) +{ + FILE *fp; + + if (zl == NULL) + zl = zlog_default; + + if (zl->fp) + fclose (zl->fp); + zl->fp = NULL; + + if (zl->filename) + { + fp = fopen (zl->filename, "a"); + if (fp == NULL) + return -1; + zl->fp = fp; + } + + return 1; +} + +static char *zlog_cwd = NULL; + +void +zlog_save_cwd () +{ + char *cwd; + + cwd = getcwd (NULL, MAXPATHLEN); + + zlog_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1); + strcpy (zlog_cwd, cwd); +} + +char * +zlog_get_cwd () +{ + return zlog_cwd; +} + +void +zlog_free_cwd () +{ + if (zlog_cwd) + XFREE (MTYPE_TMP, zlog_cwd); +} + +/* Message lookup function. */ +char * +lookup (struct message *mes, int key) +{ + struct message *pnt; + + for (pnt = mes; pnt->key != 0; pnt++) + if (pnt->key == key) + return pnt->str; + + return ""; +} + +/* Very old hacky version of message lookup function. Still partly + used in bgpd and ospfd. */ +char * +mes_lookup (struct message *meslist, int max, int index) +{ + if (index < 0 || index >= max) + { + zlog_err ("message index out of bound: %d", max); + return NULL; + } + return meslist[index].str; +} diff --git a/lib/log.h b/lib/log.h new file mode 100644 index 0000000..69919b4 --- /dev/null +++ b/lib/log.h @@ -0,0 +1,128 @@ +/* Zebra logging funcions. + * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_LOG_H +#define _ZEBRA_LOG_H + +#include + +#define ZLOG_NOLOG 0x00 +#define ZLOG_FILE 0x01 +#define ZLOG_SYSLOG 0x02 +#define ZLOG_STDOUT 0x04 +#define ZLOG_STDERR 0x08 + +#define ZLOG_NOLOG_INDEX 0 +#define ZLOG_FILE_INDEX 1 +#define ZLOG_SYSLOG_INDEX 2 +#define ZLOG_STDOUT_INDEX 3 +#define ZLOG_STDERR_INDEX 4 +#define ZLOG_MAX_INDEX 5 + +typedef enum +{ + ZLOG_NONE, + ZLOG_DEFAULT, + ZLOG_ZEBRA, + ZLOG_RIP, + ZLOG_BGP, + ZLOG_OSPF, + ZLOG_RIPNG, + ZLOG_OSPF6, + ZLOG_MASC +} zlog_proto_t; + +struct zlog +{ + const char *ident; + zlog_proto_t protocol; + int flags; + FILE *fp; + char *filename; + int syslog; + int stat; + int connected; + int maskpri; /* as per syslog setlogmask */ + int priority; /* as per syslog priority */ + int facility; /* as per syslog facility */ + int record_priority; +}; + +/* Message structure. */ +struct message +{ + int key; + char *str; +}; + +/* Default logging strucutre. */ +extern struct zlog *zlog_default; + +/* Open zlog function */ +struct zlog *openzlog (const char *, int, zlog_proto_t, int, int); + +/* Close zlog function. */ +void closezlog (struct zlog *zl); + +/* GCC have printf type attribute check. */ +#ifdef __GNUC__ +#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) +#else +#define PRINTF_ATTRIBUTE(a,b) +#endif /* __GNUC__ */ + +/* Generic function for zlog. */ +void zlog (struct zlog *zl, int priority, const char *format, ...) PRINTF_ATTRIBUTE(3, 4); + +/* Handy zlog functions. */ +void zlog_err (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); +void zlog_warn (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); +void zlog_info (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); +void zlog_notice (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); +void zlog_debug (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); + +/* For bgpd's peer oriented log. */ +void plog_err (struct zlog *, const char *format, ...); +void plog_warn (struct zlog *, const char *format, ...); +void plog_info (struct zlog *, const char *format, ...); +void plog_notice (struct zlog *, const char *format, ...); +void plog_debug (struct zlog *, const char *format, ...); + +/* Set zlog flags. */ +void zlog_set_flag (struct zlog *zl, int flags); +void zlog_reset_flag (struct zlog *zl, int flags); + +/* Set zlog filename. */ +int zlog_set_file (struct zlog *zl, int flags, char *filename); +int zlog_reset_file (struct zlog *zl); + +/* Rotate log. */ +int zlog_rotate (); + +/* For hackey massage lookup and check */ +#define LOOKUP(x, y) mes_lookup(x, x ## _max, y) + +char *lookup (struct message *, int); +char *mes_lookup (struct message *meslist, int max, int index); + +extern const char *zlog_priority[]; + +#endif /* _ZEBRA_LOG_H */ diff --git a/lib/md5-gnu.h b/lib/md5-gnu.h new file mode 100644 index 0000000..dacc1ae --- /dev/null +++ b/lib/md5-gnu.h @@ -0,0 +1,156 @@ +/* Declaration of functions and data types used for MD5 sum computing + library functions. + Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _MD5_H +#define _MD5_H 1 + +#include + +#if defined HAVE_LIMITS_H || _LIBC +# include +#endif + +/* The following contortions are an attempt to use the C preprocessor + to determine an unsigned integral type that is 32 bits wide. An + alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but + doing that would require that the configure script compile and *run* + the resulting executable. Locally running cross-compiled executables + is usually not possible. */ + +#ifdef _LIBC +# include +typedef u_int32_t md5_uint32; +#else +# if defined __STDC__ && __STDC__ +# define UINT_MAX_32_BITS 4294967295U +# else +# define UINT_MAX_32_BITS 0xFFFFFFFF +# endif + +/* If UINT_MAX isn't defined, assume it's a 32-bit type. + This should be valid for all systems GNU cares about because + that doesn't include 16-bit systems, and only modern systems + (that certainly have ) have 64+-bit integral types. */ + +# ifndef UINT_MAX +# define UINT_MAX UINT_MAX_32_BITS +# endif + +# if UINT_MAX == UINT_MAX_32_BITS + typedef unsigned int md5_uint32; +# else +# if USHRT_MAX == UINT_MAX_32_BITS + typedef unsigned short md5_uint32; +# else +# if ULONG_MAX == UINT_MAX_32_BITS + typedef unsigned long md5_uint32; +# else + /* The following line is intended to evoke an error. + Using #error is not portable enough. */ + "Cannot determine unsigned 32-bit data type." +# endif +# endif +# endif +#endif + +#undef __P +#if defined (__STDC__) && __STDC__ +# define __P(x) x +#else +# define __P(x) () +#endif + +/* Structure to save state of computation between the single steps. */ +struct md5_ctx +{ + md5_uint32 A; + md5_uint32 B; + md5_uint32 C; + md5_uint32 D; + + md5_uint32 total[2]; + md5_uint32 buflen; + char buffer[128]; +}; + +/* + * The following three functions are build up the low level used in + * the functions `md5_stream' and `md5_buffer'. + */ + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +extern void __md5_init_ctx __P ((struct md5_ctx *ctx)); +extern void md5_init_ctx __P ((struct md5_ctx *ctx)); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void __md5_process_block __P ((const void *buffer, size_t len, + struct md5_ctx *ctx)); +extern void md5_process_block __P ((const void *buffer, size_t len, + struct md5_ctx *ctx)); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void __md5_process_bytes __P ((const void *buffer, size_t len, + struct md5_ctx *ctx)); +extern void md5_process_bytes __P ((const void *buffer, size_t len, + struct md5_ctx *ctx)); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 16 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *__md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf)); +extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf)); + + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *__md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf)); +extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf)); + + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +extern int __md5_stream __P ((FILE *stream, void *resblock)); + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *__md5_buffer __P ((const char *buffer, size_t len, + void *resblock)); +extern void *md5_buffer __P ((const char *buffer, size_t len, + void *resblock)); + +#endif /* md5.h */ diff --git a/lib/md5.c b/lib/md5.c new file mode 100644 index 0000000..2068c46 --- /dev/null +++ b/lib/md5.c @@ -0,0 +1,447 @@ +/* md5.c - Functions to compute MD5 message digest of files or memory blocks + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Written by Ulrich Drepper , 1995. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#if STDC_HEADERS || defined _LIBC +# include +# include +#else +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +#include "md5-gnu.h" + +#ifdef _LIBC +# include +# if __BYTE_ORDER == __BIG_ENDIAN +# define WORDS_BIGENDIAN 1 +# endif +/* We need to keep the namespace clean so define the MD5 function + protected using leading __ and use weak aliases. */ +# define md5_init_ctx __md5_init_ctx +# define md5_process_block __md5_process_block +# define md5_process_bytes __md5_process_bytes +# define md5_finish_ctx __md5_finish_ctx +# define md5_read_ctx __md5_read_ctx +# define md5_stream __md5_stream +# define md5_buffer __md5_buffer +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (ctx) + struct md5_ctx *ctx; +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result + must be in little endian byte order. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_read_ctx (ctx, resbuf) + const struct md5_ctx *ctx; + void *resbuf; +{ + ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); + ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); + ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); + ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_finish_ctx (ctx, resbuf) + struct md5_ctx *ctx; + void *resbuf; +{ + /* Take yet unprocessed bytes into account. */ + md5_uint32 bytes = ctx->buflen; + size_t pad; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; + memcpy (&ctx->buffer[bytes], fillbuf, pad); + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3); + *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) | + (ctx->total[0] >> 29)); + + /* Process last bytes. */ + md5_process_block (ctx->buffer, bytes + pad + 8, ctx); + + return md5_read_ctx (ctx, resbuf); +} + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md5_stream (stream, resblock) + FILE *stream; + void *resblock; +{ + /* Important: BLOCKSIZE must be a multiple of 64. */ +#define BLOCKSIZE 4096 + struct md5_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + do + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + } + while (sum < BLOCKSIZE && n != 0); + if (n == 0 && ferror (stream)) + return 1; + + /* If end of file is reached, end the loop. */ + if (n == 0) + break; + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + + /* Add the last bytes if necessary. */ + if (sum > 0) + md5_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + md5_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (buffer, len, resblock) + const char *buffer; + size_t len; + void *resblock; +{ + struct md5_ctx ctx; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return md5_finish_ctx (&ctx, resblock); +} + + +void +md5_process_bytes (buffer, len, ctx) + const void *buffer; + size_t len; + struct md5_ctx *ctx; +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&ctx->buffer[left_over], buffer, add); + ctx->buflen += add; + + if (left_over + add > 64) + { + md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx); + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], + (left_over + add) & 63); + ctx->buflen = (left_over + add) & 63; + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len > 64) + { + md5_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + memcpy (ctx->buffer, buffer, len); + ctx->buflen = len; + } +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (buffer, len, ctx) + const void *buffer; + size_t len; + struct md5_ctx *ctx; +{ + md5_uint32 correct_words[16]; + const md5_uint32 *words = buffer; + size_t nwords = len / sizeof (md5_uint32); + const md5_uint32 *endp = words + nwords; + md5_uint32 A = ctx->A; + md5_uint32 B = ctx->B; + md5_uint32 C = ctx->C; + md5_uint32 D = ctx->D; + + /* First increment the byte count. RFC 1321 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + md5_uint32 *cwp = correct_words; + md5_uint32 A_save = A; + md5_uint32 B_save = B; + md5_uint32 C_save = C; + md5_uint32 D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} + + +#ifdef _LIBC +/* Define weak aliases. */ +# undef md5_init_ctx +weak_alias (__md5_init_ctx, md5_init_ctx) +# undef md5_process_block +weak_alias (__md5_process_block, md5_process_block) +# undef md5_process_bytes +weak_alias (__md5_process_bytes, md5_process_bytes) +# undef md5_finish_ctx +weak_alias (__md5_finish_ctx, md5_finish_ctx) +# undef md5_read_ctx +weak_alias (__md5_read_ctx, md5_read_ctx) +# undef md5_stream +weak_alias (__md5_stream, md5_stream) +# undef md5_buffer +weak_alias (__md5_buffer, md5_buffer) +#endif diff --git a/lib/memory.c b/lib/memory.c new file mode 100644 index 0000000..c9b9995 --- /dev/null +++ b/lib/memory.c @@ -0,0 +1,493 @@ +/* + * Memory management routine + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "memory.h" + +void alloc_inc (int); +void alloc_dec (int); + +struct message mstr [] = +{ + { MTYPE_THREAD, "thread" }, + { MTYPE_THREAD_MASTER, "thread_master" }, + { MTYPE_VECTOR, "vector" }, + { MTYPE_VECTOR_INDEX, "vector_index" }, + { MTYPE_IF, "interface" }, + { 0, NULL }, +}; + +/* Fatal memory allocation error occured. */ +static void +zerror (const char *fname, int type, size_t size) +{ + fprintf (stderr, "%s : can't allocate memory for `%s' size %d\n", + fname, lookup (mstr, type), (int) size); + exit (1); +} + +/* Memory allocation. */ +void * +zmalloc (int type, size_t size) +{ + void *memory; + + memory = malloc (size); + + if (memory == NULL) + zerror ("malloc", type, size); + + alloc_inc (type); + + return memory; +} + +/* Memory allocation with num * size with cleared. */ +void * +zcalloc (int type, size_t size) +{ + void *memory; + + memory = calloc (1, size); + + if (memory == NULL) + zerror ("calloc", type, size); + + alloc_inc (type); + + return memory; +} + +/* Memory reallocation. */ +void * +zrealloc (int type, void *ptr, size_t size) +{ + void *memory; + + memory = realloc (ptr, size); + if (memory == NULL) + zerror ("realloc", type, size); + return memory; +} + +/* Memory free. */ +void +zfree (int type, void *ptr) +{ + alloc_dec (type); + free (ptr); +} + +/* String duplication. */ +char * +zstrdup (int type, char *str) +{ + void *dup; + + dup = strdup (str); + if (dup == NULL) + zerror ("strdup", type, strlen (str)); + alloc_inc (type); + return dup; +} + +#ifdef MEMORY_LOG +struct +{ + char *name; + unsigned long alloc; + unsigned long t_malloc; + unsigned long c_malloc; + unsigned long t_calloc; + unsigned long c_calloc; + unsigned long t_realloc; + unsigned long t_free; + unsigned long c_strdup; +} mstat [MTYPE_MAX]; + +void +mtype_log (char *func, void *memory, const char *file, int line, int type) +{ + zlog_info ("%s: %s %p %s %d", func, lookup (mstr, type), memory, file, line); +} + +void * +mtype_zmalloc (const char *file, int line, int type, size_t size) +{ + void *memory; + + mstat[type].c_malloc++; + mstat[type].t_malloc++; + + memory = zmalloc (type, size); + mtype_log ("zmalloc", memory, file, line, type); + + return memory; +} + +void * +mtype_zcalloc (const char *file, int line, int type, size_t size) +{ + void *memory; + + mstat[type].c_calloc++; + mstat[type].t_calloc++; + + memory = zcalloc (type, size); + mtype_log ("xcalloc", memory, file, line, type); + + return memory; +} + +void * +mtype_zrealloc (const char *file, int line, int type, void *ptr, size_t size) +{ + void *memory; + + /* Realloc need before allocated pointer. */ + mstat[type].t_realloc++; + + memory = zrealloc (type, ptr, size); + + mtype_log ("xrealloc", memory, file, line, type); + + return memory; +} + +/* Important function. */ +void +mtype_zfree (const char *file, int line, int type, void *ptr) +{ + mstat[type].t_free++; + + mtype_log ("xfree", ptr, file, line, type); + + zfree (type, ptr); +} + +char * +mtype_zstrdup (const char *file, int line, int type, char *str) +{ + char *memory; + + mstat[type].c_strdup++; + + memory = zstrdup (type, str); + + mtype_log ("xstrdup", memory, file, line, type); + + return memory; +} +#else +struct +{ + char *name; + unsigned long alloc; +} mstat [MTYPE_MAX]; +#endif /* MTPYE_LOG */ + +/* Increment allocation counter. */ +void +alloc_inc (int type) +{ + mstat[type].alloc++; +} + +/* Decrement allocation counter. */ +void +alloc_dec (int type) +{ + mstat[type].alloc--; +} + +/* Looking up memory status from vty interface. */ +#include "vector.h" +#include "vty.h" +#include "command.h" + +/* For pretty printng of memory allocate information. */ +struct memory_list +{ + int index; + char *format; +}; + +struct memory_list memory_list_lib[] = +{ + { MTYPE_TMP, "Temporary memory" }, + { MTYPE_ROUTE_TABLE, "Route table " }, + { MTYPE_ROUTE_NODE, "Route node " }, + { MTYPE_RIB, "RIB " }, + { MTYPE_NEXTHOP, "Nexthop " }, + { MTYPE_LINK_LIST, "Link List " }, + { MTYPE_LINK_NODE, "Link Node " }, + { MTYPE_HASH, "Hash " }, + { MTYPE_HASH_BACKET, "Hash Bucket " }, + { MTYPE_ACCESS_LIST, "Access List " }, + { MTYPE_ACCESS_LIST_STR, "Access List Str " }, + { MTYPE_ACCESS_FILTER, "Access Filter " }, + { MTYPE_PREFIX_LIST, "Prefix List " }, + { MTYPE_PREFIX_LIST_STR, "Prefix List Str " }, + { MTYPE_PREFIX_LIST_ENTRY, "Prefix List Entry "}, + { MTYPE_ROUTE_MAP, "Route map " }, + { MTYPE_ROUTE_MAP_NAME, "Route map name " }, + { MTYPE_ROUTE_MAP_INDEX, "Route map index " }, + { MTYPE_ROUTE_MAP_RULE, "Route map rule " }, + { MTYPE_ROUTE_MAP_RULE_STR, "Route map rule str" }, + { MTYPE_DESC, "Command desc " }, + { MTYPE_BUFFER, "Buffer " }, + { MTYPE_BUFFER_DATA, "Buffer data " }, + { MTYPE_STREAM, "Stream " }, + { MTYPE_KEYCHAIN, "Key chain " }, + { MTYPE_KEY, "Key " }, + { MTYPE_VTY, "VTY " }, + { -1, NULL } +}; + +struct memory_list memory_list_bgp[] = +{ + { MTYPE_BGP_PEER, "BGP peer" }, + { MTYPE_ATTR, "BGP attribute" }, + { MTYPE_AS_PATH, "BGP aspath" }, + { MTYPE_AS_SEG, "BGP aspath seg" }, + { MTYPE_AS_STR, "BGP aspath str" }, + { 0, NULL }, + { MTYPE_BGP_TABLE, "BGP table" }, + { MTYPE_BGP_NODE, "BGP node" }, + { MTYPE_BGP_ADVERTISE_ATTR, "BGP adv attr" }, + { MTYPE_BGP_ADVERTISE, "BGP adv" }, + { MTYPE_BGP_ADJ_IN, "BGP adj in" }, + { MTYPE_BGP_ADJ_OUT, "BGP adj out" }, + { 0, NULL }, + { MTYPE_AS_LIST, "BGP AS list" }, + { MTYPE_AS_FILTER, "BGP AS filter" }, + { MTYPE_AS_FILTER_STR, "BGP AS filter str" }, + { 0, NULL }, + { MTYPE_COMMUNITY, "community" }, + { MTYPE_COMMUNITY_VAL, "community val" }, + { MTYPE_COMMUNITY_STR, "community str" }, + { 0, NULL }, + { MTYPE_ECOMMUNITY, "extcommunity" }, + { MTYPE_ECOMMUNITY_VAL, "extcommunity val" }, + { MTYPE_ECOMMUNITY_STR, "extcommunity str" }, + { 0, NULL }, + { MTYPE_COMMUNITY_LIST, "community-list" }, + { MTYPE_COMMUNITY_LIST_NAME, "community-list name" }, + { MTYPE_COMMUNITY_LIST_ENTRY, "community-list entry" }, + { MTYPE_COMMUNITY_LIST_CONFIG, "community-list config" }, + { 0, NULL }, + { MTYPE_CLUSTER, "Cluster list" }, + { MTYPE_CLUSTER_VAL, "Cluster list val" }, + { 0, NULL }, + { MTYPE_TRANSIT, "BGP transit attr" }, + { MTYPE_TRANSIT_VAL, "BGP transit val" }, + { 0, NULL }, + { MTYPE_BGP_DISTANCE, "BGP distance" }, + { MTYPE_BGP_NEXTHOP_CACHE, "BGP nexthop" }, + { MTYPE_BGP_CONFED_LIST, "BGP confed list" }, + { MTYPE_PEER_UPDATE_SOURCE, "peer update if" }, + { MTYPE_BGP_DAMP_INFO, "Dampening info" }, + { MTYPE_BGP_REGEXP, "BGP regexp" }, + { -1, NULL } +}; + +struct memory_list memory_list_rip[] = +{ + { MTYPE_RIP, "RIP structure " }, + { MTYPE_RIP_INFO, "RIP route info " }, + { MTYPE_RIP_INTERFACE, "RIP interface " }, + { MTYPE_RIP_PEER, "RIP peer " }, + { MTYPE_RIP_OFFSET_LIST, "RIP offset list " }, + { MTYPE_RIP_DISTANCE, "RIP distance " }, + { -1, NULL } +}; + +struct memory_list memory_list_ospf[] = +{ + { MTYPE_OSPF_TOP, "OSPF top " }, + { MTYPE_OSPF_AREA, "OSPF area " }, + { MTYPE_OSPF_AREA_RANGE, "OSPF area range " }, + { MTYPE_OSPF_NETWORK, "OSPF network " }, +#ifdef NBMA_ENABLE + { MTYPE_OSPF_NEIGHBOR_STATIC,"OSPF static nbr " }, +#endif /* NBMA_ENABLE */ + { MTYPE_OSPF_IF, "OSPF interface " }, + { MTYPE_OSPF_NEIGHBOR, "OSPF neighbor " }, + { MTYPE_OSPF_ROUTE, "OSPF route " }, + { MTYPE_OSPF_TMP, "OSPF tmp mem " }, + { MTYPE_OSPF_LSA, "OSPF LSA " }, + { MTYPE_OSPF_LSA_DATA, "OSPF LSA data " }, + { MTYPE_OSPF_LSDB, "OSPF LSDB " }, + { MTYPE_OSPF_PACKET, "OSPF packet " }, + { MTYPE_OSPF_FIFO, "OSPF FIFO queue " }, + { MTYPE_OSPF_VERTEX, "OSPF vertex " }, + { MTYPE_OSPF_NEXTHOP, "OSPF nexthop " }, + { MTYPE_OSPF_PATH, "OSPF path " }, + { MTYPE_OSPF_VL_DATA, "OSPF VL data " }, + { MTYPE_OSPF_CRYPT_KEY, "OSPF crypt key " }, + { MTYPE_OSPF_EXTERNAL_INFO, "OSPF ext. info " }, + { MTYPE_OSPF_DISTANCE, "OSPF distance " }, + { MTYPE_OSPF_IF_INFO, "OSPF if info " }, + { MTYPE_OSPF_IF_PARAMS, "OSPF if params " }, + { -1, NULL }, +}; + +struct memory_list memory_list_ospf6[] = +{ + { MTYPE_OSPF6_TOP, "OSPF6 top " }, + { MTYPE_OSPF6_AREA, "OSPF6 area " }, + { MTYPE_OSPF6_IF, "OSPF6 interface " }, + { MTYPE_OSPF6_NEIGHBOR, "OSPF6 neighbor " }, + { MTYPE_OSPF6_ROUTE, "OSPF6 route " }, + { MTYPE_OSPF6_PREFIX, "OSPF6 prefix " }, + { MTYPE_OSPF6_MESSAGE, "OSPF6 message " }, + { MTYPE_OSPF6_LSA, "OSPF6 LSA " }, + { MTYPE_OSPF6_LSA_SUMMARY, "OSPF6 LSA summary " }, + { MTYPE_OSPF6_LSDB, "OSPF6 LSA database" }, + { MTYPE_OSPF6_VERTEX, "OSPF6 vertex " }, + { MTYPE_OSPF6_SPFTREE, "OSPF6 SPF tree " }, + { MTYPE_OSPF6_NEXTHOP, "OSPF6 nexthop " }, + { MTYPE_OSPF6_EXTERNAL_INFO,"OSPF6 ext. info " }, + { MTYPE_OSPF6_OTHER, "OSPF6 other " }, + { -1, NULL }, +}; + +struct memory_list memory_list_separator[] = +{ + { 0, NULL}, + {-1, NULL} +}; + +void +show_memory_vty (struct vty *vty, struct memory_list *list) +{ + struct memory_list *m; + + for (m = list; m->index >= 0; m++) + if (m->index == 0) + vty_out (vty, "-----------------------------\r\n"); + else + vty_out (vty, "%-22s: %5ld\r\n", m->format, mstat[m->index].alloc); +} + +DEFUN (show_memory_all, + show_memory_all_cmd, + "show memory all", + "Show running system information\n" + "Memory statistics\n" + "All memory statistics\n") +{ + show_memory_vty (vty, memory_list_lib); + show_memory_vty (vty, memory_list_separator); + show_memory_vty (vty, memory_list_rip); + show_memory_vty (vty, memory_list_separator); + show_memory_vty (vty, memory_list_ospf); + show_memory_vty (vty, memory_list_separator); + show_memory_vty (vty, memory_list_ospf6); + show_memory_vty (vty, memory_list_separator); + show_memory_vty (vty, memory_list_bgp); + + return CMD_SUCCESS; +} + +ALIAS (show_memory_all, + show_memory_cmd, + "show memory", + "Show running system information\n" + "Memory statistics\n"); + +DEFUN (show_memory_lib, + show_memory_lib_cmd, + "show memory lib", + SHOW_STR + "Memory statistics\n" + "Library memory\n") +{ + show_memory_vty (vty, memory_list_lib); + return CMD_SUCCESS; +} + +DEFUN (show_memory_rip, + show_memory_rip_cmd, + "show memory rip", + SHOW_STR + "Memory statistics\n" + "RIP memory\n") +{ + show_memory_vty (vty, memory_list_rip); + return CMD_SUCCESS; +} + +DEFUN (show_memory_bgp, + show_memory_bgp_cmd, + "show memory bgp", + SHOW_STR + "Memory statistics\n" + "BGP memory\n") +{ + show_memory_vty (vty, memory_list_bgp); + return CMD_SUCCESS; +} + +DEFUN (show_memory_ospf, + show_memory_ospf_cmd, + "show memory ospf", + SHOW_STR + "Memory statistics\n" + "OSPF memory\n") +{ + show_memory_vty (vty, memory_list_ospf); + return CMD_SUCCESS; +} + +DEFUN (show_memory_ospf6, + show_memory_ospf6_cmd, + "show memory ospf6", + SHOW_STR + "Memory statistics\n" + "OSPF6 memory\n") +{ + show_memory_vty (vty, memory_list_ospf6); + return CMD_SUCCESS; +} + +void +memory_init () +{ + install_element (VIEW_NODE, &show_memory_cmd); + install_element (VIEW_NODE, &show_memory_all_cmd); + install_element (VIEW_NODE, &show_memory_lib_cmd); + install_element (VIEW_NODE, &show_memory_rip_cmd); + install_element (VIEW_NODE, &show_memory_bgp_cmd); + install_element (VIEW_NODE, &show_memory_ospf_cmd); + install_element (VIEW_NODE, &show_memory_ospf6_cmd); + + install_element (ENABLE_NODE, &show_memory_cmd); + install_element (ENABLE_NODE, &show_memory_all_cmd); + install_element (ENABLE_NODE, &show_memory_lib_cmd); + install_element (ENABLE_NODE, &show_memory_rip_cmd); + install_element (ENABLE_NODE, &show_memory_bgp_cmd); + install_element (ENABLE_NODE, &show_memory_ospf_cmd); + install_element (ENABLE_NODE, &show_memory_ospf6_cmd); +} diff --git a/lib/memory.h b/lib/memory.h new file mode 100644 index 0000000..d490c45 --- /dev/null +++ b/lib/memory.h @@ -0,0 +1,246 @@ +/* Memory management routine + Copyright (C) 1998 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _ZEBRA_MEMORY_H +#define _ZEBRA_MEMORY_H + +/* #define MEMORY_LOG */ + +/* For tagging memory, below is the type of the memory. */ +enum +{ + MTYPE_TMP = 1, + MTYPE_STRVEC, + MTYPE_VECTOR, + MTYPE_VECTOR_INDEX, + MTYPE_LINK_LIST, + MTYPE_LINK_NODE, + MTYPE_THREAD, + MTYPE_THREAD_MASTER, + MTYPE_VTY, + MTYPE_VTY_HIST, + MTYPE_VTY_OUT_BUF, + MTYPE_IF, + MTYPE_IF_IRDP, + MTYPE_CONNECTED, + MTYPE_AS_SEG, + MTYPE_AS_STR, + MTYPE_AS_PATH, + MTYPE_CLUSTER, + MTYPE_CLUSTER_VAL, + MTYPE_ATTR, + MTYPE_TRANSIT, + MTYPE_TRANSIT_VAL, + MTYPE_BUFFER, + MTYPE_BUFFER_DATA, + MTYPE_STREAM, + MTYPE_STREAM_DATA, + MTYPE_STREAM_FIFO, + MTYPE_PREFIX, + MTYPE_PREFIX_IPV4, + MTYPE_PREFIX_IPV6, + MTYPE_HASH, + MTYPE_HASH_INDEX, + MTYPE_HASH_BACKET, + MTYPE_RIPNG_ROUTE, + MTYPE_RIPNG_AGGREGATE, + MTYPE_ROUTE_TABLE, + MTYPE_ROUTE_NODE, + MTYPE_ACCESS_LIST, + MTYPE_ACCESS_LIST_STR, + MTYPE_ACCESS_FILTER, + MTYPE_PREFIX_LIST, + MTYPE_PREFIX_LIST_STR, + MTYPE_PREFIX_LIST_ENTRY, + MTYPE_ROUTE_MAP, + MTYPE_ROUTE_MAP_NAME, + MTYPE_ROUTE_MAP_INDEX, + MTYPE_ROUTE_MAP_RULE, + MTYPE_ROUTE_MAP_RULE_STR, + MTYPE_ROUTE_MAP_COMPILED, + + MTYPE_RIB, + MTYPE_DISTRIBUTE, + MTYPE_ZLOG, + MTYPE_ZCLIENT, + MTYPE_NEXTHOP, + MTYPE_RTADV_PREFIX, + MTYPE_IF_RMAP, + MTYPE_SOCKUNION, + MTYPE_STATIC_IPV4, + MTYPE_STATIC_IPV6, + + MTYPE_DESC, + MTYPE_OSPF_TOP, + MTYPE_OSPF_AREA, + MTYPE_OSPF_AREA_RANGE, + MTYPE_OSPF_NETWORK, + MTYPE_OSPF_NEIGHBOR_STATIC, + MTYPE_OSPF_IF, + MTYPE_OSPF_NEIGHBOR, + MTYPE_OSPF_ROUTE, + MTYPE_OSPF_TMP, + MTYPE_OSPF_LSA, + MTYPE_OSPF_LSA_DATA, + MTYPE_OSPF_LSDB, + MTYPE_OSPF_PACKET, + MTYPE_OSPF_FIFO, + MTYPE_OSPF_VERTEX, + MTYPE_OSPF_NEXTHOP, + MTYPE_OSPF_PATH, + MTYPE_OSPF_VL_DATA, + MTYPE_OSPF_CRYPT_KEY, + MTYPE_OSPF_EXTERNAL_INFO, + MTYPE_OSPF_MESSAGE, + MTYPE_OSPF_DISTANCE, + MTYPE_OSPF_IF_INFO, + MTYPE_OSPF_IF_PARAMS, + + MTYPE_OSPF6_TOP, + MTYPE_OSPF6_AREA, + MTYPE_OSPF6_IF, + MTYPE_OSPF6_NEIGHBOR, + MTYPE_OSPF6_ROUTE, + MTYPE_OSPF6_PREFIX, + MTYPE_OSPF6_MESSAGE, + MTYPE_OSPF6_LSA, + MTYPE_OSPF6_LSA_SUMMARY, + MTYPE_OSPF6_LSDB, + MTYPE_OSPF6_VERTEX, + MTYPE_OSPF6_SPFTREE, + MTYPE_OSPF6_NEXTHOP, + MTYPE_OSPF6_EXTERNAL_INFO, + MTYPE_OSPF6_OTHER, + + MTYPE_BGP, + MTYPE_BGP_PEER, + MTYPE_PEER_GROUP, + MTYPE_PEER_DESC, + MTYPE_PEER_UPDATE_SOURCE, + MTYPE_BGP_STATIC, + MTYPE_BGP_AGGREGATE, + MTYPE_BGP_CONFED_LIST, + MTYPE_BGP_NEXTHOP_CACHE, + MTYPE_BGP_DAMP_INFO, + MTYPE_BGP_DAMP_ARRAY, + MTYPE_BGP_ANNOUNCE, + MTYPE_BGP_ATTR_QUEUE, + MTYPE_BGP_ROUTE_QUEUE, + MTYPE_BGP_DISTANCE, + MTYPE_BGP_ROUTE, + MTYPE_BGP_TABLE, + MTYPE_BGP_NODE, + MTYPE_BGP_ADVERTISE_ATTR, + MTYPE_BGP_ADVERTISE, + MTYPE_BGP_ADJ_IN, + MTYPE_BGP_ADJ_OUT, + MTYPE_BGP_REGEXP, + MTYPE_AS_FILTER, + MTYPE_AS_FILTER_STR, + MTYPE_AS_LIST, + + MTYPE_COMMUNITY, + MTYPE_COMMUNITY_VAL, + MTYPE_COMMUNITY_STR, + + MTYPE_ECOMMUNITY, + MTYPE_ECOMMUNITY_VAL, + MTYPE_ECOMMUNITY_STR, + + /* community-list and extcommunity-list. */ + MTYPE_COMMUNITY_LIST_HANDLER, + MTYPE_COMMUNITY_LIST, + MTYPE_COMMUNITY_LIST_NAME, + MTYPE_COMMUNITY_LIST_ENTRY, + MTYPE_COMMUNITY_LIST_CONFIG, + + MTYPE_RIP, + MTYPE_RIP_INTERFACE, + MTYPE_RIP_DISTANCE, + MTYPE_RIP_OFFSET_LIST, + MTYPE_RIP_INFO, + MTYPE_RIP_PEER, + MTYPE_KEYCHAIN, + MTYPE_KEY, + + MTYPE_VTYSH_CONFIG, + MTYPE_VTYSH_CONFIG_LINE, + + MTYPE_VRF, + MTYPE_VRF_NAME, + + MTYPE_MAX +}; + +#ifdef MEMORY_LOG +#define XMALLOC(mtype, size) \ + mtype_zmalloc (__FILE__, __LINE__, (mtype), (size)) +#define XCALLOC(mtype, size) \ + mtype_zcalloc (__FILE__, __LINE__, (mtype), (size)) +#define XREALLOC(mtype, ptr, size) \ + mtype_zrealloc (__FILE__, __LINE__, (mtype), (ptr), (size)) +#define XFREE(mtype, ptr) \ + mtype_zfree (__FILE__, __LINE__, (mtype), (ptr)) +#define XSTRDUP(mtype, str) \ + mtype_zstrdup (__FILE__, __LINE__, (mtype), (str)) +#else +#define XMALLOC(mtype, size) zmalloc ((mtype), (size)) +#define XCALLOC(mtype, size) zcalloc ((mtype), (size)) +#define XREALLOC(mtype, ptr, size) zrealloc ((mtype), (ptr), (size)) +#define XFREE(mtype, ptr) zfree ((mtype), (ptr)) +#define XSTRDUP(mtype, str) zstrdup ((mtype), (str)) +#endif /* MEMORY_LOG */ + +/* Prototypes of memory function. */ +void *zmalloc (int type, size_t size); +void *zcalloc (int type, size_t size); +void *zrealloc (int type, void *ptr, size_t size); +void zfree (int type, void *ptr); +char *zstrdup (int type, char *str); + +void *mtype_zmalloc (const char *file, + int line, + int type, + size_t size); + +void *mtype_zcalloc (const char *file, + int line, + int type, + size_t num, + size_t size); + +void *mtype_zrealloc (const char *file, + int line, + int type, + void *ptr, + size_t size); + +void mtype_zfree (const char *file, + int line, + int type, + void *ptr); + +char *mtype_zstrdup (const char *file, + int line, + int type, + char *str); +void memory_init (); + +#endif /* _ZEBRA_MEMORY_H */ diff --git a/lib/network.c b/lib/network.c new file mode 100644 index 0000000..b68761b --- /dev/null +++ b/lib/network.c @@ -0,0 +1,71 @@ +/* + * Network library. + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +/* Read nbytes from fd and store into ptr. */ +int +readn (int fd, char *ptr, int nbytes) +{ + int nleft; + int nread; + + nleft = nbytes; + + while (nleft > 0) + { + nread = read (fd, ptr, nleft); + + if (nread < 0) + return (nread); + else + if (nread == 0) + break; + + nleft -= nread; + ptr += nread; + } + + return nbytes - nleft; +} + +/* Write nbytes from ptr to fd. */ +int +writen(int fd, char *ptr, int nbytes) +{ + int nleft; + int nwritten; + + nleft = nbytes; + + while (nleft > 0) + { + nwritten = write(fd, ptr, nleft); + + if (nwritten <= 0) + return (nwritten); + + nleft -= nwritten; + ptr += nwritten; + } + return nbytes - nleft; +} diff --git a/lib/network.h b/lib/network.h new file mode 100644 index 0000000..a021295 --- /dev/null +++ b/lib/network.h @@ -0,0 +1,29 @@ +/* + * Network library header. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_NETWORK_H +#define _ZEBRA_NETWORK_H + +int readn (int, char *, int); +int writen (int, char *, int); + +#endif /* _ZEBRA_NETWORK_H */ diff --git a/lib/pid_output.c b/lib/pid_output.c new file mode 100644 index 0000000..4146244 --- /dev/null +++ b/lib/pid_output.c @@ -0,0 +1,77 @@ +/* + * Process id output. + * Copyright (C) 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +pid_t +pid_output (char *path) +{ + FILE *fp; + pid_t pid; + + pid = getpid(); + + fp = fopen (path, "w"); + if (fp != NULL) + { + fprintf (fp, "%d\n", (int) pid); + fclose (fp); + return -1; + } + return pid; +} + +pid_t +pid_output_lock (char *path) +{ + int tmp; + int fd; + pid_t pid; + char buf[16], *p; + + pid = getpid (); + + fd = open (path, O_RDWR | O_CREAT | O_EXCL, 0644); + if (fd < 0) + { + fd = open (path, O_RDONLY); + if (fd < 0) + fprintf (stderr, "Can't creat pid lock file, exit\n"); + else + { + read (fd, buf, sizeof (buf)); + if ((p = index (buf, '\n')) != NULL) + *p = 0; + fprintf (stderr, "Another process(%s) running, exit\n", buf); + } + exit (-1); + } + else + { + sprintf (buf, "%d\n", (int) pid); + tmp = write (fd, buf, strlen (buf)); + close (fd); + } + + return pid; +} + diff --git a/lib/plist.c b/lib/plist.c new file mode 100644 index 0000000..41f9901 --- /dev/null +++ b/lib/plist.c @@ -0,0 +1,2881 @@ +/* Prefix list functions. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "command.h" +#include "memory.h" +#include "plist.h" +#include "sockunion.h" +#include "buffer.h" + +/* Each prefix-list's entry. */ +struct prefix_list_entry +{ + int seq; + + int le; + int ge; + + enum prefix_list_type type; + + int any; + struct prefix prefix; + + unsigned long refcnt; + unsigned long hitcnt; + + struct prefix_list_entry *next; + struct prefix_list_entry *prev; +}; + +/* List of struct prefix_list. */ +struct prefix_list_list +{ + struct prefix_list *head; + struct prefix_list *tail; +}; + +/* Master structure of prefix_list. */ +struct prefix_master +{ + /* List of prefix_list which name is number. */ + struct prefix_list_list num; + + /* List of prefix_list which name is string. */ + struct prefix_list_list str; + + /* Whether sequential number is used. */ + int seqnum; + + /* The latest update. */ + struct prefix_list *recent; + + /* Hook function which is executed when new prefix_list is added. */ + void (*add_hook) (); + + /* Hook function which is executed when prefix_list is deleted. */ + void (*delete_hook) (); +}; + +/* Static structure of IPv4 prefix_list's master. */ +static struct prefix_master prefix_master_ipv4 = +{ + {NULL, NULL}, + {NULL, NULL}, + 1, + NULL, + NULL, +}; + +#ifdef HAVE_IPV6 +/* Static structure of IPv6 prefix-list's master. */ +static struct prefix_master prefix_master_ipv6 = +{ + {NULL, NULL}, + {NULL, NULL}, + 1, + NULL, + NULL, +}; +#endif /* HAVE_IPV6*/ + +/* Static structure of BGP ORF prefix_list's master. */ +static struct prefix_master prefix_master_orf = +{ + {NULL, NULL}, + {NULL, NULL}, + 1, + NULL, + NULL, +}; + +struct prefix_master * +prefix_master_get (afi_t afi) +{ + if (afi == AFI_IP) + return &prefix_master_ipv4; +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + return &prefix_master_ipv6; +#endif /* HAVE_IPV6 */ + else if (afi == AFI_ORF_PREFIX) + return &prefix_master_orf; + return NULL; +} + +/* Lookup prefix_list from list of prefix_list by name. */ +struct prefix_list * +prefix_list_lookup (afi_t afi, char *name) +{ + struct prefix_list *plist; + struct prefix_master *master; + + if (name == NULL) + return NULL; + + master = prefix_master_get (afi); + if (master == NULL) + return NULL; + + for (plist = master->num.head; plist; plist = plist->next) + if (strcmp (plist->name, name) == 0) + return plist; + + for (plist = master->str.head; plist; plist = plist->next) + if (strcmp (plist->name, name) == 0) + return plist; + + return NULL; +} + +struct prefix_list * +prefix_list_new () +{ + struct prefix_list *new; + + new = XCALLOC (MTYPE_PREFIX_LIST, sizeof (struct prefix_list)); + return new; +} + +void +prefix_list_free (struct prefix_list *plist) +{ + XFREE (MTYPE_PREFIX_LIST, plist); +} + +struct prefix_list_entry * +prefix_list_entry_new () +{ + struct prefix_list_entry *new; + + new = XCALLOC (MTYPE_PREFIX_LIST_ENTRY, sizeof (struct prefix_list_entry)); + return new; +} + +void +prefix_list_entry_free (struct prefix_list_entry *pentry) +{ + XFREE (MTYPE_PREFIX_LIST_ENTRY, pentry); +} + +/* Insert new prefix list to list of prefix_list. Each prefix_list + is sorted by the name. */ +struct prefix_list * +prefix_list_insert (afi_t afi, char *name) +{ + int i; + long number; + struct prefix_list *plist; + struct prefix_list *point; + struct prefix_list_list *list; + struct prefix_master *master; + + master = prefix_master_get (afi); + if (master == NULL) + return NULL; + + /* Allocate new prefix_list and copy given name. */ + plist = prefix_list_new (); + plist->name = XSTRDUP (MTYPE_PREFIX_LIST_STR, name); + plist->master = master; + + /* If name is made by all digit character. We treat it as + number. */ + for (number = 0, i = 0; i < strlen (name); i++) + { + if (isdigit ((int) name[i])) + number = (number * 10) + (name[i] - '0'); + else + break; + } + + /* In case of name is all digit character */ + if (i == strlen (name)) + { + plist->type = PREFIX_TYPE_NUMBER; + + /* Set prefix_list to number list. */ + list = &master->num; + + for (point = list->head; point; point = point->next) + if (atol (point->name) >= number) + break; + } + else + { + plist->type = PREFIX_TYPE_STRING; + + /* Set prefix_list to string list. */ + list = &master->str; + + /* Set point to insertion point. */ + for (point = list->head; point; point = point->next) + if (strcmp (point->name, name) >= 0) + break; + } + + /* In case of this is the first element of master. */ + if (list->head == NULL) + { + list->head = list->tail = plist; + return plist; + } + + /* In case of insertion is made at the tail of access_list. */ + if (point == NULL) + { + plist->prev = list->tail; + list->tail->next = plist; + list->tail = plist; + return plist; + } + + /* In case of insertion is made at the head of access_list. */ + if (point == list->head) + { + plist->next = list->head; + list->head->prev = plist; + list->head = plist; + return plist; + } + + /* Insertion is made at middle of the access_list. */ + plist->next = point; + plist->prev = point->prev; + + if (point->prev) + point->prev->next = plist; + point->prev = plist; + + return plist; +} + +struct prefix_list * +prefix_list_get (afi_t afi, char *name) +{ + struct prefix_list *plist; + + plist = prefix_list_lookup (afi, name); + + if (plist == NULL) + plist = prefix_list_insert (afi, name); + return plist; +} + +/* Delete prefix-list from prefix_list_master and free it. */ +void +prefix_list_delete (struct prefix_list *plist) +{ + struct prefix_list_list *list; + struct prefix_master *master; + struct prefix_list_entry *pentry; + struct prefix_list_entry *next; + + /* If prefix-list contain prefix_list_entry free all of it. */ + for (pentry = plist->head; pentry; pentry = next) + { + next = pentry->next; + prefix_list_entry_free (pentry); + plist->count--; + } + + master = plist->master; + + if (plist->type == PREFIX_TYPE_NUMBER) + list = &master->num; + else + list = &master->str; + + if (plist->next) + plist->next->prev = plist->prev; + else + list->tail = plist->prev; + + if (plist->prev) + plist->prev->next = plist->next; + else + list->head = plist->next; + + if (plist->desc) + XFREE (MTYPE_TMP, plist->desc); + + /* Make sure master's recent changed prefix-list information is + cleared. */ + master->recent = NULL; + + if (plist->name) + XFREE (MTYPE_PREFIX_LIST_STR, plist->name); + + prefix_list_free (plist); + + if (master->delete_hook) + (*master->delete_hook) (); +} + +struct prefix_list_entry * +prefix_list_entry_make (struct prefix *prefix, enum prefix_list_type type, + int seq, int le, int ge, int any) +{ + struct prefix_list_entry *pentry; + + pentry = prefix_list_entry_new (); + + if (any) + pentry->any = 1; + + prefix_copy (&pentry->prefix, prefix); + pentry->type = type; + pentry->seq = seq; + pentry->le = le; + pentry->ge = ge; + + return pentry; +} + +/* Add hook function. */ +void +prefix_list_add_hook (void (*func) (struct prefix_list *plist)) +{ + prefix_master_ipv4.add_hook = func; +#ifdef HAVE_IPV6 + prefix_master_ipv6.add_hook = func; +#endif /* HAVE_IPV6 */ +} + +/* Delete hook function. */ +void +prefix_list_delete_hook (void (*func) (struct prefix_list *plist)) +{ + prefix_master_ipv4.delete_hook = func; +#ifdef HAVE_IPV6 + prefix_master_ipv6.delete_hook = func; +#endif /* HAVE_IPVt6 */ +} + +/* Calculate new sequential number. */ +int +prefix_new_seq_get (struct prefix_list *plist) +{ + int maxseq; + int newseq; + struct prefix_list_entry *pentry; + + maxseq = newseq = 0; + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + if (maxseq < pentry->seq) + maxseq = pentry->seq; + } + + newseq = ((maxseq / 5) * 5) + 5; + + return newseq; +} + +/* Return prefix list entry which has same seq number. */ +struct prefix_list_entry * +prefix_seq_check (struct prefix_list *plist, int seq) +{ + struct prefix_list_entry *pentry; + + for (pentry = plist->head; pentry; pentry = pentry->next) + if (pentry->seq == seq) + return pentry; + return NULL; +} + +struct prefix_list_entry * +prefix_list_entry_lookup (struct prefix_list *plist, struct prefix *prefix, + enum prefix_list_type type, int seq, int le, int ge) +{ + struct prefix_list_entry *pentry; + + for (pentry = plist->head; pentry; pentry = pentry->next) + if (prefix_same (&pentry->prefix, prefix) && pentry->type == type) + { + if (seq >= 0 && pentry->seq != seq) + continue; + + if (pentry->le != le) + continue; + if (pentry->ge != ge) + continue; + + return pentry; + } + + return NULL; +} + +void +prefix_list_entry_delete (struct prefix_list *plist, + struct prefix_list_entry *pentry, + int update_list) +{ + if (plist == NULL || pentry == NULL) + return; + if (pentry->prev) + pentry->prev->next = pentry->next; + else + plist->head = pentry->next; + if (pentry->next) + pentry->next->prev = pentry->prev; + else + plist->tail = pentry->prev; + + prefix_list_entry_free (pentry); + + plist->count--; + + if (update_list) + { + if (plist->master->delete_hook) + (*plist->master->delete_hook) (plist); + + if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL) + prefix_list_delete (plist); + else + plist->master->recent = plist; + } +} + +void +prefix_list_entry_add (struct prefix_list *plist, + struct prefix_list_entry *pentry) +{ + struct prefix_list_entry *replace; + struct prefix_list_entry *point; + + /* Automatic asignment of seq no. */ + if (pentry->seq == -1) + pentry->seq = prefix_new_seq_get (plist); + + /* Is there any same seq prefix list entry? */ + replace = prefix_seq_check (plist, pentry->seq); + if (replace) + prefix_list_entry_delete (plist, replace, 0); + + /* Check insert point. */ + for (point = plist->head; point; point = point->next) + if (point->seq >= pentry->seq) + break; + + /* In case of this is the first element of the list. */ + pentry->next = point; + + if (point) + { + if (point->prev) + point->prev->next = pentry; + else + plist->head = pentry; + + pentry->prev = point->prev; + point->prev = pentry; + } + else + { + if (plist->tail) + plist->tail->next = pentry; + else + plist->head = pentry; + + pentry->prev = plist->tail; + plist->tail = pentry; + } + + /* Increment count. */ + plist->count++; + + /* Run hook function. */ + if (plist->master->add_hook) + (*plist->master->add_hook) (plist); + + plist->master->recent = plist; +} + +/* Return string of prefix_list_type. */ +static char * +prefix_list_type_str (struct prefix_list_entry *pentry) +{ + switch (pentry->type) + { + case PREFIX_PERMIT: + return "permit"; + break; + case PREFIX_DENY: + return "deny"; + break; + default: + return ""; + break; + } +} + +int +prefix_list_entry_match (struct prefix_list_entry *pentry, struct prefix *p) +{ + int ret; + + ret = prefix_match (&pentry->prefix, p); + if (! ret) + return 0; + + /* In case of le nor ge is specified, exact match is performed. */ + if (! pentry->le && ! pentry->ge) + { + if (pentry->prefix.prefixlen != p->prefixlen) + return 0; + } + else + { + if (pentry->le) + if (p->prefixlen > pentry->le) + return 0; + + if (pentry->ge) + if (p->prefixlen < pentry->ge) + return 0; + } + return 1; +} + +enum prefix_list_type +prefix_list_apply (struct prefix_list *plist, void *object) +{ + struct prefix_list_entry *pentry; + struct prefix *p; + + p = (struct prefix *) object; + + if (plist == NULL) + return PREFIX_DENY; + + if (plist->count == 0) + return PREFIX_PERMIT; + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + pentry->refcnt++; + if (prefix_list_entry_match (pentry, p)) + { + pentry->hitcnt++; + return pentry->type; + } + } + + return PREFIX_DENY; +} + +void +prefix_list_print (struct prefix_list *plist) +{ + struct prefix_list_entry *pentry; + + if (plist == NULL) + return; + + printf ("ip prefix-list %s: %d entries\n", plist->name, plist->count); + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + if (pentry->any) + printf ("any %s\n", prefix_list_type_str (pentry)); + else + { + struct prefix *p; + char buf[BUFSIZ]; + + p = &pentry->prefix; + + printf (" seq %d %s %s/%d", + pentry->seq, + prefix_list_type_str (pentry), + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + if (pentry->ge) + printf (" ge %d", pentry->ge); + if (pentry->le) + printf (" le %d", pentry->le); + printf ("\n"); + } + } +} + +/* Retrun 1 when plist already include pentry policy. */ +struct prefix_list_entry * +prefix_entry_dup_check (struct prefix_list *plist, + struct prefix_list_entry *new) +{ + struct prefix_list_entry *pentry; + int seq = 0; + + if (new->seq == -1) + seq = prefix_new_seq_get (plist); + else + seq = new->seq; + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + if (prefix_same (&pentry->prefix, &new->prefix) + && pentry->type == new->type + && pentry->le == new->le + && pentry->ge == new->ge + && pentry->seq != seq) + return pentry; + } + return NULL; +} + +int +vty_invalid_prefix_range (struct vty *vty, char *prefix) +{ + vty_out (vty, "%% Invalid prefix range for %s, make sure: len < ge-value <= le-value%s", + prefix, VTY_NEWLINE); + return CMD_WARNING; +} + +int +vty_prefix_list_install (struct vty *vty, afi_t afi, + char *name, char *seq, char *typestr, + char *prefix, char *ge, char *le) +{ + int ret; + enum prefix_list_type type; + struct prefix_list *plist; + struct prefix_list_entry *pentry; + struct prefix_list_entry *dup; + struct prefix p; + int any = 0; + int seqnum = -1; + int lenum = 0; + int genum = 0; + + /* Sequential number. */ + if (seq) + seqnum = atoi (seq); + + /* ge and le number */ + if (ge) + genum = atoi (ge); + if (le) + lenum = atoi (le); + + /* Check filter type. */ + if (strncmp ("permit", typestr, 1) == 0) + type = PREFIX_PERMIT; + else if (strncmp ("deny", typestr, 1) == 0) + type = PREFIX_DENY; + else + { + vty_out (vty, "%% prefix type must be permit or deny%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* "any" is special token for matching any IPv4 addresses. */ + if (afi == AFI_IP) + { + if (strncmp ("any", prefix, strlen (prefix)) == 0) + { + ret = str2prefix_ipv4 ("0.0.0.0/0", (struct prefix_ipv4 *) &p); + genum = 0; + lenum = IPV4_MAX_BITLEN; + any = 1; + } + else + ret = str2prefix_ipv4 (prefix, (struct prefix_ipv4 *) &p); + + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv4 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + } +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + { + if (strncmp ("any", prefix, strlen (prefix)) == 0) + { + ret = str2prefix_ipv6 ("::/0", (struct prefix_ipv6 *) &p); + genum = 0; + lenum = IPV6_MAX_BITLEN; + any = 1; + } + else + ret = str2prefix_ipv6 (prefix, (struct prefix_ipv6 *) &p); + + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv6 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + } +#endif /* HAVE_IPV6 */ + + /* ge and le check. */ + if (genum && genum <= p.prefixlen) + return vty_invalid_prefix_range (vty, prefix); + + if (lenum && lenum <= p.prefixlen) + return vty_invalid_prefix_range (vty, prefix); + + if (lenum && genum > lenum) + return vty_invalid_prefix_range (vty, prefix); + + if (genum && lenum == (afi == AFI_IP ? 32 : 128)) + lenum = 0; + + /* Get prefix_list with name. */ + plist = prefix_list_get (afi, name); + + /* Make prefix entry. */ + pentry = prefix_list_entry_make (&p, type, seqnum, lenum, genum, any); + + /* Check same policy. */ + dup = prefix_entry_dup_check (plist, pentry); + + if (dup) + { + prefix_list_entry_free (pentry); + vty_out (vty, "%% Insertion failed - prefix-list entry exists:%s", + VTY_NEWLINE); + vty_out (vty, " seq %d %s %s", dup->seq, typestr, prefix); + if (! any && genum) + vty_out (vty, " ge %d", genum); + if (! any && lenum) + vty_out (vty, " le %d", lenum); + vty_out (vty, "%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Install new filter to the access_list. */ + prefix_list_entry_add (plist, pentry); + + return CMD_SUCCESS; +} + +int +vty_prefix_list_uninstall (struct vty *vty, afi_t afi, + char *name, char *seq, char *typestr, + char *prefix, char *ge, char *le) +{ + int ret; + enum prefix_list_type type; + struct prefix_list *plist; + struct prefix_list_entry *pentry; + struct prefix p; + int seqnum = -1; + int lenum = 0; + int genum = 0; + + /* Check prefix list name. */ + plist = prefix_list_lookup (afi, name); + if (! plist) + { + vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Only prefix-list name specified, delete the entire prefix-list. */ + if (seq == NULL && typestr == NULL && prefix == NULL && + ge == NULL && le == NULL) + { + prefix_list_delete (plist); + return CMD_SUCCESS; + } + + /* Check sequence number. */ + if (seq) + seqnum = atoi (seq); + + /* ge and le number */ + if (ge) + genum = atoi (ge); + if (le) + lenum = atoi (le); + + /* Check of filter type. */ + if (strncmp ("permit", typestr, 1) == 0) + type = PREFIX_PERMIT; + else if (strncmp ("deny", typestr, 1) == 0) + type = PREFIX_DENY; + else + { + vty_out (vty, "%% prefix type must be permit or deny%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* "any" is special token for matching any IPv4 addresses. */ + if (afi == AFI_IP) + { + if (strncmp ("any", prefix, strlen (prefix)) == 0) + { + ret = str2prefix_ipv4 ("0.0.0.0/0", (struct prefix_ipv4 *) &p); + genum = 0; + lenum = IPV4_MAX_BITLEN; + } + else + ret = str2prefix_ipv4 (prefix, (struct prefix_ipv4 *) &p); + + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv4 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + } +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + { + if (strncmp ("any", prefix, strlen (prefix)) == 0) + { + ret = str2prefix_ipv6 ("::/0", (struct prefix_ipv6 *) &p); + genum = 0; + lenum = IPV6_MAX_BITLEN; + } + else + ret = str2prefix_ipv6 (prefix, (struct prefix_ipv6 *) &p); + + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv6 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + } +#endif /* HAVE_IPV6 */ + + /* Lookup prefix entry. */ + pentry = prefix_list_entry_lookup(plist, &p, type, seqnum, lenum, genum); + + if (pentry == NULL) + { + vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Install new filter to the access_list. */ + prefix_list_entry_delete (plist, pentry, 1); + + return CMD_SUCCESS; +} + +int +vty_prefix_list_desc_unset (struct vty *vty, afi_t afi, char *name) +{ + struct prefix_list *plist; + + plist = prefix_list_lookup (afi, name); + if (! plist) + { + vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (plist->desc) + { + XFREE (MTYPE_TMP, plist->desc); + plist->desc = NULL; + } + + if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL) + prefix_list_delete (plist); + + return CMD_SUCCESS; +} + +enum display_type +{ + normal_display, + summary_display, + detail_display, + sequential_display, + longer_display, + first_match_display +}; + +void +vty_show_prefix_entry (struct vty *vty, afi_t afi, struct prefix_list *plist, + struct prefix_master *master, enum display_type dtype, + int seqnum) +{ + struct prefix_list_entry *pentry; + + if (dtype == normal_display) + { + vty_out (vty, "ip%s prefix-list %s: %d entries%s", + afi == AFI_IP ? "" : "v6", + plist->name, plist->count, VTY_NEWLINE); + if (plist->desc) + vty_out (vty, " Description: %s%s", plist->desc, VTY_NEWLINE); + } + else if (dtype == summary_display || dtype == detail_display) + { + vty_out (vty, "ip%s prefix-list %s:%s", + afi == AFI_IP ? "" : "v6", plist->name, VTY_NEWLINE); + + if (plist->desc) + vty_out (vty, " Description: %s%s", plist->desc, VTY_NEWLINE); + + vty_out (vty, " count: %d, range entries: %d, sequences: %d - %d%s", + plist->count, plist->rangecount, + plist->head ? plist->head->seq : 0, + plist->tail ? plist->tail->seq : 0, + VTY_NEWLINE); + } + + if (dtype != summary_display) + { + for (pentry = plist->head; pentry; pentry = pentry->next) + { + if (dtype == sequential_display && pentry->seq != seqnum) + continue; + + vty_out (vty, " "); + + if (master->seqnum) + vty_out (vty, "seq %d ", pentry->seq); + + vty_out (vty, "%s ", prefix_list_type_str (pentry)); + + if (pentry->any) + vty_out (vty, "any"); + else + { + struct prefix *p = &pentry->prefix; + char buf[BUFSIZ]; + + vty_out (vty, "%s/%d", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + if (pentry->ge) + vty_out (vty, " ge %d", pentry->ge); + if (pentry->le) + vty_out (vty, " le %d", pentry->le); + } + + if (dtype == detail_display || dtype == sequential_display) + vty_out (vty, " (hit count: %ld, refcount: %ld)", + pentry->hitcnt, pentry->refcnt); + + vty_out (vty, "%s", VTY_NEWLINE); + } + } +} + +int +vty_show_prefix_list (struct vty *vty, afi_t afi, char *name, + char *seq, enum display_type dtype) +{ + struct prefix_list *plist; + struct prefix_master *master; + int seqnum = 0; + + master = prefix_master_get (afi); + if (master == NULL) + return CMD_WARNING; + + if (seq) + seqnum = atoi (seq); + + if (name) + { + plist = prefix_list_lookup (afi, name); + if (! plist) + { + vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum); + } + else + { + if (dtype == detail_display || dtype == summary_display) + { + if (master->recent) + vty_out (vty, "Prefix-list with the last deletion/insertion: %s%s", + master->recent->name, VTY_NEWLINE); + } + + for (plist = master->num.head; plist; plist = plist->next) + vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum); + + for (plist = master->str.head; plist; plist = plist->next) + vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum); + } + + return CMD_SUCCESS; +} + +int +vty_show_prefix_list_prefix (struct vty *vty, afi_t afi, char *name, + char *prefix, enum display_type type) +{ + struct prefix_list *plist; + struct prefix_list_entry *pentry; + struct prefix p; + int ret; + int match; + + plist = prefix_list_lookup (afi, name); + if (! plist) + { + vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2prefix (prefix, &p); + if (ret <= 0) + { + vty_out (vty, "%% prefix is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + match = 0; + + if (type == normal_display || type == first_match_display) + if (prefix_same (&p, &pentry->prefix)) + match = 1; + + if (type == longer_display) + if (prefix_match (&p, &pentry->prefix)) + match = 1; + + if (match) + { + vty_out (vty, " seq %d %s ", + pentry->seq, + prefix_list_type_str (pentry)); + + if (pentry->any) + vty_out (vty, "any"); + else + { + struct prefix *p = &pentry->prefix; + char buf[BUFSIZ]; + + vty_out (vty, "%s/%d", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + if (pentry->ge) + vty_out (vty, " ge %d", pentry->ge); + if (pentry->le) + vty_out (vty, " le %d", pentry->le); + } + + if (type == normal_display || type == first_match_display) + vty_out (vty, " (hit count: %ld, refcount: %ld)", + pentry->hitcnt, pentry->refcnt); + + vty_out (vty, "%s", VTY_NEWLINE); + + if (type == first_match_display) + return CMD_SUCCESS; + } + } + return CMD_SUCCESS; +} + +int +vty_clear_prefix_list (struct vty *vty, afi_t afi, char *name, char *prefix) +{ + struct prefix_master *master; + struct prefix_list *plist; + struct prefix_list_entry *pentry; + int ret; + struct prefix p; + + master = prefix_master_get (afi); + if (master == NULL) + return CMD_WARNING; + + if (name == NULL && prefix == NULL) + { + for (plist = master->num.head; plist; plist = plist->next) + for (pentry = plist->head; pentry; pentry = pentry->next) + pentry->hitcnt = 0; + + for (plist = master->str.head; plist; plist = plist->next) + for (pentry = plist->head; pentry; pentry = pentry->next) + pentry->hitcnt = 0; + } + else + { + plist = prefix_list_lookup (afi, name); + if (! plist) + { + vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (prefix) + { + ret = str2prefix (prefix, &p); + if (ret <= 0) + { + vty_out (vty, "%% prefix is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + if (prefix) + { + if (prefix_match (&pentry->prefix, &p)) + pentry->hitcnt = 0; + } + else + pentry->hitcnt = 0; + } + } + return CMD_SUCCESS; +} + +DEFUN (ip_prefix_list, + ip_prefix_list_cmd, + "ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, + argv[1], argv[2], NULL, NULL); +} + +DEFUN (ip_prefix_list_ge, + ip_prefix_list_ge_cmd, + "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], argv[3], NULL); +} + +DEFUN (ip_prefix_list_ge_le, + ip_prefix_list_ge_le_cmd, + "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4]); +} + +DEFUN (ip_prefix_list_le, + ip_prefix_list_le_cmd, + "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], NULL, argv[3]); +} + +DEFUN (ip_prefix_list_le_ge, + ip_prefix_list_le_ge_cmd, + "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], argv[4], argv[3]); +} + +DEFUN (ip_prefix_list_seq, + ip_prefix_list_seq_cmd, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], NULL, NULL); +} + +DEFUN (ip_prefix_list_seq_ge, + ip_prefix_list_seq_ge_cmd, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], argv[4], NULL); +} + +DEFUN (ip_prefix_list_seq_ge_le, + ip_prefix_list_seq_ge_le_cmd, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5]); +} + +DEFUN (ip_prefix_list_seq_le, + ip_prefix_list_seq_le_cmd, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], NULL, argv[4]); +} + +DEFUN (ip_prefix_list_seq_le_ge, + ip_prefix_list_seq_le_ge_cmd, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], argv[5], argv[4]); +} + +DEFUN (no_ip_prefix_list, + no_ip_prefix_list_cmd, + "no ip prefix-list WORD", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, NULL, + NULL, NULL, NULL); +} + +DEFUN (no_ip_prefix_list_prefix, + no_ip_prefix_list_prefix_cmd, + "no ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], NULL, NULL); +} + +DEFUN (no_ip_prefix_list_ge, + no_ip_prefix_list_ge_cmd, + "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], argv[3], NULL); +} + +DEFUN (no_ip_prefix_list_ge_le, + no_ip_prefix_list_ge_le_cmd, + "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4]); +} + +DEFUN (no_ip_prefix_list_le, + no_ip_prefix_list_le_cmd, + "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], NULL, argv[3]); +} + +DEFUN (no_ip_prefix_list_le_ge, + no_ip_prefix_list_le_ge_cmd, + "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1], + argv[2], argv[4], argv[3]); +} + +DEFUN (no_ip_prefix_list_seq, + no_ip_prefix_list_seq_cmd, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], NULL, NULL); +} + +DEFUN (no_ip_prefix_list_seq_ge, + no_ip_prefix_list_seq_ge_cmd, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], argv[4], NULL); +} + +DEFUN (no_ip_prefix_list_seq_ge_le, + no_ip_prefix_list_seq_ge_le_cmd, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5]); +} + +DEFUN (no_ip_prefix_list_seq_le, + no_ip_prefix_list_seq_le_cmd, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], NULL, argv[4]); +} + +DEFUN (no_ip_prefix_list_seq_le_ge, + no_ip_prefix_list_seq_le_ge_cmd, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2], + argv[3], argv[5], argv[4]); +} + +DEFUN (ip_prefix_list_sequence_number, + ip_prefix_list_sequence_number_cmd, + "ip prefix-list sequence-number", + IP_STR + PREFIX_LIST_STR + "Include/exclude sequence numbers in NVGEN\n") +{ + prefix_master_ipv4.seqnum = 1; + return CMD_SUCCESS; +} + +DEFUN (no_ip_prefix_list_sequence_number, + no_ip_prefix_list_sequence_number_cmd, + "no ip prefix-list sequence-number", + NO_STR + IP_STR + PREFIX_LIST_STR + "Include/exclude sequence numbers in NVGEN\n") +{ + prefix_master_ipv4.seqnum = 0; + return CMD_SUCCESS; +} + +DEFUN (ip_prefix_list_description, + ip_prefix_list_description_cmd, + "ip prefix-list WORD description .LINE", + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Prefix-list specific description\n" + "Up to 80 characters describing this prefix-list\n") +{ + struct prefix_list *plist; + struct buffer *b; + int i; + + plist = prefix_list_get (AFI_IP, argv[0]); + + if (plist->desc) + { + XFREE (MTYPE_TMP, plist->desc); + plist->desc = NULL; + } + + /* Below is description get codes. */ + b = buffer_new (1024); + for (i = 1; i < argc; i++) + { + buffer_putstr (b, (u_char *)argv[i]); + buffer_putc (b, ' '); + } + buffer_putc (b, '\0'); + + plist->desc = buffer_getstr (b); + + buffer_free (b); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_prefix_list_description, + no_ip_prefix_list_description_cmd, + "no ip prefix-list WORD description", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Prefix-list specific description\n") +{ + return vty_prefix_list_desc_unset (vty, AFI_IP, argv[0]); +} + +ALIAS (no_ip_prefix_list_description, + no_ip_prefix_list_description_arg_cmd, + "no ip prefix-list WORD description .LINE", + NO_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Prefix-list specific description\n" + "Up to 80 characters describing this prefix-list\n"); + +DEFUN (show_ip_prefix_list, + show_ip_prefix_list_cmd, + "show ip prefix-list", + SHOW_STR + IP_STR + PREFIX_LIST_STR) +{ + return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, normal_display); +} + +DEFUN (show_ip_prefix_list_name, + show_ip_prefix_list_name_cmd, + "show ip prefix-list WORD", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n") +{ + return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, normal_display); +} + +DEFUN (show_ip_prefix_list_name_seq, + show_ip_prefix_list_name_seq_cmd, + "show ip prefix-list WORD seq <1-4294967295>", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n") +{ + return vty_show_prefix_list (vty, AFI_IP, argv[0], argv[1], sequential_display); +} + +DEFUN (show_ip_prefix_list_prefix, + show_ip_prefix_list_prefix_cmd, + "show ip prefix-list WORD A.B.C.D/M", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], normal_display); +} + +DEFUN (show_ip_prefix_list_prefix_longer, + show_ip_prefix_list_prefix_longer_cmd, + "show ip prefix-list WORD A.B.C.D/M longer", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Lookup longer prefix\n") +{ + return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], longer_display); +} + +DEFUN (show_ip_prefix_list_prefix_first_match, + show_ip_prefix_list_prefix_first_match_cmd, + "show ip prefix-list WORD A.B.C.D/M first-match", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "First matched prefix\n") +{ + return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], first_match_display); +} + +DEFUN (show_ip_prefix_list_summary, + show_ip_prefix_list_summary_cmd, + "show ip prefix-list summary", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Summary of prefix lists\n") +{ + return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, summary_display); +} + +DEFUN (show_ip_prefix_list_summary_name, + show_ip_prefix_list_summary_name_cmd, + "show ip prefix-list summary WORD", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Summary of prefix lists\n" + "Name of a prefix list\n") +{ + return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, summary_display); +} + + +DEFUN (show_ip_prefix_list_detail, + show_ip_prefix_list_detail_cmd, + "show ip prefix-list detail", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Detail of prefix lists\n") +{ + return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, detail_display); +} + +DEFUN (show_ip_prefix_list_detail_name, + show_ip_prefix_list_detail_name_cmd, + "show ip prefix-list detail WORD", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Detail of prefix lists\n" + "Name of a prefix list\n") +{ + return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, detail_display); +} + +DEFUN (clear_ip_prefix_list, + clear_ip_prefix_list_cmd, + "clear ip prefix-list", + CLEAR_STR + IP_STR + PREFIX_LIST_STR) +{ + return vty_clear_prefix_list (vty, AFI_IP, NULL, NULL); +} + +DEFUN (clear_ip_prefix_list_name, + clear_ip_prefix_list_name_cmd, + "clear ip prefix-list WORD", + CLEAR_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n") +{ + return vty_clear_prefix_list (vty, AFI_IP, argv[0], NULL); +} + +DEFUN (clear_ip_prefix_list_name_prefix, + clear_ip_prefix_list_name_prefix_cmd, + "clear ip prefix-list WORD A.B.C.D/M", + CLEAR_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + return vty_clear_prefix_list (vty, AFI_IP, argv[0], argv[1]); +} + +#ifdef HAVE_IPV6 +DEFUN (ipv6_prefix_list, + ipv6_prefix_list_cmd, + "ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Any prefix match. Same as \"::0/0 le 128\"\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, + argv[1], argv[2], NULL, NULL); +} + +DEFUN (ipv6_prefix_list_ge, + ipv6_prefix_list_ge_cmd, + "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], argv[3], NULL); +} + +DEFUN (ipv6_prefix_list_ge_le, + ipv6_prefix_list_ge_le_cmd, + "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4]); +} + +DEFUN (ipv6_prefix_list_le, + ipv6_prefix_list_le_cmd, + "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], NULL, argv[3]); +} + +DEFUN (ipv6_prefix_list_le_ge, + ipv6_prefix_list_le_ge_cmd, + "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], argv[4], argv[3]); +} + +DEFUN (ipv6_prefix_list_seq, + ipv6_prefix_list_seq_cmd, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Any prefix match. Same as \"::0/0 le 128\"\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], NULL, NULL); +} + +DEFUN (ipv6_prefix_list_seq_ge, + ipv6_prefix_list_seq_ge_cmd, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], argv[4], NULL); +} + +DEFUN (ipv6_prefix_list_seq_ge_le, + ipv6_prefix_list_seq_ge_le_cmd, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5]); +} + +DEFUN (ipv6_prefix_list_seq_le, + ipv6_prefix_list_seq_le_cmd, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], NULL, argv[4]); +} + +DEFUN (ipv6_prefix_list_seq_le_ge, + ipv6_prefix_list_seq_le_ge_cmd, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], argv[5], argv[4]); +} + +DEFUN (no_ipv6_prefix_list, + no_ipv6_prefix_list_cmd, + "no ipv6 prefix-list WORD", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, NULL, + NULL, NULL, NULL); +} + +DEFUN (no_ipv6_prefix_list_prefix, + no_ipv6_prefix_list_prefix_cmd, + "no ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Any prefix match. Same as \"::0/0 le 128\"\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], NULL, NULL); +} + +DEFUN (no_ipv6_prefix_list_ge, + no_ipv6_prefix_list_ge_cmd, + "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], argv[3], NULL); +} + +DEFUN (no_ipv6_prefix_list_ge_le, + no_ipv6_prefix_list_ge_le_cmd, + "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], argv[3], argv[4]); +} + +DEFUN (no_ipv6_prefix_list_le, + no_ipv6_prefix_list_le_cmd, + "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], NULL, argv[3]); +} + +DEFUN (no_ipv6_prefix_list_le_ge, + no_ipv6_prefix_list_le_ge_cmd, + "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1], + argv[2], argv[4], argv[3]); +} + +DEFUN (no_ipv6_prefix_list_seq, + no_ipv6_prefix_list_seq_cmd, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Any prefix match. Same as \"::0/0 le 128\"\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], NULL, NULL); +} + +DEFUN (no_ipv6_prefix_list_seq_ge, + no_ipv6_prefix_list_seq_ge_cmd, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], argv[4], NULL); +} + +DEFUN (no_ipv6_prefix_list_seq_ge_le, + no_ipv6_prefix_list_seq_ge_le_cmd, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5]); +} + +DEFUN (no_ipv6_prefix_list_seq_le, + no_ipv6_prefix_list_seq_le_cmd, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], NULL, argv[4]); +} + +DEFUN (no_ipv6_prefix_list_seq_le_ge, + no_ipv6_prefix_list_seq_le_ge_cmd, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") +{ + return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2], + argv[3], argv[5], argv[4]); +} + +DEFUN (ipv6_prefix_list_sequence_number, + ipv6_prefix_list_sequence_number_cmd, + "ipv6 prefix-list sequence-number", + IPV6_STR + PREFIX_LIST_STR + "Include/exclude sequence numbers in NVGEN\n") +{ + prefix_master_ipv6.seqnum = 1; + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_prefix_list_sequence_number, + no_ipv6_prefix_list_sequence_number_cmd, + "no ipv6 prefix-list sequence-number", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Include/exclude sequence numbers in NVGEN\n") +{ + prefix_master_ipv6.seqnum = 0; + return CMD_SUCCESS; +} + +DEFUN (ipv6_prefix_list_description, + ipv6_prefix_list_description_cmd, + "ipv6 prefix-list WORD description .LINE", + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Prefix-list specific description\n" + "Up to 80 characters describing this prefix-list\n") +{ + struct prefix_list *plist; + struct buffer *b; + int i; + + plist = prefix_list_get (AFI_IP6, argv[0]); + + if (plist->desc) + { + XFREE (MTYPE_TMP, plist->desc); + plist->desc = NULL; + } + + /* Below is description get codes. */ + b = buffer_new (1024); + for (i = 1; i < argc; i++) + { + buffer_putstr (b, (u_char *)argv[i]); + buffer_putc (b, ' '); + } + buffer_putc (b, '\0'); + + plist->desc = buffer_getstr (b); + + buffer_free (b); + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_prefix_list_description, + no_ipv6_prefix_list_description_cmd, + "no ipv6 prefix-list WORD description", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Prefix-list specific description\n") +{ + return vty_prefix_list_desc_unset (vty, AFI_IP6, argv[0]); +} + +ALIAS (no_ipv6_prefix_list_description, + no_ipv6_prefix_list_description_arg_cmd, + "no ipv6 prefix-list WORD description .LINE", + NO_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "Prefix-list specific description\n" + "Up to 80 characters describing this prefix-list\n"); + +DEFUN (show_ipv6_prefix_list, + show_ipv6_prefix_list_cmd, + "show ipv6 prefix-list", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR) +{ + return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, normal_display); +} + +DEFUN (show_ipv6_prefix_list_name, + show_ipv6_prefix_list_name_cmd, + "show ipv6 prefix-list WORD", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n") +{ + return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, normal_display); +} + +DEFUN (show_ipv6_prefix_list_name_seq, + show_ipv6_prefix_list_name_seq_cmd, + "show ipv6 prefix-list WORD seq <1-4294967295>", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n") +{ + return vty_show_prefix_list (vty, AFI_IP6, argv[0], argv[1], sequential_display); +} + +DEFUN (show_ipv6_prefix_list_prefix, + show_ipv6_prefix_list_prefix_cmd, + "show ipv6 prefix-list WORD X:X::X:X/M", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") +{ + return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], normal_display); +} + +DEFUN (show_ipv6_prefix_list_prefix_longer, + show_ipv6_prefix_list_prefix_longer_cmd, + "show ipv6 prefix-list WORD X:X::X:X/M longer", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Lookup longer prefix\n") +{ + return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], longer_display); +} + +DEFUN (show_ipv6_prefix_list_prefix_first_match, + show_ipv6_prefix_list_prefix_first_match_cmd, + "show ipv6 prefix-list WORD X:X::X:X/M first-match", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "First matched prefix\n") +{ + return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], first_match_display); +} + +DEFUN (show_ipv6_prefix_list_summary, + show_ipv6_prefix_list_summary_cmd, + "show ipv6 prefix-list summary", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Summary of prefix lists\n") +{ + return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, summary_display); +} + +DEFUN (show_ipv6_prefix_list_summary_name, + show_ipv6_prefix_list_summary_name_cmd, + "show ipv6 prefix-list summary WORD", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Summary of prefix lists\n" + "Name of a prefix list\n") +{ + return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, summary_display); +} + +DEFUN (show_ipv6_prefix_list_detail, + show_ipv6_prefix_list_detail_cmd, + "show ipv6 prefix-list detail", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Detail of prefix lists\n") +{ + return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, detail_display); +} + +DEFUN (show_ipv6_prefix_list_detail_name, + show_ipv6_prefix_list_detail_name_cmd, + "show ipv6 prefix-list detail WORD", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Detail of prefix lists\n" + "Name of a prefix list\n") +{ + return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, detail_display); +} + +DEFUN (clear_ipv6_prefix_list, + clear_ipv6_prefix_list_cmd, + "clear ipv6 prefix-list", + CLEAR_STR + IPV6_STR + PREFIX_LIST_STR) +{ + return vty_clear_prefix_list (vty, AFI_IP6, NULL, NULL); +} + +DEFUN (clear_ipv6_prefix_list_name, + clear_ipv6_prefix_list_name_cmd, + "clear ipv6 prefix-list WORD", + CLEAR_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n") +{ + return vty_clear_prefix_list (vty, AFI_IP6, argv[0], NULL); +} + +DEFUN (clear_ipv6_prefix_list_name_prefix, + clear_ipv6_prefix_list_name_prefix_cmd, + "clear ipv6 prefix-list WORD X:X::X:X/M", + CLEAR_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") +{ + return vty_clear_prefix_list (vty, AFI_IP6, argv[0], argv[1]); +} +#endif /* HAVE_IPV6 */ + +/* Configuration write function. */ +int +config_write_prefix_afi (afi_t afi, struct vty *vty) +{ + struct prefix_list *plist; + struct prefix_list_entry *pentry; + struct prefix_master *master; + int write = 0; + + master = prefix_master_get (afi); + if (master == NULL) + return 0; + + if (! master->seqnum) + { + vty_out (vty, "no ip%s prefix-list sequence-number%s", + afi == AFI_IP ? "" : "v6", VTY_NEWLINE); + vty_out (vty, "!%s", VTY_NEWLINE); + } + + for (plist = master->num.head; plist; plist = plist->next) + { + if (plist->desc) + { + vty_out (vty, "ip%s prefix-list %s description %s%s", + afi == AFI_IP ? "" : "v6", + plist->name, plist->desc, VTY_NEWLINE); + write++; + } + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + vty_out (vty, "ip%s prefix-list %s ", + afi == AFI_IP ? "" : "v6", + plist->name); + + if (master->seqnum) + vty_out (vty, "seq %d ", pentry->seq); + + vty_out (vty, "%s ", prefix_list_type_str (pentry)); + + if (pentry->any) + vty_out (vty, "any"); + else + { + struct prefix *p = &pentry->prefix; + char buf[BUFSIZ]; + + vty_out (vty, "%s/%d", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + if (pentry->ge) + vty_out (vty, " ge %d", pentry->ge); + if (pentry->le) + vty_out (vty, " le %d", pentry->le); + } + vty_out (vty, "%s", VTY_NEWLINE); + write++; + } + /* vty_out (vty, "!%s", VTY_NEWLINE); */ + } + + for (plist = master->str.head; plist; plist = plist->next) + { + if (plist->desc) + { + vty_out (vty, "ip%s prefix-list %s description %s%s", + afi == AFI_IP ? "" : "v6", + plist->name, plist->desc, VTY_NEWLINE); + write++; + } + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + vty_out (vty, "ip%s prefix-list %s ", + afi == AFI_IP ? "" : "v6", + plist->name); + + if (master->seqnum) + vty_out (vty, "seq %d ", pentry->seq); + + vty_out (vty, "%s", prefix_list_type_str (pentry)); + + if (pentry->any) + vty_out (vty, " any"); + else + { + struct prefix *p = &pentry->prefix; + char buf[BUFSIZ]; + + vty_out (vty, " %s/%d", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + if (pentry->ge) + vty_out (vty, " ge %d", pentry->ge); + if (pentry->le) + vty_out (vty, " le %d", pentry->le); + } + vty_out (vty, "%s", VTY_NEWLINE); + write++; + } + } + + return write; +} + +int stream_putc (struct stream *, u_char); +int stream_putl (struct stream *, u_int32_t); +int stream_put_prefix (struct stream *, struct prefix *); + +struct stream * +prefix_bgp_orf_entry (struct stream *s, struct prefix_list *plist, + u_char init_flag, u_char permit_flag, u_char deny_flag) +{ + struct prefix_list_entry *pentry; + + if (! plist) + return s; + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + u_char flag = init_flag; + struct prefix *p = &pentry->prefix; + + flag |= (pentry->type == PREFIX_PERMIT ? + permit_flag : deny_flag); + stream_putc (s, flag); + stream_putl (s, (u_int32_t)pentry->seq); + stream_putc (s, (u_char)pentry->ge); + stream_putc (s, (u_char)pentry->le); + stream_put_prefix (s, p); + } + + return s; +} + +int +prefix_bgp_orf_set (char *name, afi_t afi, struct orf_prefix *orfp, + int permit, int set) +{ + struct prefix_list *plist; + struct prefix_list_entry *pentry; + + /* ge and le value check */ + if (orfp->ge && orfp->ge <= orfp->p.prefixlen) + return CMD_WARNING; + if (orfp->le && orfp->le <= orfp->p.prefixlen) + return CMD_WARNING; + if (orfp->le && orfp->ge > orfp->le) + return CMD_WARNING; + + if (orfp->ge && orfp->le == (afi == AFI_IP ? 32 : 128)) + orfp->le = 0; + + plist = prefix_list_get (AFI_ORF_PREFIX, name); + if (! plist) + return CMD_WARNING; + + if (set) + { + pentry = prefix_list_entry_make (&orfp->p, + (permit ? PREFIX_PERMIT : PREFIX_DENY), + orfp->seq, orfp->le, orfp->ge, 0); + + if (prefix_entry_dup_check (plist, pentry)) + { + prefix_list_entry_free (pentry); + return CMD_WARNING; + } + + prefix_list_entry_add (plist, pentry); + } + else + { + pentry = prefix_list_entry_lookup (plist, &orfp->p, + (permit ? PREFIX_PERMIT : PREFIX_DENY), + orfp->seq, orfp->le, orfp->ge); + + if (! pentry) + return CMD_WARNING; + + prefix_list_entry_delete (plist, pentry, 1); + } + + return CMD_SUCCESS; +} + +void +prefix_bgp_orf_remove_all (char *name) +{ + struct prefix_list *plist; + + plist = prefix_list_lookup (AFI_ORF_PREFIX, name); + if (plist) + prefix_list_delete (plist); +} + +/* return prefix count */ +int +prefix_bgp_show_prefix_list (struct vty *vty, afi_t afi, char *name) +{ + struct prefix_list *plist; + struct prefix_list_entry *pentry; + + plist = prefix_list_lookup (AFI_ORF_PREFIX, name); + if (! plist) + return 0; + + if (! vty) + return plist->count; + + vty_out (vty, "ip%s prefix-list %s: %d entries%s", + afi == AFI_IP ? "" : "v6", + plist->name, plist->count, VTY_NEWLINE); + + for (pentry = plist->head; pentry; pentry = pentry->next) + { + struct prefix *p = &pentry->prefix; + char buf[BUFSIZ]; + + vty_out (vty, " seq %d %s %s/%d", pentry->seq, + prefix_list_type_str (pentry), + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + if (pentry->ge) + vty_out (vty, " ge %d", pentry->ge); + if (pentry->le) + vty_out (vty, " le %d", pentry->le); + + vty_out (vty, "%s", VTY_NEWLINE); + } + return plist->count; +} + +void +prefix_list_reset_orf () +{ + struct prefix_list *plist; + struct prefix_list *next; + struct prefix_master *master; + + master = prefix_master_get (AFI_ORF_PREFIX); + if (master == NULL) + return; + + for (plist = master->num.head; plist; plist = next) + { + next = plist->next; + prefix_list_delete (plist); + } + for (plist = master->str.head; plist; plist = next) + { + next = plist->next; + prefix_list_delete (plist); + } + + assert (master->num.head == NULL); + assert (master->num.tail == NULL); + + assert (master->str.head == NULL); + assert (master->str.tail == NULL); + + master->seqnum = 1; + master->recent = NULL; +} + + +/* Prefix-list node. */ +struct cmd_node prefix_node = +{ + PREFIX_NODE, + "", /* Prefix list has no interface. */ + 1 +}; + +int +config_write_prefix_ipv4 (struct vty *vty) +{ + return config_write_prefix_afi (AFI_IP, vty); +} + +void +prefix_list_reset_ipv4 () +{ + struct prefix_list *plist; + struct prefix_list *next; + struct prefix_master *master; + + master = prefix_master_get (AFI_IP); + if (master == NULL) + return; + + for (plist = master->num.head; plist; plist = next) + { + next = plist->next; + prefix_list_delete (plist); + } + for (plist = master->str.head; plist; plist = next) + { + next = plist->next; + prefix_list_delete (plist); + } + + assert (master->num.head == NULL); + assert (master->num.tail == NULL); + + assert (master->str.head == NULL); + assert (master->str.tail == NULL); + + master->seqnum = 1; + master->recent = NULL; +} + +void +prefix_list_init_ipv4 () +{ + install_node (&prefix_node, config_write_prefix_ipv4); + + install_element (CONFIG_NODE, &ip_prefix_list_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_ge_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_ge_le_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_le_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_le_ge_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_seq_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_le_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_seq_le_cmd); + install_element (CONFIG_NODE, &ip_prefix_list_seq_le_ge_cmd); + + install_element (CONFIG_NODE, &no_ip_prefix_list_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_prefix_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_ge_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_ge_le_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_le_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_le_ge_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_le_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_ge_cmd); + + install_element (CONFIG_NODE, &ip_prefix_list_description_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_description_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_description_arg_cmd); + + install_element (CONFIG_NODE, &ip_prefix_list_sequence_number_cmd); + install_element (CONFIG_NODE, &no_ip_prefix_list_sequence_number_cmd); + + install_element (VIEW_NODE, &show_ip_prefix_list_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_name_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_name_seq_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_prefix_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_prefix_first_match_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_summary_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_summary_name_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_detail_cmd); + install_element (VIEW_NODE, &show_ip_prefix_list_detail_name_cmd); + + install_element (ENABLE_NODE, &show_ip_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_name_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_name_seq_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_first_match_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_summary_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_summary_name_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_detail_cmd); + install_element (ENABLE_NODE, &show_ip_prefix_list_detail_name_cmd); + + install_element (ENABLE_NODE, &clear_ip_prefix_list_cmd); + install_element (ENABLE_NODE, &clear_ip_prefix_list_name_cmd); + install_element (ENABLE_NODE, &clear_ip_prefix_list_name_prefix_cmd); +} + +#ifdef HAVE_IPV6 +/* Prefix-list node. */ +struct cmd_node prefix_ipv6_node = +{ + PREFIX_IPV6_NODE, + "", /* Prefix list has no interface. */ + 1 +}; + +int +config_write_prefix_ipv6 (struct vty *vty) +{ + return config_write_prefix_afi (AFI_IP6, vty); +} + +void +prefix_list_reset_ipv6 () +{ + struct prefix_list *plist; + struct prefix_list *next; + struct prefix_master *master; + + master = prefix_master_get (AFI_IP6); + if (master == NULL) + return; + + for (plist = master->num.head; plist; plist = next) + { + next = plist->next; + prefix_list_delete (plist); + } + for (plist = master->str.head; plist; plist = next) + { + next = plist->next; + prefix_list_delete (plist); + } + + assert (master->num.head == NULL); + assert (master->num.tail == NULL); + + assert (master->str.head == NULL); + assert (master->str.tail == NULL); + + master->seqnum = 1; + master->recent = NULL; +} + +void +prefix_list_init_ipv6 () +{ + install_node (&prefix_ipv6_node, config_write_prefix_ipv6); + + install_element (CONFIG_NODE, &ipv6_prefix_list_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_ge_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_ge_le_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_le_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_le_ge_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_le_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_cmd); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_ge_cmd); + + install_element (CONFIG_NODE, &no_ipv6_prefix_list_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_prefix_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_le_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_ge_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_le_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_ge_cmd); + + install_element (CONFIG_NODE, &ipv6_prefix_list_description_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_arg_cmd); + + install_element (CONFIG_NODE, &ipv6_prefix_list_sequence_number_cmd); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_sequence_number_cmd); + + install_element (VIEW_NODE, &show_ipv6_prefix_list_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_name_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_name_seq_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_name_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_cmd); + install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_name_cmd); + + install_element (ENABLE_NODE, &show_ipv6_prefix_list_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_seq_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_name_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_cmd); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_name_cmd); + + install_element (ENABLE_NODE, &clear_ipv6_prefix_list_cmd); + install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_cmd); + install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_prefix_cmd); +} +#endif /* HAVE_IPV6 */ + +void +prefix_list_init () +{ + prefix_list_init_ipv4 (); +#ifdef HAVE_IPV6 + prefix_list_init_ipv6 (); +#endif /* HAVE_IPV6 */ +} + +void +prefix_list_reset () +{ + prefix_list_reset_ipv4 (); +#ifdef HAVE_IPV6 + prefix_list_reset_ipv6 (); +#endif /* HAVE_IPV6 */ + prefix_list_reset_orf (); +} diff --git a/lib/plist.h b/lib/plist.h new file mode 100644 index 0000000..9a9eb71 --- /dev/null +++ b/lib/plist.h @@ -0,0 +1,78 @@ +/* + * Prefix list functions. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#define AFI_ORF_PREFIX 65535 + +enum prefix_list_type +{ + PREFIX_DENY, + PREFIX_PERMIT, +}; + +enum prefix_name_type +{ + PREFIX_TYPE_STRING, + PREFIX_TYPE_NUMBER +}; + +struct prefix_list +{ + char *name; + char *desc; + + struct prefix_master *master; + + enum prefix_name_type type; + + int count; + int rangecount; + + struct prefix_list_entry *head; + struct prefix_list_entry *tail; + + struct prefix_list *next; + struct prefix_list *prev; +}; + +struct orf_prefix +{ + u_int32_t seq; + u_char ge; + u_char le; + struct prefix p; +}; + +/* Prototypes. */ +void prefix_list_init (void); +void prefix_list_reset (void); +void prefix_list_add_hook (void (*func) (struct prefix_list *)); +void prefix_list_delete_hook (void (*func) (struct prefix_list *)); + +struct prefix_list *prefix_list_lookup (afi_t, char *); +enum prefix_list_type prefix_list_apply (struct prefix_list *, void *); + +struct stream * +prefix_bgp_orf_entry (struct stream *, struct prefix_list *, + u_char, u_char, u_char); +int prefix_bgp_orf_set (char *, afi_t, struct orf_prefix *, int, int); +void prefix_bgp_orf_remove_all (char *); +int prefix_bgp_show_prefix_list (struct vty *, afi_t, char *); diff --git a/lib/pqueue.c b/lib/pqueue.c new file mode 100644 index 0000000..1e41b09 --- /dev/null +++ b/lib/pqueue.c @@ -0,0 +1,160 @@ +/* Priority queue functions. + Copyright (C) 2003 Yasuhiro Ohara + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your +option) any later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include + +#include "pqueue.h" + +/* priority queue using heap sort */ + +/* pqueue->cmp() controls the order of sorting (i.e, ascending or + descending). If you want the left node to move upper of the heap + binary tree, make cmp() to return less than 0. for example, if cmp + (10, 20) returns -1, the sorting is ascending order. if cmp (10, + 20) returns 1, the sorting is descending order. if cmp (10, 20) + returns 0, this library does not do sorting (which will not be what + you want). To be brief, if the contents of cmp_func (left, right) + is left - right, dequeue () returns the smallest node. Otherwise + (if the contents is right - left), dequeue () returns the largest + node. */ + +#define DATA_SIZE (sizeof (void *)) +#define PARENT_OF(x) ((x - 1) / 2) +#define LEFT_OF(x) (2 * x + 1) +#define RIGHT_OF(x) (2 * x + 2) +#define HAVE_CHILD(x,q) (x < (q)->size / 2) + +static void +trickle_up (int index, struct pqueue *queue) +{ + void *tmp; + + /* Save current node as tmp node. */ + tmp = queue->array[index]; + + /* Continue until the node reaches top or the place where the parent + node should be upper than the tmp node. */ + while (index > 0 && + (*queue->cmp) (tmp, queue->array[PARENT_OF (index)]) < 0) + { + /* actually trickle up */ + queue->array[index] = queue->array[PARENT_OF (index)]; + index = PARENT_OF (index); + } + + /* Restore the tmp node to appropriate place. */ + queue->array[index] = tmp; +} + +static void +trickle_down (int index, struct pqueue *queue) +{ + void *tmp; + int which; + + /* Save current node as tmp node. */ + tmp = queue->array[index]; + + /* Continue until the node have at least one (left) child. */ + while (HAVE_CHILD (index, queue)) + { + /* If right child exists, and if the right child is more proper + to be moved upper. */ + if (RIGHT_OF (index) < queue->size && + (*queue->cmp) (queue->array[LEFT_OF (index)], + queue->array[RIGHT_OF (index)]) > 0) + which = RIGHT_OF (index); + else + which = LEFT_OF (index); + + /* If the tmp node should be upper than the child, break. */ + if ((*queue->cmp) (queue->array[which], tmp) > 0) + break; + + /* Actually trickle down the tmp node. */ + queue->array[index] = queue->array[which]; + index = which; + } + + /* Restore the tmp node to appropriate place. */ + queue->array[index] = tmp; +} + +struct pqueue * +pqueue_create () +{ + struct pqueue *queue; + + queue = (struct pqueue *) malloc (sizeof (struct pqueue)); + memset (queue, 0, sizeof (struct pqueue)); + + queue->array = (void **) + malloc (DATA_SIZE * PQUEUE_INIT_ARRAYSIZE); + memset (queue->array, 0, DATA_SIZE * PQUEUE_INIT_ARRAYSIZE); + queue->array_size = PQUEUE_INIT_ARRAYSIZE; + + return queue; +} + +void +pqueue_delete (struct pqueue *queue) +{ + free (queue->array); + free (queue); +} + +static int +pqueue_expand (struct pqueue *queue) +{ + void **newarray; + + newarray = (void **) malloc (queue->array_size * DATA_SIZE * 2); + if (newarray == NULL) + return 0; + + memset (newarray, 0, queue->array_size * DATA_SIZE * 2); + memcpy (newarray, queue->array, queue->array_size * DATA_SIZE); + + free (queue->array); + queue->array = newarray; + queue->array_size *= 2; + + return 1; +} + +void +pqueue_enqueue (void *data, struct pqueue *queue) +{ + if (queue->size + 2 >= queue->array_size && ! pqueue_expand (queue)) + return; + + queue->array[queue->size] = data; + trickle_up (queue->size, queue); + queue->size ++; +} + +void * +pqueue_dequeue (struct pqueue *queue) +{ + void *data = queue->array[0]; + queue->array[0] = queue->array[--queue->size]; + trickle_down (0, queue); + return data; +} diff --git a/lib/pqueue.h b/lib/pqueue.h new file mode 100644 index 0000000..95f79b8 --- /dev/null +++ b/lib/pqueue.h @@ -0,0 +1,41 @@ +/* Priority queue functions. + Copyright (C) 2003 Yasuhiro Ohara + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your +option) any later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef _ZEBRA_PQUEUE_H +#define _ZEBRA_PQUEUE_H + +struct pqueue +{ + void **array; + int array_size; + int size; + + int (*cmp) (void *, void *); +}; + +#define PQUEUE_INIT_ARRAYSIZE 32 + +struct pqueue *pqueue_create (); +void pqueue_delete (struct pqueue *queue); + +void pqueue_enqueue (void *data, struct pqueue *queue); +void *pqueue_dequeue (struct pqueue *queue); + +#endif /* _ZEBRA_PQUEUE_H */ diff --git a/lib/prefix.c b/lib/prefix.c new file mode 100644 index 0000000..61e0f19 --- /dev/null +++ b/lib/prefix.c @@ -0,0 +1,696 @@ +/* + * Prefix related functions. + * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "vty.h" +#include "sockunion.h" +#include "memory.h" +#include "log.h" + +/* Maskbit. */ +static u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, + 0xf8, 0xfc, 0xfe, 0xff}; + +/* Number of bits in prefix type. */ +#ifndef PNBBY +#define PNBBY 8 +#endif /* PNBBY */ + +#define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff) + +/* Address Famiy Identifier to Address Family converter. */ +int +afi2family (int afi) +{ + if (afi == AFI_IP) + return AF_INET; +#ifdef HAVE_IPV6 + else if (afi == AFI_IP6) + return AF_INET6; +#endif /* HAVE_IPV6 */ + return 0; +} + +int +family2afi (int family) +{ + if (family == AF_INET) + return AFI_IP; +#ifdef HAVE_IPV6 + else if (family == AF_INET6) + return AFI_IP6; +#endif /* HAVE_IPV6 */ + return 0; +} + +/* If n includes p prefix then return 1 else return 0. */ +int +prefix_match (struct prefix *n, struct prefix *p) +{ + int offset; + int shift; + + /* Set both prefix's head pointer. */ + u_char *np = (u_char *)&n->u.prefix; + u_char *pp = (u_char *)&p->u.prefix; + + /* If n's prefix is longer than p's one return 0. */ + if (n->prefixlen > p->prefixlen) + return 0; + + offset = n->prefixlen / PNBBY; + shift = n->prefixlen % PNBBY; + + if (shift) + if (maskbit[shift] & (np[offset] ^ pp[offset])) + return 0; + + while (offset--) + if (np[offset] != pp[offset]) + return 0; + return 1; +} + +/* Copy prefix from src to dest. */ +void +prefix_copy (struct prefix *dest, struct prefix *src) +{ + dest->family = src->family; + dest->prefixlen = src->prefixlen; + + if (src->family == AF_INET) + dest->u.prefix4 = src->u.prefix4; +#ifdef HAVE_IPV6 + else if (src->family == AF_INET6) + dest->u.prefix6 = src->u.prefix6; +#endif /* HAVE_IPV6 */ + else if (src->family == AF_UNSPEC) + { + dest->u.lp.id = src->u.lp.id; + dest->u.lp.adv_router = src->u.lp.adv_router; + } + else + { + zlog (NULL, LOG_INFO, "prefix_copy(): Unknown address family %d", + src->family); + assert (0); + } +} + +/* If both prefix structure is same then return 1 else return 0. */ +int +prefix_same (struct prefix *p1, struct prefix *p2) +{ + if (p1->family == p2->family && p1->prefixlen == p2->prefixlen) + { + if (p1->family == AF_INET) + if (IPV4_ADDR_SAME (&p1->u.prefix, &p2->u.prefix)) + return 1; +#ifdef HAVE_IPV6 + if (p1->family == AF_INET6 ) + if (IPV6_ADDR_SAME (&p1->u.prefix, &p2->u.prefix)) + return 1; +#endif /* HAVE_IPV6 */ + } + return 0; +} + +/* When both prefix structure is not same, but will be same after + applying mask, return 0. otherwise, return 1 */ +int +prefix_cmp (struct prefix *p1, struct prefix *p2) +{ + int offset; + int shift; + + /* Set both prefix's head pointer. */ + u_char *pp1 = (u_char *)&p1->u.prefix; + u_char *pp2 = (u_char *)&p2->u.prefix; + + if (p1->family != p2->family || p1->prefixlen != p2->prefixlen) + return 1; + + offset = p1->prefixlen / 8; + shift = p1->prefixlen % 8; + + if (shift) + if (maskbit[shift] & (pp1[offset] ^ pp2[offset])) + return 1; + + while (offset--) + if (pp1[offset] != pp2[offset]) + return 1; + + return 0; +} + +/* Return prefix family type string. */ +char * +prefix_family_str (struct prefix *p) +{ + if (p->family == AF_INET) + return "inet"; +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + return "inet6"; +#endif /* HAVE_IPV6 */ + return "unspec"; +} + +/* Allocate new prefix_ipv4 structure. */ +struct prefix_ipv4 * +prefix_ipv4_new () +{ + struct prefix_ipv4 *p; + + p = XCALLOC (MTYPE_PREFIX_IPV4, sizeof *p); + p->family = AF_INET; + return p; +} + +/* Free prefix_ipv4 structure. */ +void +prefix_ipv4_free (struct prefix_ipv4 *p) +{ + XFREE (MTYPE_PREFIX_IPV4, p); +} + +/* When string format is invalid return 0. */ +int +str2prefix_ipv4 (char *str, struct prefix_ipv4 *p) +{ + int ret; + int plen; + char *pnt; + char *cp; + + /* Find slash inside string. */ + pnt = strchr (str, '/'); + + /* String doesn't contail slash. */ + if (pnt == NULL) + { + /* Convert string to prefix. */ + ret = inet_aton (str, &p->prefix); + if (ret == 0) + return 0; + + /* If address doesn't contain slash we assume it host address. */ + p->family = AF_INET; + p->prefixlen = IPV4_MAX_BITLEN; + + return ret; + } + else + { + cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1); + strncpy (cp, str, pnt - str); + *(cp + (pnt - str)) = '\0'; + ret = inet_aton (cp, &p->prefix); + XFREE (MTYPE_TMP, cp); + + /* Get prefix length. */ + plen = (u_char) atoi (++pnt); + if (plen > 32) + return 0; + + p->family = AF_INET; + p->prefixlen = plen; + } + + return ret; +} + +/* Convert masklen into IP address's netmask. */ +void +masklen2ip (int masklen, struct in_addr *netmask) +{ + u_char *pnt; + int bit; + int offset; + + memset (netmask, 0, sizeof (struct in_addr)); + pnt = (unsigned char *) netmask; + + offset = masklen / 8; + bit = masklen % 8; + + while (offset--) + *pnt++ = 0xff; + + if (bit) + *pnt = maskbit[bit]; +} + +/* Convert IP address's netmask into integer. We assume netmask is + sequential one. Argument netmask should be network byte order. */ +u_char +ip_masklen (struct in_addr netmask) +{ + u_char len; + u_char *pnt; + u_char *end; + u_char val; + + len = 0; + pnt = (u_char *) &netmask; + end = pnt + 4; + + while ((*pnt == 0xff) && pnt < end) + { + len+= 8; + pnt++; + } + + if (pnt < end) + { + val = *pnt; + while (val) + { + len++; + val <<= 1; + } + } + return len; +} + +/* Apply mask to IPv4 prefix. */ +void +apply_mask_ipv4 (struct prefix_ipv4 *p) +{ + u_char *pnt; + int index; + int offset; + + index = p->prefixlen / 8; + + if (index < 4) + { + pnt = (u_char *) &p->prefix; + offset = p->prefixlen % 8; + + pnt[index] &= maskbit[offset]; + index++; + + while (index < 4) + pnt[index++] = 0; + } +} + +/* If prefix is 0.0.0.0/0 then return 1 else return 0. */ +int +prefix_ipv4_any (struct prefix_ipv4 *p) +{ + return (p->prefix.s_addr == 0 && p->prefixlen == 0); +} + +#ifdef HAVE_IPV6 + +/* Allocate a new ip version 6 route */ +struct prefix_ipv6 * +prefix_ipv6_new () +{ + struct prefix_ipv6 *p; + + p = XCALLOC (MTYPE_PREFIX_IPV6, sizeof (struct prefix_ipv6)); + p->family = AF_INET6; + return p; +} + +/* Free prefix for IPv6. */ +void +prefix_ipv6_free (struct prefix_ipv6 *p) +{ + XFREE (MTYPE_PREFIX_IPV6, p); +} + +/* If given string is valid return pin6 else return NULL */ +int +str2prefix_ipv6 (char *str, struct prefix_ipv6 *p) +{ + char *pnt; + char *cp; + int ret; + + pnt = strchr (str, '/'); + + /* If string doesn't contain `/' treat it as host route. */ + if (pnt == NULL) + { + ret = inet_pton (AF_INET6, str, &p->prefix); + if (ret != 1) + return 0; + p->prefixlen = IPV6_MAX_BITLEN; + } + else + { + int plen; + + cp = XMALLOC (0, (pnt - str) + 1); + strncpy (cp, str, pnt - str); + *(cp + (pnt - str)) = '\0'; + ret = inet_pton (AF_INET6, cp, &p->prefix); + free (cp); + if (ret != 1) + return 0; + plen = (u_char) atoi (++pnt); + if (plen > 128) + return 0; + p->prefixlen = plen; + } + p->family = AF_INET6; + + return ret; +} + +/* Convert struct in6_addr netmask into integer. */ +int +ip6_masklen (struct in6_addr netmask) +{ + int len = 0; + unsigned char val; + unsigned char *pnt; + + pnt = (unsigned char *) & netmask; + + while ((*pnt == 0xff) && len < 128) + { + len += 8; + pnt++; + } + + if (len < 128) + { + val = *pnt; + while (val) + { + len++; + val <<= 1; + } + } + return len; +} + +void +masklen2ip6 (int masklen, struct in6_addr *netmask) +{ + unsigned char *pnt; + int bit; + int offset; + + memset (netmask, 0, sizeof (struct in6_addr)); + pnt = (unsigned char *) netmask; + + offset = masklen / 8; + bit = masklen % 8; + + while (offset--) + *pnt++ = 0xff; + + if (bit) + *pnt = maskbit[bit]; +} + +void +apply_mask_ipv6 (struct prefix_ipv6 *p) +{ + u_char *pnt; + int index; + int offset; + + index = p->prefixlen / 8; + + if (index < 16) + { + pnt = (u_char *) &p->prefix; + offset = p->prefixlen % 8; + + pnt[index] &= maskbit[offset]; + index++; + + while (index < 16) + pnt[index++] = 0; + } +} + +void +str2in6_addr (char *str, struct in6_addr *addr) +{ + int i; + unsigned int x; + + /* %x must point to unsinged int */ + for (i = 0; i < 16; i++) + { + sscanf (str + (i * 2), "%02x", &x); + addr->s6_addr[i] = x & 0xff; + } +} +#endif /* HAVE_IPV6 */ + +void +apply_mask (struct prefix *p) +{ + switch (p->family) + { + case AF_INET: + apply_mask_ipv4 ((struct prefix_ipv4 *)p); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + apply_mask_ipv6 ((struct prefix_ipv6 *)p); + break; +#endif /* HAVE_IPV6 */ + default: + break; + } + return; +} + +/* Utility function of convert between struct prefix <=> union sockunion */ +struct prefix * +sockunion2prefix (union sockunion *dest, + union sockunion *mask) +{ + if (dest->sa.sa_family == AF_INET) + { + struct prefix_ipv4 *p; + + p = prefix_ipv4_new (); + p->family = AF_INET; + p->prefix = dest->sin.sin_addr; + p->prefixlen = ip_masklen (mask->sin.sin_addr); + return (struct prefix *) p; + } +#ifdef HAVE_IPV6 + if (dest->sa.sa_family == AF_INET6) + { + struct prefix_ipv6 *p; + + p = prefix_ipv6_new (); + p->family = AF_INET6; + p->prefixlen = ip6_masklen (mask->sin6.sin6_addr); + memcpy (&p->prefix, &dest->sin6.sin6_addr, sizeof (struct in6_addr)); + return (struct prefix *) p; + } +#endif /* HAVE_IPV6 */ + return NULL; +} + +/* Utility function of convert between struct prefix <=> union sockunion */ +struct prefix * +sockunion2hostprefix (union sockunion *su) +{ + if (su->sa.sa_family == AF_INET) + { + struct prefix_ipv4 *p; + + p = prefix_ipv4_new (); + p->family = AF_INET; + p->prefix = su->sin.sin_addr; + p->prefixlen = IPV4_MAX_BITLEN; + return (struct prefix *) p; + } +#ifdef HAVE_IPV6 + if (su->sa.sa_family == AF_INET6) + { + struct prefix_ipv6 *p; + + p = prefix_ipv6_new (); + p->family = AF_INET6; + p->prefixlen = IPV6_MAX_BITLEN; + memcpy (&p->prefix, &su->sin6.sin6_addr, sizeof (struct in6_addr)); + return (struct prefix *) p; + } +#endif /* HAVE_IPV6 */ + return NULL; +} + +int +prefix_blen (struct prefix *p) +{ + switch (p->family) + { + case AF_INET: + return IPV4_MAX_BYTELEN; + break; +#ifdef HAVE_IPV6 + case AF_INET6: + return IPV6_MAX_BYTELEN; + break; +#endif /* HAVE_IPV6 */ + } + return 0; +} + +/* Generic function for conversion string to struct prefix. */ +int +str2prefix (char *str, struct prefix *p) +{ + int ret; + + /* First we try to convert string to struct prefix_ipv4. */ + ret = str2prefix_ipv4 (str, (struct prefix_ipv4 *) p); + if (ret) + return ret; + +#ifdef HAVE_IPV6 + /* Next we try to convert string to struct prefix_ipv6. */ + ret = str2prefix_ipv6 (str, (struct prefix_ipv6 *) p); + if (ret) + return ret; +#endif /* HAVE_IPV6 */ + + return 0; +} + +int +prefix2str (struct prefix *p, char *str, int size) +{ + char buf[BUFSIZ]; + + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ); + snprintf (str, size, "%s/%d", buf, p->prefixlen); + return 0; +} + +struct prefix * +prefix_new () +{ + struct prefix *p; + + p = XCALLOC (MTYPE_PREFIX, sizeof *p); + return p; +} + +/* Free prefix structure. */ +void +prefix_free (struct prefix *p) +{ + XFREE (MTYPE_PREFIX, p); +} + +/* Utility function. Check the string only contains digit + character. */ +int +all_digit (char *str) +{ + for (; *str != '\0'; str++) + if (!isdigit ((int) *str)) + return 0; + return 1; +} + +/* Utility function to convert ipv4 prefixes to Classful prefixes */ +void apply_classful_mask_ipv4 (struct prefix_ipv4 *p) +{ + + u_int32_t destination; + + destination = ntohl (p->prefix.s_addr); + + if (p->prefixlen == 32); + /* do nothing for host routes */ + else if (IN_CLASSC (destination)) + { + p->prefixlen=24; + apply_mask_ipv4(p); + } + else if (IN_CLASSB(destination)) + { + p->prefixlen=16; + apply_mask_ipv4(p); + } + else + { + p->prefixlen=8; + apply_mask_ipv4(p); + } +} + +/* Utility function to convert ipv4 netmask to prefixes + ex.) "1.1.0.0" "255.255.0.0" => "1.1.0.0/16" + ex.) "1.0.0.0" NULL => "1.0.0.0/8" */ +int +netmask_str2prefix_str (char *net_str, char *mask_str, char *prefix_str) +{ + struct in_addr network; + struct in_addr mask; + u_char prefixlen; + u_int32_t destination; + int ret; + + ret = inet_aton (net_str, &network); + if (! ret) + return 0; + + if (mask_str) + { + ret = inet_aton (mask_str, &mask); + if (! ret) + return 0; + + prefixlen = ip_masklen (mask); + } + else + { + destination = ntohl (network.s_addr); + + if (network.s_addr == 0) + prefixlen = 0; + else if (IN_CLASSC (destination)) + prefixlen = 24; + else if (IN_CLASSB (destination)) + prefixlen = 16; + else if (IN_CLASSA (destination)) + prefixlen = 8; + else + return 0; + } + + sprintf (prefix_str, "%s/%d", net_str, prefixlen); + + return 1; +} + diff --git a/lib/prefix.h b/lib/prefix.h new file mode 100644 index 0000000..7d7cde6 --- /dev/null +++ b/lib/prefix.h @@ -0,0 +1,161 @@ +/* + * Prefix structure. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_PREFIX_H +#define _ZEBRA_PREFIX_H + +/* IPv4 and IPv6 unified prefix structure. */ +struct prefix +{ + u_char family; + u_char prefixlen; + union + { + u_char prefix; + struct in_addr prefix4; +#ifdef HAVE_IPV6 + struct in6_addr prefix6; +#endif /* HAVE_IPV6 */ + struct + { + struct in_addr id; + struct in_addr adv_router; + } lp; + u_char val[8]; + } u __attribute__ ((aligned (8))); +}; + +/* IPv4 prefix structure. */ +struct prefix_ipv4 +{ + u_char family; + u_char prefixlen; + struct in_addr prefix __attribute__ ((aligned (8))); +}; + +/* IPv6 prefix structure. */ +#ifdef HAVE_IPV6 +struct prefix_ipv6 +{ + u_char family; + u_char prefixlen; + struct in6_addr prefix __attribute__ ((aligned (8))); +}; +#endif /* HAVE_IPV6 */ + +struct prefix_ls +{ + u_char family; + u_char prefixlen; + struct in_addr id __attribute__ ((aligned (8))); + struct in_addr adv_router; +}; + +/* Prefix for routing distinguisher. */ +struct prefix_rd +{ + u_char family; + u_char prefixlen; + u_char val[8] __attribute__ ((aligned (8))); +}; + +#ifndef INET_ADDRSTRLEN +#define INET_ADDRSTRLEN 16 +#endif /* INET_ADDRSTRLEN */ + +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 46 +#endif /* INET6_ADDRSTRLEN */ + +#ifndef INET6_BUFSIZ +#define INET6_BUFSIZ 51 +#endif /* INET6_BUFSIZ */ + +/* Max bit/byte length of IPv4 address. */ +#define IPV4_MAX_BYTELEN 4 +#define IPV4_MAX_BITLEN 32 +#define IPV4_MAX_PREFIXLEN 32 +#define IPV4_ADDR_CMP(D,S) memcmp ((D), (S), IPV4_MAX_BYTELEN) +#define IPV4_ADDR_SAME(D,S) (memcmp ((D), (S), IPV4_MAX_BYTELEN) == 0) +#define IPV4_ADDR_COPY(D,S) memcpy ((D), (S), IPV4_MAX_BYTELEN) + +#define IPV4_NET0(a) ((((u_int32_t) (a)) & 0xff000000) == 0x00000000) +#define IPV4_NET127(a) ((((u_int32_t) (a)) & 0xff000000) == 0x7f000000) + +/* Max bit/byte length of IPv6 address. */ +#define IPV6_MAX_BYTELEN 16 +#define IPV6_MAX_BITLEN 128 +#define IPV6_MAX_PREFIXLEN 128 +#define IPV6_ADDR_CMP(D,S) memcmp ((D), (S), IPV6_MAX_BYTELEN) +#define IPV6_ADDR_SAME(D,S) (memcmp ((D), (S), IPV6_MAX_BYTELEN) == 0) +#define IPV6_ADDR_COPY(D,S) memcpy ((D), (S), IPV6_MAX_BYTELEN) + +/* Count prefix size from mask length */ +#define PSIZE(a) (((a) + 7) / (8)) + +/* Prefix's family member. */ +#define PREFIX_FAMILY(p) ((p)->family) + +/* Prototypes. */ +int afi2family (int); +int family2afi (int); + +int prefix2str (struct prefix *, char *, int); +int str2prefix (char *, struct prefix *); +struct prefix *prefix_new (); +void prefix_free (struct prefix *p); + +struct prefix_ipv4 *prefix_ipv4_new (); +void prefix_ipv4_free (); +int str2prefix_ipv4 (char *, struct prefix_ipv4 *); +void apply_mask_ipv4 (struct prefix_ipv4 *); +int prefix_blen (struct prefix *); +u_char ip_masklen (struct in_addr); +int prefix_ipv4_any (struct prefix_ipv4 *); +void masklen2ip (int, struct in_addr *); +void apply_classful_mask_ipv4 (struct prefix_ipv4 *); + +char *prefix_family_str (struct prefix *p); +struct prefix *sockunion2prefix (); +struct prefix *sockunion2hostprefix (); + +#ifdef HAVE_IPV6 +struct prefix_ipv6 *prefix_ipv6_new (); +void prefix_ipv6_free (); +struct prefix *str2routev6 (char *); +int str2prefix_ipv6 (char *str, struct prefix_ipv6 *p); +void apply_mask_ipv6 (struct prefix_ipv6 *p); +void str2in6_addr (char *str, struct in6_addr *addr); +void masklen2ip6 (int masklen, struct in6_addr *netmask); +int ip6_masklen (struct in6_addr netmask); +#endif /* HAVE_IPV6 */ + +void apply_mask (struct prefix *); +int prefix_match (struct prefix *n, struct prefix *p); +int prefix_same (struct prefix *, struct prefix *); +int prefix_cmp (struct prefix *, struct prefix *); +void prefix_copy (struct prefix *, struct prefix *); + +int all_digit (char *); +int netmask_str2prefix_str (char *, char *, char *); + +#endif /* _ZEBRA_PREFIX_H */ diff --git a/lib/print_version.c b/lib/print_version.c new file mode 100644 index 0000000..6b4064d --- /dev/null +++ b/lib/print_version.c @@ -0,0 +1,31 @@ +/* Print version function. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "version.h" + +void +print_version (char *progname) +{ + printf ("%s version %s (%s)\n", progname, ZEBRA_VERSION, host_name); + printf ("Copyright 1996-2001, Kunihiro Ishiguro\n"); +} diff --git a/lib/regex-gnu.h b/lib/regex-gnu.h new file mode 100644 index 0000000..d88ab92 --- /dev/null +++ b/lib/regex-gnu.h @@ -0,0 +1,542 @@ +/* Definitions for data structures and routines for the regular + expression library, version 0.12. + Copyright (C) 1985,89,90,91,92,93,95,96,97,98 Free Software Foundation, Inc. + + This file is part of the GNU C Library. Its master source is NOT part of + the C library, however. The master source lives in /gd/gnu/lib. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _REGEX_H +#define _REGEX_H 1 + +/* Allow the use in C++ code. */ +#ifdef __cplusplus +extern "C" { +#endif + +/* POSIX says that must be included (by the caller) before + . */ + +#if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS +/* VMS doesn't have `size_t' in , even though POSIX says it + should be there. */ +# include +#endif + +/* The following two types have to be signed and unsigned integer type + wide enough to hold a value of a pointer. For most ANSI compilers + ptrdiff_t and size_t should be likely OK. Still size of these two + types is 2 for Microsoft C. Ugh... */ +typedef long int s_reg_t; +typedef unsigned long int active_reg_t; + +/* The following bits are used to determine the regexp syntax we + recognize. The set/not-set meanings are chosen so that Emacs syntax + remains the value 0. The bits are given in alphabetical order, and + the definitions shifted by one from the previous bit; thus, when we + add or remove a bit, only one other definition need change. */ +typedef unsigned long int reg_syntax_t; + +/* If this bit is not set, then \ inside a bracket expression is literal. + If set, then such a \ quotes the following character. */ +#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) + +/* If this bit is not set, then + and ? are operators, and \+ and \? are + literals. + If set, then \+ and \? are operators and + and ? are literals. */ +#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) + +/* If this bit is set, then character classes are supported. They are: + [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], + [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. + If not set, then character classes are not supported. */ +#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) + +/* If this bit is set, then ^ and $ are always anchors (outside bracket + expressions, of course). + If this bit is not set, then it depends: + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. + + This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because + POSIX draft 11.2 says that * etc. in leading positions is undefined. + We already implemented a previous draft which made those constructs + invalid, though, so we haven't changed the code back. */ +#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) + +/* If this bit is set, then special characters are always special + regardless of where they are in the pattern. + If this bit is not set, then special characters are special only in + some contexts; otherwise they are ordinary. Specifically, + * + ? and intervals are only special when not after the beginning, + open-group, or alternation operator. */ +#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) + +/* If this bit is set, then *, +, ?, and { cannot be first in an re or + immediately after an alternation or begin-group operator. */ +#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) + +/* If this bit is set, then . matches newline. + If not set, then it doesn't. */ +#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) + +/* If this bit is set, then . doesn't match NUL. + If not set, then it does. */ +#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) + +/* If this bit is set, nonmatching lists [^...] do not match newline. + If not set, they do. */ +#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) + +/* If this bit is set, either \{...\} or {...} defines an + interval, depending on RE_NO_BK_BRACES. + If not set, \{, \}, {, and } are literals. */ +#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) + +/* If this bit is set, +, ? and | aren't recognized as operators. + If not set, they are. */ +#define RE_LIMITED_OPS (RE_INTERVALS << 1) + +/* If this bit is set, newline is an alternation operator. + If not set, newline is literal. */ +#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) + +/* If this bit is set, then `{...}' defines an interval, and \{ and \} + are literals. + If not set, then `\{...\}' defines an interval. */ +#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) + +/* If this bit is set, (...) defines a group, and \( and \) are literals. + If not set, \(...\) defines a group, and ( and ) are literals. */ +#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) + +/* If this bit is set, then \ matches . + If not set, then \ is a back-reference. */ +#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) + +/* If this bit is set, then | is an alternation operator, and \| is literal. + If not set, then \| is an alternation operator, and | is literal. */ +#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) + +/* If this bit is set, then an ending range point collating higher + than the starting range point, as in [z-a], is invalid. + If not set, then when ending range point collates higher than the + starting range point, the range is ignored. */ +#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) + +/* If this bit is set, then an unmatched ) is ordinary. + If not set, then an unmatched ) is invalid. */ +#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) + +/* If this bit is set, succeed as soon as we match the whole pattern, + without further backtracking. */ +#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) + +/* If this bit is set, do not process the GNU regex operators. + If not set, then the GNU regex operators are recognized. */ +#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) + +/* If this bit is set, turn on internal regex debugging. + If not set, and debugging was on, turn it off. + This only works if regex.c is compiled -DDEBUG. + We define this bit always, so that all that's needed to turn on + debugging is to recompile regex.c; the calling code can always have + this bit set, and it won't affect anything in the normal case. */ +#define RE_DEBUG (RE_NO_GNU_OPS << 1) + +/* This global variable defines the particular regexp syntax to use (for + some interfaces). When a regexp is compiled, the syntax used is + stored in the pattern buffer, so changing this does not affect + already-compiled regexps. */ +extern reg_syntax_t re_syntax_options; + +/* Define combinations of the above bits for the standard possibilities. + (The [[[ comments delimit what gets put into the Texinfo file, so + don't delete them!) */ +/* [[[begin syntaxes]]] */ +#define RE_SYNTAX_EMACS 0 + +#define RE_SYNTAX_AWK \ + (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ + | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ + | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) + +#define RE_SYNTAX_GNU_AWK \ + ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \ + & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS)) + +#define RE_SYNTAX_POSIX_AWK \ + (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ + | RE_INTERVALS | RE_NO_GNU_OPS) + +#define RE_SYNTAX_GREP \ + (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ + | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ + | RE_NEWLINE_ALT) + +#define RE_SYNTAX_EGREP \ + (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ + | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ + | RE_NO_BK_VBAR) + +#define RE_SYNTAX_POSIX_EGREP \ + (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) + +/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ +#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC + +#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC + +/* Syntax bits common to both basic and extended POSIX regex syntax. */ +#define _RE_SYNTAX_POSIX_COMMON \ + (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ + | RE_INTERVALS | RE_NO_EMPTY_RANGES) + +#define RE_SYNTAX_POSIX_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) + +/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes + RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this + isn't minimal, since other operators, such as \`, aren't disabled. */ +#define RE_SYNTAX_POSIX_MINIMAL_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) + +#define RE_SYNTAX_POSIX_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ + | RE_UNMATCHED_RIGHT_PAREN_ORD) + +/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS + replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */ +#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) +/* [[[end syntaxes]]] */ + +/* Maximum number of duplicates an interval can allow. Some systems + (erroneously) define this in other header files, but we want our + value, so remove any previous define. */ +#ifdef RE_DUP_MAX +# undef RE_DUP_MAX +#endif +/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */ +#define RE_DUP_MAX (0x7fff) + + +/* POSIX `cflags' bits (i.e., information for `regcomp'). */ + +/* If this bit is set, then use extended regular expression syntax. + If not set, then use basic regular expression syntax. */ +#define REG_EXTENDED 1 + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +#define REG_ICASE (REG_EXTENDED << 1) + +/* If this bit is set, then anchors do not match at newline + characters in the string. + If not set, then anchors do match at newlines. */ +#define REG_NEWLINE (REG_ICASE << 1) + +/* If this bit is set, then report only success or fail in regexec. + If not set, then returns differ between not matching and errors. */ +#define REG_NOSUB (REG_NEWLINE << 1) + + +/* POSIX `eflags' bits (i.e., information for regexec). */ + +/* If this bit is set, then the beginning-of-line operator doesn't match + the beginning of the string (presumably because it's not the + beginning of a line). + If not set, then the beginning-of-line operator does match the + beginning of the string. */ +#define REG_NOTBOL 1 + +/* Like REG_NOTBOL, except for the end-of-line. */ +#define REG_NOTEOL (1 << 1) + + +/* If any error codes are removed, changed, or added, update the + `re_error_msg' table in regex.c. */ +typedef enum +{ +#ifdef _XOPEN_SOURCE + REG_ENOSYS = -1, /* This will never happen for this implementation. */ +#endif + + REG_NOERROR = 0, /* Success. */ + REG_NOMATCH, /* Didn't find a match (for regexec). */ + + /* POSIX regcomp return error codes. (In the order listed in the + standard.) */ + REG_BADPAT, /* Invalid pattern. */ + REG_ECOLLATE, /* Not implemented. */ + REG_ECTYPE, /* Invalid character class name. */ + REG_EESCAPE, /* Trailing backslash. */ + REG_ESUBREG, /* Invalid back reference. */ + REG_EBRACK, /* Unmatched left bracket. */ + REG_EPAREN, /* Parenthesis imbalance. */ + REG_EBRACE, /* Unmatched \{. */ + REG_BADBR, /* Invalid contents of \{\}. */ + REG_ERANGE, /* Invalid range end. */ + REG_ESPACE, /* Ran out of memory. */ + REG_BADRPT, /* No preceding re for repetition op. */ + + /* Error codes we've added. */ + REG_EEND, /* Premature end. */ + REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ + REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ +} reg_errcode_t; + +/* This data structure represents a compiled pattern. Before calling + the pattern compiler, the fields `buffer', `allocated', `fastmap', + `translate', and `no_sub' can be set. After the pattern has been + compiled, the `re_nsub' field is available. All other fields are + private to the regex routines. */ + +#ifndef RE_TRANSLATE_TYPE +# define RE_TRANSLATE_TYPE char * +#endif + +struct re_pattern_buffer +{ +/* [[[begin pattern_buffer]]] */ + /* Space that holds the compiled pattern. It is declared as + `unsigned char *' because its elements are + sometimes used as array indexes. */ + unsigned char *buffer; + + /* Number of bytes to which `buffer' points. */ + unsigned long int allocated; + + /* Number of bytes actually used in `buffer'. */ + unsigned long int used; + + /* Syntax setting with which the pattern was compiled. */ + reg_syntax_t syntax; + + /* Pointer to a fastmap, if any, otherwise zero. re_search uses + the fastmap, if there is one, to skip over impossible + starting points for matches. */ + char *fastmap; + + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation + is applied to a pattern when it is compiled and to a string + when it is matched. */ + RE_TRANSLATE_TYPE translate; + + /* Number of subexpressions found by the compiler. */ + size_t re_nsub; + + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in `re_search_2', to see + whether or not we should use the fastmap, so we don't set + this absolutely perfectly; see `re_compile_fastmap' (the + `duplicate' case). */ + unsigned can_be_null : 1; + + /* If REGS_UNALLOCATED, allocate space in the `regs' structure + for `max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ +#define REGS_UNALLOCATED 0 +#define REGS_REALLOCATE 1 +#define REGS_FIXED 2 + unsigned regs_allocated : 2; + + /* Set to zero when `regex_compile' compiles a pattern; set to one + by `re_compile_fastmap' if it updates the fastmap. */ + unsigned fastmap_accurate : 1; + + /* If set, `re_match_2' does not return information about + subexpressions. */ + unsigned no_sub : 1; + + /* If set, a beginning-of-line anchor doesn't match at the + beginning of the string. */ + unsigned not_bol : 1; + + /* Similarly for an end-of-line anchor. */ + unsigned not_eol : 1; + + /* If true, an anchor at a newline matches. */ + unsigned newline_anchor : 1; + +/* [[[end pattern_buffer]]] */ +}; + +typedef struct re_pattern_buffer regex_t; + +/* Type for byte offsets within the string. POSIX mandates this. */ +typedef int regoff_t; + + +/* This is the structure we store register match data in. See + regex.texinfo for a full description of what registers match. */ +struct re_registers +{ + unsigned num_regs; + regoff_t *start; + regoff_t *end; +}; + + +/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, + `re_match_2' returns information about at least this many registers + the first time a `regs' structure is passed. */ +#ifndef RE_NREGS +# define RE_NREGS 30 +#endif + + +/* POSIX specification for registers. Aside from the different names than + `re_registers', POSIX uses an array of structures, instead of a + structure of arrays. */ +typedef struct +{ + regoff_t rm_so; /* Byte offset from string's start to substring's start. */ + regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ +} regmatch_t; + +/* Declarations for routines. */ + +/* To avoid duplicating every routine declaration -- once with a + prototype (if we are ANSI), and once without (if we aren't) -- we + use the following macro to declare argument types. This + unfortunately clutters up the declarations a bit, but I think it's + worth it. */ + +#if __STDC__ + +# define _RE_ARGS(args) args + +#else /* not __STDC__ */ + +# define _RE_ARGS(args) () + +#endif /* not __STDC__ */ + +/* Sets the current default syntax to SYNTAX, and return the old syntax. + You can also simply assign to the `re_syntax_options' variable. */ +extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); + +/* Compile the regular expression PATTERN, with length LENGTH + and syntax given by the global `re_syntax_options', into the buffer + BUFFER. Return NULL if successful, and an error string if not. */ +extern const char *re_compile_pattern + _RE_ARGS ((const char *pattern, size_t length, + struct re_pattern_buffer *buffer)); + + +/* Compile a fastmap for the compiled pattern in BUFFER; used to + accelerate searches. Return 0 if successful and -2 if was an + internal error. */ +extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); + + +/* Search in the string STRING (with length LENGTH) for the pattern + compiled into BUFFER. Start searching at position START, for RANGE + characters. Return the starting position of the match, -1 for no + match, or -2 for an internal error. Also return register + information in REGS (if REGS and BUFFER->no_sub are nonzero). */ +extern int re_search + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, int range, struct re_registers *regs)); + + +/* Like `re_search', but search in the concatenation of STRING1 and + STRING2. Also, stop searching at index START + STOP. */ +extern int re_search_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, int range, struct re_registers *regs, int stop)); + + +/* Like `re_search', but return how many characters in STRING the regexp + in BUFFER matched, starting at position START. */ +extern int re_match + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, struct re_registers *regs)); + + +/* Relates to `re_match' as `re_search_2' relates to `re_search'. */ +extern int re_match_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, struct re_registers *regs, int stop)); + + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using BUFFER and REGS will use this memory + for recording register information. STARTS and ENDS must be + allocated with malloc, and must each be at least `NUM_REGS * sizeof + (regoff_t)' bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ +extern void re_set_registers + _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, + unsigned num_regs, regoff_t *starts, regoff_t *ends)); + +#if defined _REGEX_RE_COMP || defined _LIBC +# ifndef _CRAY +/* 4.2 bsd compatibility. */ +extern char *re_comp _RE_ARGS ((const char *)); +extern int re_exec _RE_ARGS ((const char *)); +# endif +#endif + +/* POSIX compatibility. */ +extern int regcomp _RE_ARGS ((regex_t *__preg, const char *__pattern, + int __cflags)); + +extern int regexec _RE_ARGS ((const regex_t *__preg, + const char *__string, size_t __nmatch, + regmatch_t __pmatch[], int __eflags)); + +extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg, + char *__errbuf, size_t __errbuf_size)); + +extern void regfree _RE_ARGS ((regex_t *__preg)); + + +#ifdef __cplusplus +} +#endif /* C++ */ + +#endif /* regex.h */ + +/* +Local variables: +make-backup-files: t +version-control: t +trim-versions-without-asking: nil +End: +*/ diff --git a/lib/regex.c b/lib/regex.c new file mode 100644 index 0000000..8c7acd5 --- /dev/null +++ b/lib/regex.c @@ -0,0 +1,5891 @@ +/* Extended regular expression matching and search library, + version 0.12. + (Implements POSIX draft P1003.2/D11.2, except for some of the + internationalization features.) + Copyright (C) 1993, 94, 95, 96, 97, 98, 99 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* AIX requires this to be the first thing in the file. */ +#if defined _AIX && !defined REGEX_MALLOC + #pragma alloca +#endif + +#undef _GNU_SOURCE +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifndef PARAMS +# if defined __GNUC__ || (defined __STDC__ && __STDC__) +# define PARAMS(args) args +# else +# define PARAMS(args) () +# endif /* GCC. */ +#endif /* Not PARAMS. */ + +#if defined STDC_HEADERS && !defined emacs +# include +#else +/* We need this for `regex.h', and perhaps for the Emacs include files. */ +# include +#endif + +#define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC) + +/* For platform which support the ISO C amendement 1 functionality we + support user defined character classes. */ +#if defined _LIBC || WIDE_CHAR_SUPPORT +/* Solaris 2.5 has a bug: must be included before . */ +# include +# include +#endif + +#ifdef _LIBC +/* We have to keep the namespace clean. */ +# define regfree(preg) __regfree (preg) +# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) +# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) +# define regerror(errcode, preg, errbuf, errbuf_size) \ + __regerror(errcode, preg, errbuf, errbuf_size) +# define re_set_registers(bu, re, nu, st, en) \ + __re_set_registers (bu, re, nu, st, en) +# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ + __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) +# define re_match(bufp, string, size, pos, regs) \ + __re_match (bufp, string, size, pos, regs) +# define re_search(bufp, string, size, startpos, range, regs) \ + __re_search (bufp, string, size, startpos, range, regs) +# define re_compile_pattern(pattern, length, bufp) \ + __re_compile_pattern (pattern, length, bufp) +# define re_set_syntax(syntax) __re_set_syntax (syntax) +# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ + __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) +# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) + +#define btowc __btowc +#endif + +/* This is for other GNU distributions with internationalized messages. */ +#if HAVE_LIBINTL_H || defined _LIBC +# include +#else +# define gettext(msgid) (msgid) +#endif + +#ifndef gettext_noop +/* This define is so xgettext can find the internationalizable + strings. */ +# define gettext_noop(String) String +#endif + +/* The `emacs' switch turns on certain matching commands + that make sense only in Emacs. */ +#ifdef emacs + +# include "lisp.h" +# include "buffer.h" +# include "syntax.h" + +#else /* not emacs */ + +/* If we are not linking with Emacs proper, + we can't use the relocating allocator + even if config.h says that we can. */ +# undef REL_ALLOC + +# if defined STDC_HEADERS || defined _LIBC +# include +# else +char *malloc (); +char *realloc (); +# endif + +/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow. + If nothing else has been done, use the method below. */ +# ifdef INHIBIT_STRING_HEADER +# if !(defined HAVE_BZERO && defined HAVE_BCOPY) +# if !defined bzero && !defined bcopy +# undef INHIBIT_STRING_HEADER +# endif +# endif +# endif + +/* This is the normal way of making sure we have a bcopy and a bzero. + This is used in most programs--a few other programs avoid this + by defining INHIBIT_STRING_HEADER. */ +# ifndef INHIBIT_STRING_HEADER +# if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC +# include +# ifndef bzero +# ifndef _LIBC +# define bzero(s, n) (memset (s, '\0', n), (s)) +# else +# define bzero(s, n) __bzero (s, n) +# endif +# endif +# else +# include +# ifndef memcmp +# define memcmp(s1, s2, n) bcmp (s1, s2, n) +# endif +# ifndef memcpy +# define memcpy(d, s, n) (bcopy (s, d, n), (d)) +# endif +# endif +# endif + +/* Define the syntax stuff for \<, \>, etc. */ + +/* This must be nonzero for the wordchar and notwordchar pattern + commands in re_match_2. */ +# ifndef Sword +# define Sword 1 +# endif + +# ifdef SWITCH_ENUM_BUG +# define SWITCH_ENUM_CAST(x) ((int)(x)) +# else +# define SWITCH_ENUM_CAST(x) (x) +# endif + +/* How many characters in the character set. */ +# define CHAR_SET_SIZE 256 + +# ifdef SYNTAX_TABLE + +extern char *re_syntax_table; + +# else /* not SYNTAX_TABLE */ + +static char re_syntax_table[CHAR_SET_SIZE]; + +static void +init_syntax_once () +{ + register int c; + static int done; + + if (done) + return; + + bzero (re_syntax_table, sizeof re_syntax_table); + + for (c = 'a'; c <= 'z'; c++) + re_syntax_table[c] = Sword; + + for (c = 'A'; c <= 'Z'; c++) + re_syntax_table[c] = Sword; + + for (c = '0'; c <= '9'; c++) + re_syntax_table[c] = Sword; + + re_syntax_table['_'] = Sword; + + done = 1; +} + +# endif /* not SYNTAX_TABLE */ + +# define SYNTAX(c) re_syntax_table[c] + +#endif /* not emacs */ + +/* Get the interface, including the syntax bits. */ +#include + +/* isalpha etc. are used for the character classes. */ +#include + +/* Jim Meyering writes: + + "... Some ctype macros are valid only for character codes that + isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when + using /bin/cc or gcc but without giving an ansi option). So, all + ctype uses should be through macros like ISPRINT... If + STDC_HEADERS is defined, then autoconf has verified that the ctype + macros don't need to be guarded with references to isascii. ... + Defining isascii to 1 should let any compiler worth its salt + eliminate the && through constant folding." + Solaris defines some of these symbols so we must undefine them first. */ + +#undef ISASCII +#if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII) +# define ISASCII(c) 1 +#else +# define ISASCII(c) isascii(c) +#endif + +#ifdef isblank +# define ISBLANK(c) (ISASCII (c) && isblank (c)) +#else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#endif +#ifdef isgraph +# define ISGRAPH(c) (ISASCII (c) && isgraph (c)) +#else +# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) +#endif + +#undef ISPRINT +#define ISPRINT(c) (ISASCII (c) && isprint (c)) +#define ISDIGIT(c) (ISASCII (c) && isdigit (c)) +#define ISALNUM(c) (ISASCII (c) && isalnum (c)) +#define ISALPHA(c) (ISASCII (c) && isalpha (c)) +#define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) +#define ISLOWER(c) (ISASCII (c) && islower (c)) +#define ISPUNCT(c) (ISASCII (c) && ispunct (c)) +#define ISSPACE(c) (ISASCII (c) && isspace (c)) +#define ISUPPER(c) (ISASCII (c) && isupper (c)) +#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) + +#ifdef _tolower +# define TOLOWER(c) _tolower(c) +#else +# define TOLOWER(c) tolower(c) +#endif + +#ifndef NULL +# define NULL (void *)0 +#endif + +/* We remove any previous definition of `SIGN_EXTEND_CHAR', + since ours (we hope) works properly with all combinations of + machines, compilers, `char' and `unsigned char' argument types. + (Per Bothner suggested the basic approach.) */ +#undef SIGN_EXTEND_CHAR +#if __STDC__ +# define SIGN_EXTEND_CHAR(c) ((signed char) (c)) +#else /* not __STDC__ */ +/* As in Harbison and Steele. */ +# define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) +#endif + +/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we + use `alloca' instead of `malloc'. This is because using malloc in + re_search* or re_match* could cause memory leaks when C-g is used in + Emacs; also, malloc is slower and causes storage fragmentation. On + the other hand, malloc is more portable, and easier to debug. + + Because we sometimes use alloca, some routines have to be macros, + not functions -- `alloca'-allocated space disappears at the end of the + function it is called in. */ + +#ifdef REGEX_MALLOC + +# define REGEX_ALLOCATE malloc +# define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) +# define REGEX_FREE free + +#else /* not REGEX_MALLOC */ + +/* Emacs already defines alloca, sometimes. */ +# ifndef alloca + +/* Make alloca work the best possible way. */ +# ifdef __GNUC__ +# define alloca __builtin_alloca +# else /* not __GNUC__ */ +# if HAVE_ALLOCA_H +# include +# endif /* HAVE_ALLOCA_H */ +# endif /* not __GNUC__ */ + +# endif /* not alloca */ + +# define REGEX_ALLOCATE alloca + +/* Assumes a `char *destination' variable. */ +# define REGEX_REALLOCATE(source, osize, nsize) \ + (destination = (char *) alloca (nsize), \ + memcpy (destination, source, osize)) + +/* No need to do anything to free, after alloca. */ +# define REGEX_FREE(arg) ((void)0) /* Do nothing! But inhibit gcc warning. */ + +#endif /* not REGEX_MALLOC */ + +/* Define how to allocate the failure stack. */ + +#if defined REL_ALLOC && defined REGEX_MALLOC + +# define REGEX_ALLOCATE_STACK(size) \ + r_alloc (&failure_stack_ptr, (size)) +# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ + r_re_alloc (&failure_stack_ptr, (nsize)) +# define REGEX_FREE_STACK(ptr) \ + r_alloc_free (&failure_stack_ptr) + +#else /* not using relocating allocator */ + +# ifdef REGEX_MALLOC + +# define REGEX_ALLOCATE_STACK malloc +# define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize) +# define REGEX_FREE_STACK free + +# else /* not REGEX_MALLOC */ + +# define REGEX_ALLOCATE_STACK alloca + +# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ + REGEX_REALLOCATE (source, osize, nsize) +/* No need to explicitly free anything. */ +# define REGEX_FREE_STACK(arg) + +# endif /* not REGEX_MALLOC */ +#endif /* not using relocating allocator */ + + +/* True if `size1' is non-NULL and PTR is pointing anywhere inside + `string1' or just past its end. This works if PTR is NULL, which is + a good thing. */ +#define FIRST_STRING_P(ptr) \ + (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) + +/* (Re)Allocate N items of type T using malloc, or fail. */ +#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) +#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) +#define RETALLOC_IF(addr, n, t) \ + if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t) +#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) + +#define BYTEWIDTH 8 /* In bits. */ + +#define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +#undef MAX +#undef MIN +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +typedef char boolean; +#define false 0 +#define true 1 + +static int re_match_2_internal PARAMS ((struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int pos, + struct re_registers *regs, + int stop)); + +/* These are the command codes that appear in compiled regular + expressions. Some opcodes are followed by argument bytes. A + command code can specify any interpretation whatsoever for its + arguments. Zero bytes may appear in the compiled regular expression. */ + +typedef enum +{ + no_op = 0, + + /* Succeed right away--no more backtracking. */ + succeed, + + /* Followed by one byte giving n, then by n literal bytes. */ + exactn, + + /* Matches any (more or less) character. */ + anychar, + + /* Matches any one char belonging to specified set. First + following byte is number of bitmap bytes. Then come bytes + for a bitmap saying which chars are in. Bits in each byte + are ordered low-bit-first. A character is in the set if its + bit is 1. A character too large to have a bit in the map is + automatically not in the set. */ + charset, + + /* Same parameters as charset, but match any character that is + not one of those specified. */ + charset_not, + + /* Start remembering the text that is matched, for storing in a + register. Followed by one byte with the register number, in + the range 0 to one less than the pattern buffer's re_nsub + field. Then followed by one byte with the number of groups + inner to this one. (This last has to be part of the + start_memory only because we need it in the on_failure_jump + of re_match_2.) */ + start_memory, + + /* Stop remembering the text that is matched and store it in a + memory register. Followed by one byte with the register + number, in the range 0 to one less than `re_nsub' in the + pattern buffer, and one byte with the number of inner groups, + just like `start_memory'. (We need the number of inner + groups here because we don't have any easy way of finding the + corresponding start_memory when we're at a stop_memory.) */ + stop_memory, + + /* Match a duplicate of something remembered. Followed by one + byte containing the register number. */ + duplicate, + + /* Fail unless at beginning of line. */ + begline, + + /* Fail unless at end of line. */ + endline, + + /* Succeeds if at beginning of buffer (if emacs) or at beginning + of string to be matched (if not). */ + begbuf, + + /* Analogously, for end of buffer/string. */ + endbuf, + + /* Followed by two byte relative address to which to jump. */ + jump, + + /* Same as jump, but marks the end of an alternative. */ + jump_past_alt, + + /* Followed by two-byte relative address of place to resume at + in case of failure. */ + on_failure_jump, + + /* Like on_failure_jump, but pushes a placeholder instead of the + current string position when executed. */ + on_failure_keep_string_jump, + + /* Throw away latest failure point and then jump to following + two-byte relative address. */ + pop_failure_jump, + + /* Change to pop_failure_jump if know won't have to backtrack to + match; otherwise change to jump. This is used to jump + back to the beginning of a repeat. If what follows this jump + clearly won't match what the repeat does, such that we can be + sure that there is no use backtracking out of repetitions + already matched, then we change it to a pop_failure_jump. + Followed by two-byte address. */ + maybe_pop_jump, + + /* Jump to following two-byte address, and push a dummy failure + point. This failure point will be thrown away if an attempt + is made to use it for a failure. A `+' construct makes this + before the first repeat. Also used as an intermediary kind + of jump when compiling an alternative. */ + dummy_failure_jump, + + /* Push a dummy failure point and continue. Used at the end of + alternatives. */ + push_dummy_failure, + + /* Followed by two-byte relative address and two-byte number n. + After matching N times, jump to the address upon failure. */ + succeed_n, + + /* Followed by two-byte relative address, and two-byte number n. + Jump to the address N times, then fail. */ + jump_n, + + /* Set the following two-byte relative address to the + subsequent two-byte number. The address *includes* the two + bytes of number. */ + set_number_at, + + wordchar, /* Matches any word-constituent character. */ + notwordchar, /* Matches any char that is not a word-constituent. */ + + wordbeg, /* Succeeds if at word beginning. */ + wordend, /* Succeeds if at word end. */ + + wordbound, /* Succeeds if at a word boundary. */ + notwordbound /* Succeeds if not at a word boundary. */ + +#ifdef emacs + ,before_dot, /* Succeeds if before point. */ + at_dot, /* Succeeds if at point. */ + after_dot, /* Succeeds if after point. */ + + /* Matches any character whose syntax is specified. Followed by + a byte which contains a syntax code, e.g., Sword. */ + syntaxspec, + + /* Matches any character whose syntax is not that specified. */ + notsyntaxspec +#endif /* emacs */ +} re_opcode_t; + +/* Common operations on the compiled pattern. */ + +/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ + +#define STORE_NUMBER(destination, number) \ + do { \ + (destination)[0] = (number) & 0377; \ + (destination)[1] = (number) >> 8; \ + } while (0) + +/* Same as STORE_NUMBER, except increment DESTINATION to + the byte after where the number is stored. Therefore, DESTINATION + must be an lvalue. */ + +#define STORE_NUMBER_AND_INCR(destination, number) \ + do { \ + STORE_NUMBER (destination, number); \ + (destination) += 2; \ + } while (0) + +/* Put into DESTINATION a number stored in two contiguous bytes starting + at SOURCE. */ + +#define EXTRACT_NUMBER(destination, source) \ + do { \ + (destination) = *(source) & 0377; \ + (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \ + } while (0) + +#ifdef DEBUG +static void extract_number _RE_ARGS ((int *dest, unsigned char *source)); +static void +extract_number (dest, source) + int *dest; + unsigned char *source; +{ + int temp = SIGN_EXTEND_CHAR (*(source + 1)); + *dest = *source & 0377; + *dest += temp << 8; +} + +# ifndef EXTRACT_MACROS /* To debug the macros. */ +# undef EXTRACT_NUMBER +# define EXTRACT_NUMBER(dest, src) extract_number (&dest, src) +# endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number. + SOURCE must be an lvalue. */ + +#define EXTRACT_NUMBER_AND_INCR(destination, source) \ + do { \ + EXTRACT_NUMBER (destination, source); \ + (source) += 2; \ + } while (0) + +#ifdef DEBUG +static void extract_number_and_incr _RE_ARGS ((int *destination, + unsigned char **source)); +static void +extract_number_and_incr (destination, source) + int *destination; + unsigned char **source; +{ + extract_number (destination, *source); + *source += 2; +} + +# ifndef EXTRACT_MACROS +# undef EXTRACT_NUMBER_AND_INCR +# define EXTRACT_NUMBER_AND_INCR(dest, src) \ + extract_number_and_incr (&dest, &src) +# endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* If DEBUG is defined, Regex prints many voluminous messages about what + it is doing (if the variable `debug' is nonzero). If linked with the + main program in `iregex.c', you can enter patterns and strings + interactively. And if linked with the main program in `main.c' and + the other test files, you can run the already-written tests. */ + +#ifdef DEBUG + +/* We use standard I/O for debugging. */ +# include + +/* It is useful to test things that ``must'' be true when debugging. */ +# include + +static int debug; + +# define DEBUG_STATEMENT(e) e +# define DEBUG_PRINT1(x) if (debug) printf (x) +# define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2) +# define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3) +# define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4) +# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ + if (debug) print_partial_compiled_pattern (s, e) +# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ + if (debug) print_double_string (w, s1, sz1, s2, sz2) + + +/* Print the fastmap in human-readable form. */ + +void +print_fastmap (fastmap) + char *fastmap; +{ + unsigned was_a_range = 0; + unsigned i = 0; + + while (i < (1 << BYTEWIDTH)) + { + if (fastmap[i++]) + { + was_a_range = 0; + putchar (i - 1); + while (i < (1 << BYTEWIDTH) && fastmap[i]) + { + was_a_range = 1; + i++; + } + if (was_a_range) + { + printf ("-"); + putchar (i - 1); + } + } + } + putchar ('\n'); +} + + +/* Print a compiled pattern string in human-readable form, starting at + the START pointer into it and ending just before the pointer END. */ + +void +print_partial_compiled_pattern (start, end) + unsigned char *start; + unsigned char *end; +{ + int mcnt, mcnt2; + unsigned char *p1; + unsigned char *p = start; + unsigned char *pend = end; + + if (start == NULL) + { + printf ("(null)\n"); + return; + } + + /* Loop over pattern commands. */ + while (p < pend) + { + printf ("%d:\t", p - start); + + switch ((re_opcode_t) *p++) + { + case no_op: + printf ("/no_op"); + break; + + case exactn: + mcnt = *p++; + printf ("/exactn/%d", mcnt); + do + { + putchar ('/'); + putchar (*p++); + } + while (--mcnt); + break; + + case start_memory: + mcnt = *p++; + printf ("/start_memory/%d/%d", mcnt, *p++); + break; + + case stop_memory: + mcnt = *p++; + printf ("/stop_memory/%d/%d", mcnt, *p++); + break; + + case duplicate: + printf ("/duplicate/%d", *p++); + break; + + case anychar: + printf ("/anychar"); + break; + + case charset: + case charset_not: + { + register int c, last = -100; + register int in_range = 0; + + printf ("/charset [%s", + (re_opcode_t) *(p - 1) == charset_not ? "^" : ""); + + assert (p + *p < pend); + + for (c = 0; c < 256; c++) + if (c / 8 < *p + && (p[1 + (c/8)] & (1 << (c % 8)))) + { + /* Are we starting a range? */ + if (last + 1 == c && ! in_range) + { + putchar ('-'); + in_range = 1; + } + /* Have we broken a range? */ + else if (last + 1 != c && in_range) + { + putchar (last); + in_range = 0; + } + + if (! in_range) + putchar (c); + + last = c; + } + + if (in_range) + putchar (last); + + putchar (']'); + + p += 1 + *p; + } + break; + + case begline: + printf ("/begline"); + break; + + case endline: + printf ("/endline"); + break; + + case on_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_jump to %d", p + mcnt - start); + break; + + case on_failure_keep_string_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_keep_string_jump to %d", p + mcnt - start); + break; + + case dummy_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/dummy_failure_jump to %d", p + mcnt - start); + break; + + case push_dummy_failure: + printf ("/push_dummy_failure"); + break; + + case maybe_pop_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/maybe_pop_jump to %d", p + mcnt - start); + break; + + case pop_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/pop_failure_jump to %d", p + mcnt - start); + break; + + case jump_past_alt: + extract_number_and_incr (&mcnt, &p); + printf ("/jump_past_alt to %d", p + mcnt - start); + break; + + case jump: + extract_number_and_incr (&mcnt, &p); + printf ("/jump to %d", p + mcnt - start); + break; + + case succeed_n: + extract_number_and_incr (&mcnt, &p); + p1 = p + mcnt; + extract_number_and_incr (&mcnt2, &p); + printf ("/succeed_n to %d, %d times", p1 - start, mcnt2); + break; + + case jump_n: + extract_number_and_incr (&mcnt, &p); + p1 = p + mcnt; + extract_number_and_incr (&mcnt2, &p); + printf ("/jump_n to %d, %d times", p1 - start, mcnt2); + break; + + case set_number_at: + extract_number_and_incr (&mcnt, &p); + p1 = p + mcnt; + extract_number_and_incr (&mcnt2, &p); + printf ("/set_number_at location %d to %d", p1 - start, mcnt2); + break; + + case wordbound: + printf ("/wordbound"); + break; + + case notwordbound: + printf ("/notwordbound"); + break; + + case wordbeg: + printf ("/wordbeg"); + break; + + case wordend: + printf ("/wordend"); + +# ifdef emacs + case before_dot: + printf ("/before_dot"); + break; + + case at_dot: + printf ("/at_dot"); + break; + + case after_dot: + printf ("/after_dot"); + break; + + case syntaxspec: + printf ("/syntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; + + case notsyntaxspec: + printf ("/notsyntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; +# endif /* emacs */ + + case wordchar: + printf ("/wordchar"); + break; + + case notwordchar: + printf ("/notwordchar"); + break; + + case begbuf: + printf ("/begbuf"); + break; + + case endbuf: + printf ("/endbuf"); + break; + + default: + printf ("?%d", *(p-1)); + } + + putchar ('\n'); + } + + printf ("%d:\tend of pattern.\n", p - start); +} + + +void +print_compiled_pattern (bufp) + struct re_pattern_buffer *bufp; +{ + unsigned char *buffer = bufp->buffer; + + print_partial_compiled_pattern (buffer, buffer + bufp->used); + printf ("%ld bytes used/%ld bytes allocated.\n", + bufp->used, bufp->allocated); + + if (bufp->fastmap_accurate && bufp->fastmap) + { + printf ("fastmap: "); + print_fastmap (bufp->fastmap); + } + + printf ("re_nsub: %d\t", bufp->re_nsub); + printf ("regs_alloc: %d\t", bufp->regs_allocated); + printf ("can_be_null: %d\t", bufp->can_be_null); + printf ("newline_anchor: %d\n", bufp->newline_anchor); + printf ("no_sub: %d\t", bufp->no_sub); + printf ("not_bol: %d\t", bufp->not_bol); + printf ("not_eol: %d\t", bufp->not_eol); + printf ("syntax: %lx\n", bufp->syntax); + /* Perhaps we should print the translate table? */ +} + + +void +print_double_string (where, string1, size1, string2, size2) + const char *where; + const char *string1; + const char *string2; + int size1; + int size2; +{ + int this_char; + + if (where == NULL) + printf ("(null)"); + else + { + if (FIRST_STRING_P (where)) + { + for (this_char = where - string1; this_char < size1; this_char++) + putchar (string1[this_char]); + + where = string2; + } + + for (this_char = where - string2; this_char < size2; this_char++) + putchar (string2[this_char]); + } +} + +void +printchar (c) + int c; +{ + putc (c, stderr); +} + +#else /* not DEBUG */ + +# undef assert +# define assert(e) + +# define DEBUG_STATEMENT(e) +# define DEBUG_PRINT1(x) +# define DEBUG_PRINT2(x1, x2) +# define DEBUG_PRINT3(x1, x2, x3) +# define DEBUG_PRINT4(x1, x2, x3, x4) +# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) +# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) + +#endif /* not DEBUG */ + +/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can + also be assigned to arbitrarily: each pattern buffer stores its own + syntax, so it can be changed between regex compilations. */ +/* This has no initializer because initialized variables in Emacs + become read-only after dumping. */ +reg_syntax_t re_syntax_options; + + +/* Specify the precise syntax of regexps for compilation. This provides + for compatibility for various utilities which historically have + different, incompatible syntaxes. + + The argument SYNTAX is a bit mask comprised of the various bits + defined in regex.h. We return the old syntax. */ + +reg_syntax_t +re_set_syntax (syntax) + reg_syntax_t syntax; +{ + reg_syntax_t ret = re_syntax_options; + + re_syntax_options = syntax; +#ifdef DEBUG + if (syntax & RE_DEBUG) + debug = 1; + else if (debug) /* was on but now is not */ + debug = 0; +#endif /* DEBUG */ + return ret; +} +#ifdef _LIBC +weak_alias (__re_set_syntax, re_set_syntax) +#endif + +/* This table gives an error message for each of the error codes listed + in regex.h. Obviously the order here has to be same as there. + POSIX doesn't require that we do anything for REG_NOERROR, + but why not be nice? */ + +static const char re_error_msgid[] = + { +#define REG_NOERROR_IDX 0 + gettext_noop ("Success") /* REG_NOERROR */ + "\0" +#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success") + gettext_noop ("No match") /* REG_NOMATCH */ + "\0" +#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match") + gettext_noop ("Invalid regular expression") /* REG_BADPAT */ + "\0" +#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression") + gettext_noop ("Invalid collation character"), /* REG_ECOLLATE */ + "\0" +#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character") + gettext_noop ("Invalid character class name") /* REG_ECTYPE */ + "\0" +#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name") + gettext_noop ("Trailing backslash") /* REG_EESCAPE */ + "\0" +#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash") + gettext_noop ("Invalid back reference") /* REG_ESUBREG */ + "\0" +#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference") + gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */ + "\0" +#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^") + gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */ + "\0" +#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(") + gettext_noop ("Unmatched \\{") /* REG_EBRACE */ + "\0" +#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{") + gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */ + "\0" +#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}") + gettext_noop ("Invalid range end") /* REG_ERANGE */ + "\0" +#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end") + gettext_noop ("Memory exhausted") /* REG_ESPACE */ + "\0" +#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted") + gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */ + "\0" +#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression") + gettext_noop ("Premature end of regular expression") /* REG_EEND */ + "\0" +#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression") + gettext_noop ("Regular expression too big") /* REG_ESIZE */ + "\0" +#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big") + gettext_noop ("Unmatched ) or \\)"), /* REG_ERPAREN */ + }; + +static const size_t re_error_msgid_idx[] = + { + REG_NOERROR_IDX, + REG_NOMATCH_IDX, + REG_BADPAT_IDX, + REG_ECOLLATE_IDX, + REG_ECTYPE_IDX, + REG_EESCAPE_IDX, + REG_ESUBREG_IDX, + REG_EBRACK_IDX, + REG_EPAREN_IDX, + REG_EBRACE_IDX, + REG_BADBR_IDX, + REG_ERANGE_IDX, + REG_ESPACE_IDX, + REG_BADRPT_IDX, + REG_EEND_IDX, + REG_ESIZE_IDX, + REG_ERPAREN_IDX + }; + +/* Avoiding alloca during matching, to placate r_alloc. */ + +/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the + searching and matching functions should not call alloca. On some + systems, alloca is implemented in terms of malloc, and if we're + using the relocating allocator routines, then malloc could cause a + relocation, which might (if the strings being searched are in the + ralloc heap) shift the data out from underneath the regexp + routines. + + Here's another reason to avoid allocation: Emacs + processes input from X in a signal handler; processing X input may + call malloc; if input arrives while a matching routine is calling + malloc, then we're scrod. But Emacs can't just block input while + calling matching routines; then we don't notice interrupts when + they come in. So, Emacs blocks input around all regexp calls + except the matching calls, which it leaves unprotected, in the + faith that they will not malloc. */ + +/* Normally, this is fine. */ +#define MATCH_MAY_ALLOCATE + +/* When using GNU C, we are not REALLY using the C alloca, no matter + what config.h may say. So don't take precautions for it. */ +#ifdef __GNUC__ +# undef C_ALLOCA +#endif + +/* The match routines may not allocate if (1) they would do it with malloc + and (2) it's not safe for them to use malloc. + Note that if REL_ALLOC is defined, matching would not use malloc for the + failure stack, but we would still use it for the register vectors; + so REL_ALLOC should not affect this. */ +#if (defined C_ALLOCA || defined REGEX_MALLOC) && defined emacs +# undef MATCH_MAY_ALLOCATE +#endif + + +/* Failure stack declarations and macros; both re_compile_fastmap and + re_match_2 use a failure stack. These have to be macros because of + REGEX_ALLOCATE_STACK. */ + + +/* Number of failure points for which to initially allocate space + when matching. If this number is exceeded, we allocate more + space, so it is not a hard limit. */ +#ifndef INIT_FAILURE_ALLOC +# define INIT_FAILURE_ALLOC 5 +#endif + +/* Roughly the maximum number of failure points on the stack. Would be + exactly that if always used MAX_FAILURE_ITEMS items each time we failed. + This is a variable only so users of regex can assign to it; we never + change it ourselves. */ + +#ifdef INT_IS_16BIT + +# if defined MATCH_MAY_ALLOCATE +/* 4400 was enough to cause a crash on Alpha OSF/1, + whose default stack limit is 2mb. */ +long int re_max_failures = 4000; +# else +long int re_max_failures = 2000; +# endif + +union fail_stack_elt +{ + unsigned char *pointer; + long int integer; +}; + +typedef union fail_stack_elt fail_stack_elt_t; + +typedef struct +{ + fail_stack_elt_t *stack; + unsigned long int size; + unsigned long int avail; /* Offset of next open position. */ +} fail_stack_type; + +#else /* not INT_IS_16BIT */ + +# if defined MATCH_MAY_ALLOCATE +/* 4400 was enough to cause a crash on Alpha OSF/1, + whose default stack limit is 2mb. */ +int re_max_failures = 20000; +# else +int re_max_failures = 2000; +# endif + +union fail_stack_elt +{ + unsigned char *pointer; + int integer; +}; + +typedef union fail_stack_elt fail_stack_elt_t; + +typedef struct +{ + fail_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} fail_stack_type; + +#endif /* INT_IS_16BIT */ + +#define FAIL_STACK_EMPTY() (fail_stack.avail == 0) +#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0) +#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) + + +/* Define macros to initialize and free the failure stack. + Do `return -2' if the alloc fails. */ + +#ifdef MATCH_MAY_ALLOCATE +# define INIT_FAIL_STACK() \ + do { \ + fail_stack.stack = (fail_stack_elt_t *) \ + REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \ + \ + if (fail_stack.stack == NULL) \ + return -2; \ + \ + fail_stack.size = INIT_FAILURE_ALLOC; \ + fail_stack.avail = 0; \ + } while (0) + +# define RESET_FAIL_STACK() REGEX_FREE_STACK (fail_stack.stack) +#else +# define INIT_FAIL_STACK() \ + do { \ + fail_stack.avail = 0; \ + } while (0) + +# define RESET_FAIL_STACK() +#endif + + +/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. + + Return 1 if succeeds, and 0 if either ran out of memory + allocating space for it or it was already too large. + + REGEX_REALLOCATE_STACK requires `destination' be declared. */ + +#define DOUBLE_FAIL_STACK(fail_stack) \ + ((fail_stack).size > (unsigned) (re_max_failures * MAX_FAILURE_ITEMS) \ + ? 0 \ + : ((fail_stack).stack = (fail_stack_elt_t *) \ + REGEX_REALLOCATE_STACK ((fail_stack).stack, \ + (fail_stack).size * sizeof (fail_stack_elt_t), \ + ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \ + \ + (fail_stack).stack == NULL \ + ? 0 \ + : ((fail_stack).size <<= 1, \ + 1))) + + +/* Push pointer POINTER on FAIL_STACK. + Return 1 if was able to do so and 0 if ran out of memory allocating + space to do so. */ +#define PUSH_PATTERN_OP(POINTER, FAIL_STACK) \ + ((FAIL_STACK_FULL () \ + && !DOUBLE_FAIL_STACK (FAIL_STACK)) \ + ? 0 \ + : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER, \ + 1)) + +/* Push a pointer value onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_POINTER(item) \ + fail_stack.stack[fail_stack.avail++].pointer = (unsigned char *) (item) + +/* This pushes an integer-valued item onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_INT(item) \ + fail_stack.stack[fail_stack.avail++].integer = (item) + +/* Push a fail_stack_elt_t value onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_ELT(item) \ + fail_stack.stack[fail_stack.avail++] = (item) + +/* These three POP... operations complement the three PUSH... operations. + All assume that `fail_stack' is nonempty. */ +#define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer +#define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer +#define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail] + +/* Used to omit pushing failure point id's when we're not debugging. */ +#ifdef DEBUG +# define DEBUG_PUSH PUSH_FAILURE_INT +# define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT () +#else +# define DEBUG_PUSH(item) +# define DEBUG_POP(item_addr) +#endif + + +/* Push the information about the state we will need + if we ever fail back to it. + + Requires variables fail_stack, regstart, regend, reg_info, and + num_regs_pushed be declared. DOUBLE_FAIL_STACK requires `destination' + be declared. + + Does `return FAILURE_CODE' if runs out of memory. */ + +#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ + do { \ + char *destination; \ + /* Must be int, so when we don't save any registers, the arithmetic \ + of 0 + -1 isn't done as unsigned. */ \ + /* Can't be int, since there is not a shred of a guarantee that int \ + is wide enough to hold a value of something to which pointer can \ + be assigned */ \ + active_reg_t this_reg; \ + \ + DEBUG_STATEMENT (failure_id++); \ + DEBUG_STATEMENT (nfailure_points_pushed++); \ + DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ + DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\ + DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ + \ + DEBUG_PRINT2 (" slots needed: %ld\n", NUM_FAILURE_ITEMS); \ + DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \ + \ + /* Ensure we have enough space allocated for what we will push. */ \ + while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ + { \ + if (!DOUBLE_FAIL_STACK (fail_stack)) \ + return failure_code; \ + \ + DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ + (fail_stack).size); \ + DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ + } \ + \ + /* Push the info, starting with the registers. */ \ + DEBUG_PRINT1 ("\n"); \ + \ + if (1) \ + for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ + this_reg++) \ + { \ + DEBUG_PRINT2 (" Pushing reg: %lu\n", this_reg); \ + DEBUG_STATEMENT (num_regs_pushed++); \ + \ + DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \ + PUSH_FAILURE_POINTER (regstart[this_reg]); \ + \ + DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \ + PUSH_FAILURE_POINTER (regend[this_reg]); \ + \ + DEBUG_PRINT2 (" info: %p\n ", \ + reg_info[this_reg].word.pointer); \ + DEBUG_PRINT2 (" match_null=%d", \ + REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ + DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ + DEBUG_PRINT2 (" matched_something=%d", \ + MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT2 (" ever_matched=%d", \ + EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT1 ("\n"); \ + PUSH_FAILURE_ELT (reg_info[this_reg].word); \ + } \ + \ + DEBUG_PRINT2 (" Pushing low active reg: %ld\n", lowest_active_reg);\ + PUSH_FAILURE_INT (lowest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing high active reg: %ld\n", highest_active_reg);\ + PUSH_FAILURE_INT (highest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing pattern %p:\n", pattern_place); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \ + PUSH_FAILURE_POINTER (pattern_place); \ + \ + DEBUG_PRINT2 (" Pushing string %p: `", string_place); \ + DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \ + size2); \ + DEBUG_PRINT1 ("'\n"); \ + PUSH_FAILURE_POINTER (string_place); \ + \ + DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \ + DEBUG_PUSH (failure_id); \ + } while (0) + +/* This is the number of items that are pushed and popped on the stack + for each register. */ +#define NUM_REG_ITEMS 3 + +/* Individual items aside from the registers. */ +#ifdef DEBUG +# define NUM_NONREG_ITEMS 5 /* Includes failure point id. */ +#else +# define NUM_NONREG_ITEMS 4 +#endif + +/* We push at most this many items on the stack. */ +/* We used to use (num_regs - 1), which is the number of registers + this regexp will save; but that was changed to 5 + to avoid stack overflow for a regexp with lots of parens. */ +#define MAX_FAILURE_ITEMS (5 * NUM_REG_ITEMS + NUM_NONREG_ITEMS) + +/* We actually push this many items. */ +#define NUM_FAILURE_ITEMS \ + (((0 \ + ? 0 : highest_active_reg - lowest_active_reg + 1) \ + * NUM_REG_ITEMS) \ + + NUM_NONREG_ITEMS) + +/* How many items can still be added to the stack without overflowing it. */ +#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) + + +/* Pops what PUSH_FAIL_STACK pushes. + + We restore into the parameters, all of which should be lvalues: + STR -- the saved data position. + PAT -- the saved pattern position. + LOW_REG, HIGH_REG -- the highest and lowest active registers. + REGSTART, REGEND -- arrays of string positions. + REG_INFO -- array of information about each subexpression. + + Also assumes the variables `fail_stack' and (if debugging), `bufp', + `pend', `string1', `size1', `string2', and `size2'. */ + +#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\ +{ \ + DEBUG_STATEMENT (unsigned failure_id;) \ + active_reg_t this_reg; \ + const unsigned char *string_temp; \ + \ + assert (!FAIL_STACK_EMPTY ()); \ + \ + /* Remove failure points and point to how many regs pushed. */ \ + DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ + DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ + DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ + \ + assert (fail_stack.avail >= NUM_NONREG_ITEMS); \ + \ + DEBUG_POP (&failure_id); \ + DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \ + \ + /* If the saved string location is NULL, it came from an \ + on_failure_keep_string_jump opcode, and we want to throw away the \ + saved NULL, thus retaining our current position in the string. */ \ + string_temp = POP_FAILURE_POINTER (); \ + if (string_temp != NULL) \ + str = (const char *) string_temp; \ + \ + DEBUG_PRINT2 (" Popping string %p: `", str); \ + DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ + DEBUG_PRINT1 ("'\n"); \ + \ + pat = (unsigned char *) POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" Popping pattern %p:\n", pat); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ + \ + /* Restore register info. */ \ + high_reg = (active_reg_t) POP_FAILURE_INT (); \ + DEBUG_PRINT2 (" Popping high active reg: %ld\n", high_reg); \ + \ + low_reg = (active_reg_t) POP_FAILURE_INT (); \ + DEBUG_PRINT2 (" Popping low active reg: %ld\n", low_reg); \ + \ + if (1) \ + for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \ + { \ + DEBUG_PRINT2 (" Popping reg: %ld\n", this_reg); \ + \ + reg_info[this_reg].word = POP_FAILURE_ELT (); \ + DEBUG_PRINT2 (" info: %p\n", \ + reg_info[this_reg].word.pointer); \ + \ + regend[this_reg] = (const char *) POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \ + \ + regstart[this_reg] = (const char *) POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \ + } \ + else \ + { \ + for (this_reg = highest_active_reg; this_reg > high_reg; this_reg--) \ + { \ + reg_info[this_reg].word.integer = 0; \ + regend[this_reg] = 0; \ + regstart[this_reg] = 0; \ + } \ + highest_active_reg = high_reg; \ + } \ + \ + set_regs_matched_done = 0; \ + DEBUG_STATEMENT (nfailure_points_popped++); \ +} /* POP_FAILURE_POINT */ + + + +/* Structure for per-register (a.k.a. per-group) information. + Other register information, such as the + starting and ending positions (which are addresses), and the list of + inner groups (which is a bits list) are maintained in separate + variables. + + We are making a (strictly speaking) nonportable assumption here: that + the compiler will pack our bit fields into something that fits into + the type of `word', i.e., is something that fits into one item on the + failure stack. */ + + +/* Declarations and macros for re_match_2. */ + +typedef union +{ + fail_stack_elt_t word; + struct + { + /* This field is one if this group can match the empty string, + zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ +#define MATCH_NULL_UNSET_VALUE 3 + unsigned match_null_string_p : 2; + unsigned is_active : 1; + unsigned matched_something : 1; + unsigned ever_matched_something : 1; + } bits; +} register_info_type; + +#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p) +#define IS_ACTIVE(R) ((R).bits.is_active) +#define MATCHED_SOMETHING(R) ((R).bits.matched_something) +#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) + + +/* Call this when have matched a real character; it sets `matched' flags + for the subexpressions which we are currently inside. Also records + that those subexprs have matched. */ +#define SET_REGS_MATCHED() \ + do \ + { \ + if (!set_regs_matched_done) \ + { \ + active_reg_t r; \ + set_regs_matched_done = 1; \ + for (r = lowest_active_reg; r <= highest_active_reg; r++) \ + { \ + MATCHED_SOMETHING (reg_info[r]) \ + = EVER_MATCHED_SOMETHING (reg_info[r]) \ + = 1; \ + } \ + } \ + } \ + while (0) + +/* Registers are set to a sentinel when they haven't yet matched. */ +static char reg_unset_dummy; +#define REG_UNSET_VALUE (®_unset_dummy) +#define REG_UNSET(e) ((e) == REG_UNSET_VALUE) + +/* Subroutine declarations and macros for regex_compile. */ + +static reg_errcode_t regex_compile _RE_ARGS ((const char *pattern, size_t size, + reg_syntax_t syntax, + struct re_pattern_buffer *bufp)); +static void store_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc, int arg)); +static void store_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc, + int arg1, int arg2)); +static void insert_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc, + int arg, unsigned char *end)); +static void insert_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc, + int arg1, int arg2, unsigned char *end)); +static boolean at_begline_loc_p _RE_ARGS ((const char *pattern, const char *p, + reg_syntax_t syntax)); +static boolean at_endline_loc_p _RE_ARGS ((const char *p, const char *pend, + reg_syntax_t syntax)); +static reg_errcode_t compile_range _RE_ARGS ((const char **p_ptr, + const char *pend, + char *translate, + reg_syntax_t syntax, + unsigned char *b)); + +/* Fetch the next character in the uncompiled pattern---translating it + if necessary. Also cast from a signed character in the constant + string passed to us by the user to an unsigned char that we can use + as an array index (in, e.g., `translate'). */ +#ifndef PATFETCH +# define PATFETCH(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + if (translate) c = (unsigned char) translate[c]; \ + } while (0) +#endif + +/* Fetch the next character in the uncompiled pattern, with no + translation. */ +#define PATFETCH_RAW(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + } while (0) + +/* Go backwards one character in the pattern. */ +#define PATUNFETCH p-- + + +/* If `translate' is non-null, return translate[D], else just D. We + cast the subscript to translate because some data is declared as + `char *', to avoid warnings when a string constant is passed. But + when we use a character as a subscript we must make it unsigned. */ +#ifndef TRANSLATE +# define TRANSLATE(d) \ + (translate ? (char) translate[(unsigned char) (d)] : (d)) +#endif + + +/* Macros for outputting the compiled pattern into `buffer'. */ + +/* If the buffer isn't allocated when it comes in, use this. */ +#define INIT_BUF_SIZE 32 + +/* Make sure we have at least N more bytes of space in buffer. */ +#define GET_BUFFER_SPACE(n) \ + while ((unsigned long) (b - bufp->buffer + (n)) > bufp->allocated) \ + EXTEND_BUFFER () + +/* Make sure we have one more byte of buffer space and then add C to it. */ +#define BUF_PUSH(c) \ + do { \ + GET_BUFFER_SPACE (1); \ + *b++ = (unsigned char) (c); \ + } while (0) + + +/* Ensure we have two more bytes of buffer space and then append C1 and C2. */ +#define BUF_PUSH_2(c1, c2) \ + do { \ + GET_BUFFER_SPACE (2); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + } while (0) + + +/* As with BUF_PUSH_2, except for three bytes. */ +#define BUF_PUSH_3(c1, c2, c3) \ + do { \ + GET_BUFFER_SPACE (3); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + *b++ = (unsigned char) (c3); \ + } while (0) + + +/* Store a jump with opcode OP at LOC to location TO. We store a + relative address offset by the three bytes the jump itself occupies. */ +#define STORE_JUMP(op, loc, to) \ + store_op1 (op, loc, (int) ((to) - (loc) - 3)) + +/* Likewise, for a two-argument jump. */ +#define STORE_JUMP2(op, loc, to, arg) \ + store_op2 (op, loc, (int) ((to) - (loc) - 3), arg) + +/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP(op, loc, to) \ + insert_op1 (op, loc, (int) ((to) - (loc) - 3), b) + +/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP2(op, loc, to, arg) \ + insert_op2 (op, loc, (int) ((to) - (loc) - 3), arg, b) + + +/* This is not an arbitrary limit: the arguments which represent offsets + into the pattern are two bytes long. So if 2^16 bytes turns out to + be too small, many things would have to change. */ +/* Any other compiler which, like MSC, has allocation limit below 2^16 + bytes will have to use approach similar to what was done below for + MSC and drop MAX_BUF_SIZE a bit. Otherwise you may end up + reallocating to 0 bytes. Such thing is not going to work too well. + You have been warned!! */ +#if defined _MSC_VER && !defined WIN32 +/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes. + The REALLOC define eliminates a flurry of conversion warnings, + but is not required. */ +# define MAX_BUF_SIZE 65500L +# define REALLOC(p,s) realloc ((p), (size_t) (s)) +#else +# define MAX_BUF_SIZE (1L << 16) +# define REALLOC(p,s) realloc ((p), (s)) +#endif + +/* Extend the buffer by twice its current size via realloc and + reset the pointers that pointed into the old block to point to the + correct places in the new one. If extending the buffer results in it + being larger than MAX_BUF_SIZE, then flag memory exhausted. */ +#define EXTEND_BUFFER() \ + do { \ + unsigned char *old_buffer = bufp->buffer; \ + if (bufp->allocated == MAX_BUF_SIZE) \ + return REG_ESIZE; \ + bufp->allocated <<= 1; \ + if (bufp->allocated > MAX_BUF_SIZE) \ + bufp->allocated = MAX_BUF_SIZE; \ + bufp->buffer = (unsigned char *) REALLOC (bufp->buffer, bufp->allocated);\ + if (bufp->buffer == NULL) \ + return REG_ESPACE; \ + /* If the buffer moved, move all the pointers into it. */ \ + if (old_buffer != bufp->buffer) \ + { \ + b = (b - old_buffer) + bufp->buffer; \ + begalt = (begalt - old_buffer) + bufp->buffer; \ + if (fixup_alt_jump) \ + fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\ + if (laststart) \ + laststart = (laststart - old_buffer) + bufp->buffer; \ + if (pending_exact) \ + pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ + } \ + } while (0) + + +/* Since we have one byte reserved for the register number argument to + {start,stop}_memory, the maximum number of groups we can report + things about is what fits in that byte. */ +#define MAX_REGNUM 255 + +/* But patterns can have more than `MAX_REGNUM' registers. We just + ignore the excess. */ +typedef unsigned regnum_t; + + +/* Macros for the compile stack. */ + +/* Since offsets can go either forwards or backwards, this type needs to + be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ +/* int may be not enough when sizeof(int) == 2. */ +typedef long pattern_offset_t; + +typedef struct +{ + pattern_offset_t begalt_offset; + pattern_offset_t fixup_alt_jump; + pattern_offset_t inner_group_offset; + pattern_offset_t laststart_offset; + regnum_t regnum; +} compile_stack_elt_t; + + +typedef struct +{ + compile_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} compile_stack_type; + + +#define INIT_COMPILE_STACK_SIZE 32 + +#define COMPILE_STACK_EMPTY (compile_stack.avail == 0) +#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) + +/* The next available element. */ +#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) + + +/* Set the bit for character C in a list. */ +#define SET_LIST_BIT(c) \ + (b[((unsigned char) (c)) / BYTEWIDTH] \ + |= 1 << (((unsigned char) c) % BYTEWIDTH)) + + +/* Get the next unsigned number in the uncompiled pattern. */ +#define GET_UNSIGNED_NUMBER(num) \ + { if (p != pend) \ + { \ + PATFETCH (c); \ + while (ISDIGIT (c)) \ + { \ + if (num < 0) \ + num = 0; \ + num = num * 10 + c - '0'; \ + if (p == pend) \ + break; \ + PATFETCH (c); \ + } \ + } \ + } + +#if defined _LIBC || WIDE_CHAR_SUPPORT +/* The GNU C library provides support for user-defined character classes + and the functions from ISO C amendement 1. */ +# ifdef CHARCLASS_NAME_MAX +# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX +# else +/* This shouldn't happen but some implementation might still have this + problem. Use a reasonable default value. */ +# define CHAR_CLASS_MAX_LENGTH 256 +# endif + +# ifdef _LIBC +# define IS_CHAR_CLASS(string) __wctype (string) +# else +# define IS_CHAR_CLASS(string) wctype (string) +# endif +#else +# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ + +# define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ + || STREQ (string, "cntrl") || STREQ (string, "blank")) +#endif + +#ifndef MATCH_MAY_ALLOCATE + +/* If we cannot allocate large objects within re_match_2_internal, + we make the fail stack and register vectors global. + The fail stack, we grow to the maximum size when a regexp + is compiled. + The register vectors, we adjust in size each time we + compile a regexp, according to the number of registers it needs. */ + +static fail_stack_type fail_stack; + +/* Size with which the following vectors are currently allocated. + That is so we can make them bigger as needed, + but never make them smaller. */ +static int regs_allocated_size; + +static const char ** regstart, ** regend; +static const char ** old_regstart, ** old_regend; +static const char **best_regstart, **best_regend; +static register_info_type *reg_info; +static const char **reg_dummy; +static register_info_type *reg_info_dummy; + +/* Make the register vectors big enough for NUM_REGS registers, + but don't make them smaller. */ + +static +regex_grow_registers (num_regs) + int num_regs; +{ + if (num_regs > regs_allocated_size) + { + RETALLOC_IF (regstart, num_regs, const char *); + RETALLOC_IF (regend, num_regs, const char *); + RETALLOC_IF (old_regstart, num_regs, const char *); + RETALLOC_IF (old_regend, num_regs, const char *); + RETALLOC_IF (best_regstart, num_regs, const char *); + RETALLOC_IF (best_regend, num_regs, const char *); + RETALLOC_IF (reg_info, num_regs, register_info_type); + RETALLOC_IF (reg_dummy, num_regs, const char *); + RETALLOC_IF (reg_info_dummy, num_regs, register_info_type); + + regs_allocated_size = num_regs; + } +} + +#endif /* not MATCH_MAY_ALLOCATE */ + +static boolean group_in_compile_stack _RE_ARGS ((compile_stack_type + compile_stack, + regnum_t regnum)); + +/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. + Returns one of error codes defined in `regex.h', or zero for success. + + Assumes the `allocated' (and perhaps `buffer') and `translate' + fields are set in BUFP on entry. + + If it succeeds, results are put in BUFP (if it returns an error, the + contents of BUFP are undefined): + `buffer' is the compiled pattern; + `syntax' is set to SYNTAX; + `used' is set to the length of the compiled pattern; + `fastmap_accurate' is zero; + `re_nsub' is the number of subexpressions in PATTERN; + `not_bol' and `not_eol' are zero; + + The `fastmap' and `newline_anchor' fields are neither + examined nor set. */ + +/* Return, freeing storage we allocated. */ +#define FREE_STACK_RETURN(value) \ + return (free (compile_stack.stack), value) + +static reg_errcode_t +regex_compile (pattern, size, syntax, bufp) + const char *pattern; + size_t size; + reg_syntax_t syntax; + struct re_pattern_buffer *bufp; +{ + /* We fetch characters from PATTERN here. Even though PATTERN is + `char *' (i.e., signed), we declare these variables as unsigned, so + they can be reliably used as array indices. */ + register unsigned char c, c1; + + /* A random temporary spot in PATTERN. */ + const char *p1; + + /* Points to the end of the buffer, where we should append. */ + register unsigned char *b; + + /* Keeps track of unclosed groups. */ + compile_stack_type compile_stack; + + /* Points to the current (ending) position in the pattern. */ + const char *p = pattern; + const char *pend = pattern + size; + + /* How to translate the characters in the pattern. */ + RE_TRANSLATE_TYPE translate = bufp->translate; + + /* Address of the count-byte of the most recently inserted `exactn' + command. This makes it possible to tell if a new exact-match + character can be added to that command or if the character requires + a new `exactn' command. */ + unsigned char *pending_exact = 0; + + /* Address of start of the most recently finished expression. + This tells, e.g., postfix * where to find the start of its + operand. Reset at the beginning of groups and alternatives. */ + unsigned char *laststart = 0; + + /* Address of beginning of regexp, or inside of last group. */ + unsigned char *begalt; + + /* Place in the uncompiled pattern (i.e., the {) to + which to go back if the interval is invalid. */ + const char *beg_interval; + + /* Address of the place where a forward jump should go to the end of + the containing expression. Each alternative of an `or' -- except the + last -- ends with a forward jump of this sort. */ + unsigned char *fixup_alt_jump = 0; + + /* Counts open-groups as they are encountered. Remembered for the + matching close-group on the compile stack, so the same register + number is put in the stop_memory as the start_memory. */ + regnum_t regnum = 0; + +#ifdef DEBUG + DEBUG_PRINT1 ("\nCompiling pattern: "); + if (debug) + { + unsigned debug_count; + + for (debug_count = 0; debug_count < size; debug_count++) + putchar (pattern[debug_count]); + putchar ('\n'); + } +#endif /* DEBUG */ + + /* Initialize the compile stack. */ + compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); + if (compile_stack.stack == NULL) + return REG_ESPACE; + + compile_stack.size = INIT_COMPILE_STACK_SIZE; + compile_stack.avail = 0; + + /* Initialize the pattern buffer. */ + bufp->syntax = syntax; + bufp->fastmap_accurate = 0; + bufp->not_bol = bufp->not_eol = 0; + + /* Set `used' to zero, so that if we return an error, the pattern + printer (for debugging) will think there's no pattern. We reset it + at the end. */ + bufp->used = 0; + + /* Always count groups, whether or not bufp->no_sub is set. */ + bufp->re_nsub = 0; + +#if !defined emacs && !defined SYNTAX_TABLE + /* Initialize the syntax table. */ + init_syntax_once (); +#endif + + if (bufp->allocated == 0) + { + if (bufp->buffer) + { /* If zero allocated, but buffer is non-null, try to realloc + enough space. This loses if buffer's address is bogus, but + that is the user's responsibility. */ + RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); + } + else + { /* Caller did not allocate a buffer. Do it for them. */ + bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); + } + if (!bufp->buffer) FREE_STACK_RETURN (REG_ESPACE); + + bufp->allocated = INIT_BUF_SIZE; + } + + begalt = b = bufp->buffer; + + /* Loop through the uncompiled pattern until we're at the end. */ + while (p != pend) + { + PATFETCH (c); + + switch (c) + { + case '^': + { + if ( /* If at start of pattern, it's an operator. */ + p == pattern + 1 + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's come before. */ + || at_begline_loc_p (pattern, p, syntax)) + BUF_PUSH (begline); + else + goto normal_char; + } + break; + + + case '$': + { + if ( /* If at end of pattern, it's an operator. */ + p == pend + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's next. */ + || at_endline_loc_p (p, pend, syntax)) + BUF_PUSH (endline); + else + goto normal_char; + } + break; + + + case '+': + case '?': + if ((syntax & RE_BK_PLUS_QM) + || (syntax & RE_LIMITED_OPS)) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern... */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + FREE_STACK_RETURN (REG_BADRPT); + else if (!(syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + } + + { + /* Are we optimizing this jump? */ + boolean keep_string_p = false; + + /* 1 means zero (many) matches is allowed. */ + char zero_times_ok = 0, many_times_ok = 0; + + /* If there is a sequence of repetition chars, collapse it + down to just one (the right one). We can't combine + interval operators with these because of, e.g., `a{2}*', + which should only match an even number of `a's. */ + + for (;;) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + + if (p == pend) + break; + + PATFETCH (c); + + if (c == '*' + || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) + ; + + else if (syntax & RE_BK_PLUS_QM && c == '\\') + { + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + + c = c1; + } + else + { + PATUNFETCH; + break; + } + + /* If we get here, we found another repeat character. */ + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether or not zero matches is allowed + and also whether or not two or more matches is allowed. */ + if (many_times_ok) + { /* More than one repetition is allowed, so put in at the + end a backward relative jump from `b' to before the next + jump we're going to put in below (which jumps from + laststart to after this jump). + + But if we are at the `*' in the exact sequence `.*\n', + insert an unconditional jump backwards to the ., + instead of the beginning of the loop. This way we only + push a failure point once, instead of every time + through the loop. */ + assert (p - 1 > pattern); + + /* Allocate the space for the jump. */ + GET_BUFFER_SPACE (3); + + /* We know we are not at the first character of the pattern, + because laststart was nonzero. And we've already + incremented `p', by the way, to be the character after + the `*'. Do we have to do something analogous here + for null bytes, because of RE_DOT_NOT_NULL? */ + if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') + && zero_times_ok + && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') + && !(syntax & RE_DOT_NEWLINE)) + { /* We have .*\n. */ + STORE_JUMP (jump, b, laststart); + keep_string_p = true; + } + else + /* Anything else. */ + STORE_JUMP (maybe_pop_jump, b, laststart - 3); + + /* We've added more stuff to the buffer. */ + b += 3; + } + + /* On failure, jump from laststart to b + 3, which will be the + end of the buffer after this jump is inserted. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump + : on_failure_jump, + laststart, b + 3); + pending_exact = 0; + b += 3; + + if (!zero_times_ok) + { + /* At least one repetition is required, so insert a + `dummy_failure_jump' before the initial + `on_failure_jump' instruction of the loop. This + effects a skip over that instruction the first time + we hit that loop. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6); + b += 3; + } + } + break; + + + case '.': + laststart = b; + BUF_PUSH (anychar); + break; + + + case '[': + { + boolean had_char_class = false; + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + /* Ensure that we have enough space to push a charset: the + opcode, the length count, and the bitset; 34 bytes in all. */ + GET_BUFFER_SPACE (34); + + laststart = b; + + /* We test `*p == '^' twice, instead of using an if + statement, so we only need one BUF_PUSH. */ + BUF_PUSH (*p == '^' ? charset_not : charset); + if (*p == '^') + p++; + + /* Remember the first position in the bracket expression. */ + p1 = p; + + /* Push the number of bytes in the bitmap. */ + BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + + /* Clear the whole map. */ + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); + + /* charset_not matches newline according to a syntax bit. */ + if ((re_opcode_t) b[-2] == charset_not + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) + SET_LIST_BIT ('\n'); + + /* Read in characters and ranges, setting map bits. */ + for (;;) + { + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + PATFETCH (c); + + /* \ might escape characters inside [...] and [^...]. */ + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') + { + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + PATFETCH (c1); + SET_LIST_BIT (c1); + continue; + } + + /* Could be the end of the bracket expression. If it's + not (i.e., when the bracket expression is `[]' so + far), the ']' character bit gets set way below. */ + if (c == ']' && p != p1 + 1) + break; + + /* Look ahead to see if it's a range when the last thing + was a character class. */ + if (had_char_class && c == '-' && *p != ']') + FREE_STACK_RETURN (REG_ERANGE); + + /* Look ahead to see if it's a range when the last thing + was a character: if this is a hyphen not at the + beginning or the end of a list, then it's the range + operator. */ + if (c == '-' + && !(p - 2 >= pattern && p[-2] == '[') + && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') + && *p != ']') + { + reg_errcode_t ret + = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); + } + + else if (p[0] == '-' && p[1] != ']') + { /* This handles ranges made up of characters only. */ + reg_errcode_t ret; + + /* Move past the `-'. */ + PATFETCH (c1); + + ret = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); + } + + /* See if we're at the beginning of a possible character + class. */ + + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') + { /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[:'. */ + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (;;) + { + PATFETCH (c); + if ((c == ':' && *p == ']') || p == pend) + break; + if (c1 < CHAR_CLASS_MAX_LENGTH) + str[c1++] = c; + else + /* This is in any case an invalid class name. */ + str[0] = '\0'; + } + str[c1] = '\0'; + + /* If isn't a word bracketed by `[:' and `:]': + undo the ending character, the letters, and leave + the leading `:' and `[' (but set bits for them). */ + if (c == ':' && *p == ']') + { +#if defined _LIBC || WIDE_CHAR_SUPPORT + boolean is_lower = STREQ (str, "lower"); + boolean is_upper = STREQ (str, "upper"); + wctype_t wt; + int ch; + + wt = IS_CHAR_CLASS (str); + if (wt == 0) + FREE_STACK_RETURN (REG_ECTYPE); + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (ch = 0; ch < 1 << BYTEWIDTH; ++ch) + { +# ifdef _LIBC + if (__iswctype (__btowc (ch), wt)) + SET_LIST_BIT (ch); +# else + if (iswctype (btowc (ch), wt)) + SET_LIST_BIT (ch); +# endif + + if (translate && (is_upper || is_lower) + && (ISUPPER (ch) || ISLOWER (ch))) + SET_LIST_BIT (ch); + } + + had_char_class = true; +#else + int ch; + boolean is_alnum = STREQ (str, "alnum"); + boolean is_alpha = STREQ (str, "alpha"); + boolean is_blank = STREQ (str, "blank"); + boolean is_cntrl = STREQ (str, "cntrl"); + boolean is_digit = STREQ (str, "digit"); + boolean is_graph = STREQ (str, "graph"); + boolean is_lower = STREQ (str, "lower"); + boolean is_print = STREQ (str, "print"); + boolean is_punct = STREQ (str, "punct"); + boolean is_space = STREQ (str, "space"); + boolean is_upper = STREQ (str, "upper"); + boolean is_xdigit = STREQ (str, "xdigit"); + + if (!IS_CHAR_CLASS (str)) + FREE_STACK_RETURN (REG_ECTYPE); + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (ch = 0; ch < 1 << BYTEWIDTH; ch++) + { + /* This was split into 3 if's to + avoid an arbitrary limit in some compiler. */ + if ( (is_alnum && ISALNUM (ch)) + || (is_alpha && ISALPHA (ch)) + || (is_blank && ISBLANK (ch)) + || (is_cntrl && ISCNTRL (ch))) + SET_LIST_BIT (ch); + if ( (is_digit && ISDIGIT (ch)) + || (is_graph && ISGRAPH (ch)) + || (is_lower && ISLOWER (ch)) + || (is_print && ISPRINT (ch))) + SET_LIST_BIT (ch); + if ( (is_punct && ISPUNCT (ch)) + || (is_space && ISSPACE (ch)) + || (is_upper && ISUPPER (ch)) + || (is_xdigit && ISXDIGIT (ch))) + SET_LIST_BIT (ch); + if ( translate && (is_upper || is_lower) + && (ISUPPER (ch) || ISLOWER (ch))) + SET_LIST_BIT (ch); + } + had_char_class = true; +#endif /* libc || wctype.h */ + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT (':'); + had_char_class = false; + } + } + else + { + had_char_class = false; + SET_LIST_BIT (c); + } + } + + /* Discard any (non)matching list bytes that are all 0 at the + end of the map. Decrease the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + } + break; + + + case '(': + if (syntax & RE_NO_BK_PARENS) + goto handle_open; + else + goto normal_char; + + + case ')': + if (syntax & RE_NO_BK_PARENS) + goto handle_close; + else + goto normal_char; + + + case '\n': + if (syntax & RE_NEWLINE_ALT) + goto handle_alt; + else + goto normal_char; + + + case '|': + if (syntax & RE_NO_BK_VBAR) + goto handle_alt; + else + goto normal_char; + + + case '{': + if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) + goto handle_interval; + else + goto normal_char; + + + case '\\': + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + /* Do not translate the character after the \, so that we can + distinguish, e.g., \B from \b, even if we normally would + translate, e.g., B to b. */ + PATFETCH_RAW (c); + + switch (c) + { + case '(': + if (syntax & RE_NO_BK_PARENS) + goto normal_backslash; + + handle_open: + bufp->re_nsub++; + regnum++; + + if (COMPILE_STACK_FULL) + { + RETALLOC (compile_stack.stack, compile_stack.size << 1, + compile_stack_elt_t); + if (compile_stack.stack == NULL) return REG_ESPACE; + + compile_stack.size <<= 1; + } + + /* These are the values to restore when we hit end of this + group. They are all relative offsets, so that if the + whole pattern moves because of realloc, they will still + be valid. */ + COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; + COMPILE_STACK_TOP.fixup_alt_jump + = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; + COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; + COMPILE_STACK_TOP.regnum = regnum; + + /* We will eventually replace the 0 with the number of + groups inner to this one. But do not push a + start_memory for groups beyond the last one we can + represent in the compiled pattern. */ + if (regnum <= MAX_REGNUM) + { + COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2; + BUF_PUSH_3 (start_memory, regnum, 0); + } + + compile_stack.avail++; + + fixup_alt_jump = 0; + laststart = 0; + begalt = b; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + break; + + + case ')': + if (syntax & RE_NO_BK_PARENS) goto normal_backslash; + + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_backslash; + else + FREE_STACK_RETURN (REG_ERPAREN); + } + + handle_close: + if (fixup_alt_jump) + { /* Push a dummy failure point at the end of the + alternative for a possible future + `pop_failure_jump' to pop. See comments at + `push_dummy_failure' in `re_match_2'. */ + BUF_PUSH (push_dummy_failure); + + /* We allocated space for this jump when we assigned + to `fixup_alt_jump', in the `handle_alt' case below. */ + STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); + } + + /* See similar code for backslashed left paren above. */ + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_char; + else + FREE_STACK_RETURN (REG_ERPAREN); + } + + /* Since we just checked for an empty stack above, this + ``can't happen''. */ + assert (compile_stack.avail != 0); + { + /* We don't just want to restore into `regnum', because + later groups should continue to be numbered higher, + as in `(ab)c(de)' -- the second group is #2. */ + regnum_t this_group_regnum; + + compile_stack.avail--; + begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; + fixup_alt_jump + = COMPILE_STACK_TOP.fixup_alt_jump + ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 + : 0; + laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; + this_group_regnum = COMPILE_STACK_TOP.regnum; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + + /* We're at the end of the group, so now we know how many + groups were inside this one. */ + if (this_group_regnum <= MAX_REGNUM) + { + unsigned char *inner_group_loc + = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset; + + *inner_group_loc = regnum - this_group_regnum; + BUF_PUSH_3 (stop_memory, this_group_regnum, + regnum - this_group_regnum); + } + } + break; + + + case '|': /* `\|'. */ + if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) + goto normal_backslash; + handle_alt: + if (syntax & RE_LIMITED_OPS) + goto normal_char; + + /* Insert before the previous alternative a jump which + jumps to this alternative if the former fails. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (on_failure_jump, begalt, b + 6); + pending_exact = 0; + b += 3; + + /* The alternative before this one has a jump after it + which gets executed if it gets matched. Adjust that + jump so it will jump to this alternative's analogous + jump (put in below, which in turn will jump to the next + (if any) alternative's such jump, etc.). The last such + jump jumps to the correct final destination. A picture: + _____ _____ + | | | | + | v | v + a | b | c + + If we are at `b', then fixup_alt_jump right now points to a + three-byte space after `a'. We'll put in the jump, set + fixup_alt_jump to right after `b', and leave behind three + bytes which we'll fill in when we get to after `c'. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + /* Mark and leave space for a jump after this alternative, + to be filled in later either by next alternative or + when know we're at the end of a series of alternatives. */ + fixup_alt_jump = b; + GET_BUFFER_SPACE (3); + b += 3; + + laststart = 0; + begalt = b; + break; + + + case '{': + /* If \{ is a literal. */ + if (!(syntax & RE_INTERVALS) + /* If we're at `\{' and it's not the open-interval + operator. */ + || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + || (p - 2 == pattern && p == pend)) + goto normal_backslash; + + handle_interval: + { + /* If got here, then the syntax allows intervals. */ + + /* At least (most) this many matches must be made. */ + int lower_bound = -1, upper_bound = -1; + + beg_interval = p - 1; + + if (p == pend) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + FREE_STACK_RETURN (REG_EBRACE); + } + + GET_UNSIGNED_NUMBER (lower_bound); + + if (c == ',') + { + GET_UNSIGNED_NUMBER (upper_bound); + if (upper_bound < 0) upper_bound = RE_DUP_MAX; + } + else + /* Interval such as `{1}' => match exactly once. */ + upper_bound = lower_bound; + + if (lower_bound < 0 || upper_bound > RE_DUP_MAX + || lower_bound > upper_bound) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + FREE_STACK_RETURN (REG_BADBR); + } + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (c != '\\') FREE_STACK_RETURN (REG_EBRACE); + + PATFETCH (c); + } + + if (c != '}') + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + FREE_STACK_RETURN (REG_BADBR); + } + + /* We just parsed a valid interval. */ + + /* If it's invalid to have no preceding re. */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + FREE_STACK_RETURN (REG_BADRPT); + else if (syntax & RE_CONTEXT_INDEP_OPS) + laststart = b; + else + goto unfetch_interval; + } + + /* If the upper bound is zero, don't want to succeed at + all; jump from `laststart' to `b + 3', which will be + the end of the buffer after we insert the jump. */ + if (upper_bound == 0) + { + GET_BUFFER_SPACE (3); + INSERT_JUMP (jump, laststart, b + 3); + b += 3; + } + + /* Otherwise, we have a nontrivial interval. When + we're all done, the pattern will look like: + set_number_at + set_number_at + succeed_n + + jump_n + (The upper bound and `jump_n' are omitted if + `upper_bound' is 1, though.) */ + else + { /* If the upper bound is > 1, we need to insert + more at the end of the loop. */ + unsigned nbytes = 10 + (upper_bound > 1) * 10; + + GET_BUFFER_SPACE (nbytes); + + /* Initialize lower bound of the `succeed_n', even + though it will be set during matching by its + attendant `set_number_at' (inserted next), + because `re_compile_fastmap' needs to know. + Jump to the `jump_n' we might insert below. */ + INSERT_JUMP2 (succeed_n, laststart, + b + 5 + (upper_bound > 1) * 5, + lower_bound); + b += 5; + + /* Code to initialize the lower bound. Insert + before the `succeed_n'. The `5' is the last two + bytes of this `set_number_at', plus 3 bytes of + the following `succeed_n'. */ + insert_op2 (set_number_at, laststart, 5, lower_bound, b); + b += 5; + + if (upper_bound > 1) + { /* More than one repetition is allowed, so + append a backward jump to the `succeed_n' + that starts this interval. + + When we've reached this during matching, + we'll have matched the interval once, so + jump back only `upper_bound - 1' times. */ + STORE_JUMP2 (jump_n, b, laststart + 5, + upper_bound - 1); + b += 5; + + /* The location we want to set is the second + parameter of the `jump_n'; that is `b-2' as + an absolute address. `laststart' will be + the `set_number_at' we're about to insert; + `laststart+3' the number to set, the source + for the relative address. But we are + inserting into the middle of the pattern -- + so everything is getting moved up by 5. + Conclusion: (b - 2) - (laststart + 3) + 5, + i.e., b - laststart. + + We insert this at the beginning of the loop + so that if we fail during matching, we'll + reinitialize the bounds. */ + insert_op2 (set_number_at, laststart, b - laststart, + upper_bound - 1, b); + b += 5; + } + } + pending_exact = 0; + beg_interval = NULL; + } + break; + + unfetch_interval: + /* If an invalid interval, match the characters as literals. */ + assert (beg_interval); + p = beg_interval; + beg_interval = NULL; + + /* normal_char and normal_backslash need `c'. */ + PATFETCH (c); + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (p > pattern && p[-1] == '\\') + goto normal_backslash; + } + goto normal_char; + +#ifdef emacs + /* There is no way to specify the before_dot and after_dot + operators. rms says this is ok. --karl */ + case '=': + BUF_PUSH (at_dot); + break; + + case 's': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); + break; +#endif /* emacs */ + + + case 'w': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + laststart = b; + BUF_PUSH (wordchar); + break; + + + case 'W': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + laststart = b; + BUF_PUSH (notwordchar); + break; + + + case '<': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordbeg); + break; + + case '>': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordend); + break; + + case 'b': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordbound); + break; + + case 'B': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (notwordbound); + break; + + case '`': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (begbuf); + break; + + case '\'': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (endbuf); + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + if (syntax & RE_NO_BK_REFS) + goto normal_char; + + c1 = c - '0'; + + if (c1 > regnum) + FREE_STACK_RETURN (REG_ESUBREG); + + /* Can't back reference to a subexpression if inside of it. */ + if (group_in_compile_stack (compile_stack, (regnum_t) c1)) + goto normal_char; + + laststart = b; + BUF_PUSH_2 (duplicate, c1); + break; + + + case '+': + case '?': + if (syntax & RE_BK_PLUS_QM) + goto handle_plus; + else + goto normal_backslash; + + default: + normal_backslash: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + c = TRANSLATE (c); + goto normal_char; + } + break; + + + default: + /* Expects the character in `c'. */ + normal_char: + /* If no exactn currently being built. */ + if (!pending_exact + + /* If last exactn not at current position. */ + || pending_exact + *pending_exact + 1 != b + + /* We have only one byte following the exactn for the count. */ + || *pending_exact == (1 << BYTEWIDTH) - 1 + + /* If followed by a repetition operator. */ + || *p == '*' || *p == '^' + || ((syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?')) + || ((syntax & RE_INTERVALS) + && ((syntax & RE_NO_BK_BRACES) + ? *p == '{' + : (p[0] == '\\' && p[1] == '{')))) + { + /* Start building a new exactn. */ + + laststart = b; + + BUF_PUSH_2 (exactn, 0); + pending_exact = b - 1; + } + + BUF_PUSH (c); + (*pending_exact)++; + break; + } /* switch (c) */ + } /* while p != pend */ + + + /* Through the pattern now. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + if (!COMPILE_STACK_EMPTY) + FREE_STACK_RETURN (REG_EPAREN); + + /* If we don't want backtracking, force success + the first time we reach the end of the compiled pattern. */ + if (syntax & RE_NO_POSIX_BACKTRACKING) + BUF_PUSH (succeed); + + free (compile_stack.stack); + + /* We have succeeded; set the length of the buffer. */ + bufp->used = b - bufp->buffer; + +#ifdef DEBUG + if (debug) + { + DEBUG_PRINT1 ("\nCompiled pattern: \n"); + print_compiled_pattern (bufp); + } +#endif /* DEBUG */ + +#ifndef MATCH_MAY_ALLOCATE + /* Initialize the failure stack to the largest possible stack. This + isn't necessary unless we're trying to avoid calling alloca in + the search and match routines. */ + { + int num_regs = bufp->re_nsub + 1; + + /* Since DOUBLE_FAIL_STACK refuses to double only if the current size + is strictly greater than re_max_failures, the largest possible stack + is 2 * re_max_failures failure points. */ + if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS)) + { + fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS); + +# ifdef emacs + if (! fail_stack.stack) + fail_stack.stack + = (fail_stack_elt_t *) xmalloc (fail_stack.size + * sizeof (fail_stack_elt_t)); + else + fail_stack.stack + = (fail_stack_elt_t *) xrealloc (fail_stack.stack, + (fail_stack.size + * sizeof (fail_stack_elt_t))); +# else /* not emacs */ + if (! fail_stack.stack) + fail_stack.stack + = (fail_stack_elt_t *) malloc (fail_stack.size + * sizeof (fail_stack_elt_t)); + else + fail_stack.stack + = (fail_stack_elt_t *) realloc (fail_stack.stack, + (fail_stack.size + * sizeof (fail_stack_elt_t))); +# endif /* not emacs */ + } + + regex_grow_registers (num_regs); + } +#endif /* not MATCH_MAY_ALLOCATE */ + + return REG_NOERROR; +} /* regex_compile */ + +/* Subroutines for `regex_compile'. */ + +/* Store OP at LOC followed by two-byte integer parameter ARG. */ + +static void +store_op1 (op, loc, arg) + re_opcode_t op; + unsigned char *loc; + int arg; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg); +} + + +/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +store_op2 (op, loc, arg1, arg2) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg1); + STORE_NUMBER (loc + 3, arg2); +} + + +/* Copy the bytes from LOC to END to open up three bytes of space at LOC + for OP followed by two-byte integer parameter ARG. */ + +static void +insert_op1 (op, loc, arg, end) + re_opcode_t op; + unsigned char *loc; + int arg; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 3; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op1 (op, loc, arg); +} + + +/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +insert_op2 (op, loc, arg1, arg2, end) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 5; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op2 (op, loc, arg1, arg2); +} + + +/* P points to just after a ^ in PATTERN. Return true if that ^ comes + after an alternative or a begin-subexpression. We assume there is at + least one character before the ^. */ + +static boolean +at_begline_loc_p (pattern, p, syntax) + const char *pattern, *p; + reg_syntax_t syntax; +{ + const char *prev = p - 2; + boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; + + return + /* After a subexpression? */ + (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) + /* After an alternative? */ + || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)); +} + + +/* The dual of at_begline_loc_p. This one is for $. We assume there is + at least one character after the $, i.e., `P < PEND'. */ + +static boolean +at_endline_loc_p (p, pend, syntax) + const char *p, *pend; + reg_syntax_t syntax; +{ + const char *next = p; + boolean next_backslash = *next == '\\'; + const char *next_next = p + 1 < pend ? p + 1 : 0; + + return + /* Before a subexpression? */ + (syntax & RE_NO_BK_PARENS ? *next == ')' + : next_backslash && next_next && *next_next == ')') + /* Before an alternative? */ + || (syntax & RE_NO_BK_VBAR ? *next == '|' + : next_backslash && next_next && *next_next == '|'); +} + + +/* Returns true if REGNUM is in one of COMPILE_STACK's elements and + false if it's not. */ + +static boolean +group_in_compile_stack (compile_stack, regnum) + compile_stack_type compile_stack; + regnum_t regnum; +{ + int this_element; + + for (this_element = compile_stack.avail - 1; + this_element >= 0; + this_element--) + if (compile_stack.stack[this_element].regnum == regnum) + return true; + + return false; +} + + +/* Read the ending character of a range (in a bracket expression) from the + uncompiled pattern *P_PTR (which ends at PEND). We assume the + starting character is in `P[-2]'. (`P[-1]' is the character `-'.) + Then we set the translation of all bits between the starting and + ending characters (inclusive) in the compiled pattern B. + + Return an error code. + + We use these short variable names so we can use the same macros as + `regex_compile' itself. */ + +static reg_errcode_t +compile_range (p_ptr, pend, translate, syntax, b) + const char **p_ptr, *pend; + RE_TRANSLATE_TYPE translate; + reg_syntax_t syntax; + unsigned char *b; +{ + unsigned this_char; + + const char *p = *p_ptr; + unsigned int range_start, range_end; + + if (p == pend) + return REG_ERANGE; + + /* Even though the pattern is a signed `char *', we need to fetch + with unsigned char *'s; if the high bit of the pattern character + is set, the range endpoints will be negative if we fetch using a + signed char *. + + We also want to fetch the endpoints without translating them; the + appropriate translation is done in the bit-setting loop below. */ + /* The SVR4 compiler on the 3B2 had trouble with unsigned const char *. */ + range_start = ((const unsigned char *) p)[-2]; + range_end = ((const unsigned char *) p)[0]; + + /* Have to increment the pointer into the pattern string, so the + caller isn't still at the ending character. */ + (*p_ptr)++; + + /* If the start is after the end, the range is empty. */ + if (range_start > range_end) + return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR; + + /* Here we see why `this_char' has to be larger than an `unsigned + char' -- the range is inclusive, so if `range_end' == 0xff + (assuming 8-bit characters), we would otherwise go into an infinite + loop, since all characters <= 0xff. */ + for (this_char = range_start; this_char <= range_end; this_char++) + { + SET_LIST_BIT (TRANSLATE (this_char)); + } + + return REG_NOERROR; +} + +/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in + BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible + characters can start a string that matches the pattern. This fastmap + is used by re_search to skip quickly over impossible starting points. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data + area as BUFP->fastmap. + + We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in + the pattern buffer. + + Returns 0 if we succeed, -2 if an internal error. */ + +int +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + int j, k; +#ifdef MATCH_MAY_ALLOCATE + fail_stack_type fail_stack; +#endif +#ifndef REGEX_MALLOC + char *destination; +#endif + + register char *fastmap = bufp->fastmap; + unsigned char *pattern = bufp->buffer; + unsigned char *p = pattern; + register unsigned char *pend = pattern + bufp->used; + +#ifdef REL_ALLOC + /* This holds the pointer to the failure stack, when + it is allocated relocatably. */ + fail_stack_elt_t *failure_stack_ptr; +#endif + + /* Assume that each path through the pattern can be null until + proven otherwise. We set this false at the bottom of switch + statement, to which we get only if a particular path doesn't + match the empty string. */ + boolean path_can_be_null = true; + + /* We aren't doing a `succeed_n' to begin with. */ + boolean succeed_n_p = false; + + assert (fastmap != NULL && p != NULL); + + INIT_FAIL_STACK (); + bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ + bufp->fastmap_accurate = 1; /* It will be when we're done. */ + bufp->can_be_null = 0; + + while (1) + { + if (p == pend || *p == succeed) + { + /* We have reached the (effective) end of pattern. */ + if (!FAIL_STACK_EMPTY ()) + { + bufp->can_be_null |= path_can_be_null; + + /* Reset for next path. */ + path_can_be_null = true; + + p = fail_stack.stack[--fail_stack.avail].pointer; + + continue; + } + else + break; + } + + /* We should never be about to go beyond the end of the pattern. */ + assert (p < pend); + + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) + { + + /* I guess the idea here is to simply not bother with a fastmap + if a backreference is used, since it's too hard to figure out + the fastmap for the corresponding group. Setting + `can_be_null' stops `re_search_2' from using the fastmap, so + that is all we do. */ + case duplicate: + bufp->can_be_null = 1; + goto done; + + + /* Following are the cases which match a character. These end + with `break'. */ + + case exactn: + fastmap[p[1]] = 1; + break; + + + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + fastmap[j] = 1; + break; + + + case charset_not: + /* Chars beyond end of map must be allowed. */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + fastmap[j] = 1; + break; + + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; + + + case anychar: + { + int fastmap_newline = fastmap['\n']; + + /* `.' matches anything ... */ + for (j = 0; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + /* ... except perhaps newline. */ + if (!(bufp->syntax & RE_DOT_NEWLINE)) + fastmap['\n'] = fastmap_newline; + + /* Return if we have already set `can_be_null'; if we have, + then the fastmap is irrelevant. Something's wrong here. */ + else if (bufp->can_be_null) + goto done; + + /* Otherwise, have to check alternative paths. */ + break; + } + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + /* All cases after this match the empty string. These end with + `continue'. */ + + + case before_dot: + case at_dot: + case after_dot: + continue; +#endif /* emacs */ + + + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + case push_dummy_failure: + continue; + + + case jump_n: + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case jump_past_alt: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + if (j > 0) + continue; + + /* Jump backward implies we just went through the body of a + loop and matched nothing. Opcode jumped to should be + `on_failure_jump' or `succeed_n'. Just treat it like an + ordinary jump. For a * loop, it has pushed its failure + point already; if so, discard that as redundant. */ + if ((re_opcode_t) *p != on_failure_jump + && (re_opcode_t) *p != succeed_n) + continue; + + p++; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + + /* If what's on the stack is where we are now, pop it. */ + if (!FAIL_STACK_EMPTY () + && fail_stack.stack[fail_stack.avail - 1].pointer == p) + fail_stack.avail--; + + continue; + + + case on_failure_jump: + case on_failure_keep_string_jump: + handle_on_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + + /* For some patterns, e.g., `(a?)?', `p+j' here points to the + end of the pattern. We don't want to push such a point, + since when we restore it above, entering the switch will + increment `p' past the end of the pattern. We don't need + to push such a point since we obviously won't find any more + fastmap entries beyond `pend'. Such a pattern can match + the null string, though. */ + if (p + j < pend) + { + if (!PUSH_PATTERN_OP (p + j, fail_stack)) + { + RESET_FAIL_STACK (); + return -2; + } + } + else + bufp->can_be_null = 1; + + if (succeed_n_p) + { + EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ + succeed_n_p = false; + } + + continue; + + + case succeed_n: + /* Get to the number of times to succeed. */ + p += 2; + + /* Increment p past the n for when k != 0. */ + EXTRACT_NUMBER_AND_INCR (k, p); + if (k == 0) + { + p -= 4; + succeed_n_p = true; /* Spaghetti code alert. */ + goto handle_on_failure_jump; + } + continue; + + + case set_number_at: + p += 4; + continue; + + + case start_memory: + case stop_memory: + p += 2; + continue; + + + default: + abort (); /* We have listed all the cases. */ + } /* switch *p++ */ + + /* Getting here means we have found the possible starting + characters for one path of the pattern -- and that the empty + string does not match. We need not follow this path further. + Instead, look at the next alternative (remembered on the + stack), or quit if no more. The test at the top of the loop + does these things. */ + path_can_be_null = false; + p = pend; + } /* while p */ + + /* Set `can_be_null' for the last path (also the first path, if the + pattern is empty). */ + bufp->can_be_null |= path_can_be_null; + + done: + RESET_FAIL_STACK (); + return 0; +} /* re_compile_fastmap */ +#ifdef _LIBC +weak_alias (__re_compile_fastmap, re_compile_fastmap) +#endif + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use + this memory for recording register information. STARTS and ENDS + must be allocated using the malloc library routine, and must each + be at least NUM_REGS * sizeof (regoff_t) bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ + +void +re_set_registers (bufp, regs, num_regs, starts, ends) + struct re_pattern_buffer *bufp; + struct re_registers *regs; + unsigned num_regs; + regoff_t *starts, *ends; +{ + if (num_regs) + { + bufp->regs_allocated = REGS_REALLOCATE; + regs->num_regs = num_regs; + regs->start = starts; + regs->end = ends; + } + else + { + bufp->regs_allocated = REGS_UNALLOCATED; + regs->num_regs = 0; + regs->start = regs->end = (regoff_t *) 0; + } +} +#ifdef _LIBC +weak_alias (__re_set_registers, re_set_registers) +#endif + +/* Searching routines. */ + +/* Like re_search_2, below, but only one string is specified, and + doesn't let you say where to stop matching. */ + +int +re_search (bufp, string, size, startpos, range, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (bufp, NULL, 0, string, size, startpos, range, + regs, size); +} +#ifdef _LIBC +weak_alias (__re_search, re_search) +#endif + + +/* Using the compiled pattern in BUFP->buffer, first tries to match the + virtual concatenation of STRING1 and STRING2, starting first at index + STARTPOS, then at STARTPOS + 1, and so on. + + STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. + + RANGE is how far to scan while trying to match. RANGE = 0 means try + only at STARTPOS; in general, the last start tried is STARTPOS + + RANGE. + + In REGS, return the indices of the virtual concatenation of STRING1 + and STRING2 that matched the entire BUFP->buffer and its contained + subexpressions. + + Do not consider matching one past the index STOP in the virtual + concatenation of STRING1 and STRING2. + + We return either the position in the strings at which the match was + found, -1 if no match, or -2 if error (such as failure + stack overflow). */ + +int +re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int startpos; + int range; + struct re_registers *regs; + int stop; +{ + int val; + register char *fastmap = bufp->fastmap; + register RE_TRANSLATE_TYPE translate = bufp->translate; + int total_size = size1 + size2; + int endpos = startpos + range; + + /* Check for out-of-range STARTPOS. */ + if (startpos < 0 || startpos > total_size) + return -1; + + /* Fix up RANGE if it might eventually take us outside + the virtual concatenation of STRING1 and STRING2. + Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE. */ + if (endpos < 0) + range = 0 - startpos; + else if (endpos > total_size) + range = total_size - startpos; + + /* If the search isn't to be a backwards one, don't waste time in a + search for a pattern that must be anchored. */ + if (bufp->used > 0 && range > 0 + && ((re_opcode_t) bufp->buffer[0] == begbuf + /* `begline' is like `begbuf' if it cannot match at newlines. */ + || ((re_opcode_t) bufp->buffer[0] == begline + && !bufp->newline_anchor))) + { + if (startpos > 0) + return -1; + else + range = 1; + } + +#ifdef emacs + /* In a forward search for something that starts with \=. + don't keep searching past point. */ + if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0) + { + range = PT - startpos; + if (range <= 0) + return -1; + } +#endif /* emacs */ + + /* Update the fastmap now if not correct already. */ + if (fastmap && !bufp->fastmap_accurate) + if (re_compile_fastmap (bufp) == -2) + return -2; + + /* Loop through the string, looking for a place to start matching. */ + for (;;) + { + /* If a fastmap is supplied, skip quickly over characters that + cannot be the start of a match. If the pattern can match the + null string, however, we don't need to skip characters; we want + the first null string. */ + if (fastmap && startpos < total_size && !bufp->can_be_null) + { + if (range > 0) /* Searching forwards. */ + { + register const char *d; + register int lim = 0; + int irange = range; + + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + d = (startpos >= size1 ? string2 - size1 : string1) + startpos; + + /* Written out as an if-else to avoid testing `translate' + inside the loop. */ + if (translate) + while (range > lim + && !fastmap[(unsigned char) + translate[(unsigned char) *d++]]) + range--; + else + while (range > lim && !fastmap[(unsigned char) *d++]) + range--; + + startpos += irange - range; + } + else /* Searching backwards. */ + { + register char c = (size1 == 0 || startpos >= size1 + ? string2[startpos - size1] + : string1[startpos]); + + if (!fastmap[(unsigned char) TRANSLATE (c)]) + goto advance; + } + } + + /* If can't match the null string, and that's all we have left, fail. */ + if (range >= 0 && startpos == total_size && fastmap + && !bufp->can_be_null) + return -1; + + val = re_match_2_internal (bufp, string1, size1, string2, size2, + startpos, regs, stop); +#ifndef REGEX_MALLOC +# ifdef C_ALLOCA + alloca (0); +# endif +#endif + + if (val >= 0) + return startpos; + + if (val == -2) + return -2; + + advance: + if (!range) + break; + else if (range > 0) + { + range--; + startpos++; + } + else + { + range++; + startpos--; + } + } + return -1; +} /* re_search_2 */ +#ifdef _LIBC +weak_alias (__re_search_2, re_search_2) +#endif + +/* This converts PTR, a pointer into one of the search strings `string1' + and `string2' into an offset from the beginning of that string. */ +#define POINTER_TO_OFFSET(ptr) \ + (FIRST_STRING_P (ptr) \ + ? ((regoff_t) ((ptr) - string1)) \ + : ((regoff_t) ((ptr) - string2 + size1))) + +/* Macros for dealing with the split strings in re_match_2. */ + +#define MATCHING_IN_FIRST_STRING (dend == end_match_1) + +/* Call before fetching a character with *d. This switches over to + string2 if necessary. */ +#define PREFETCH() \ + while (d == dend) \ + { \ + /* End of string2 => fail. */ \ + if (dend == end_match_2) \ + goto fail; \ + /* End of string1 => advance to string2. */ \ + d = string2; \ + dend = end_match_2; \ + } + + +/* Test if at very beginning or at very end of the virtual concatenation + of `string1' and `string2'. If only one string, it's `string2'. */ +#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) +#define AT_STRINGS_END(d) ((d) == end2) + + +/* Test if D points to a character which is word-constituent. We have + two special cases to check for: if past the end of string1, look at + the first character in string2; and if before the beginning of + string2, look at the last character in string1. */ +#define WORDCHAR_P(d) \ + (SYNTAX ((d) == end1 ? *string2 \ + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ + == Sword) + +/* Disabled due to a compiler bug -- see comment at case wordbound */ +#if 0 +/* Test if the character before D and the one at D differ with respect + to being word-constituent. */ +#define AT_WORD_BOUNDARY(d) \ + (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ + || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) +#endif + +/* Free everything we malloc. */ +#ifdef MATCH_MAY_ALLOCATE +# define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL +# define FREE_VARIABLES() \ + do { \ + REGEX_FREE_STACK (fail_stack.stack); \ + FREE_VAR (regstart); \ + FREE_VAR (regend); \ + FREE_VAR (old_regstart); \ + FREE_VAR (old_regend); \ + FREE_VAR (best_regstart); \ + FREE_VAR (best_regend); \ + FREE_VAR (reg_info); \ + FREE_VAR (reg_dummy); \ + FREE_VAR (reg_info_dummy); \ + } while (0) +#else +# define FREE_VARIABLES() ((void)0) /* Do nothing! But inhibit gcc warning. */ +#endif /* not MATCH_MAY_ALLOCATE */ + +/* These values must meet several constraints. They must not be valid + register values; since we have a limit of 255 registers (because + we use only one byte in the pattern for the register number), we can + use numbers larger than 255. They must differ by 1, because of + NUM_FAILURE_ITEMS above. And the value for the lowest register must + be larger than the value for the highest register, so we do not try + to actually save any registers when none are active. */ +#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH) +#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1) + +/* Matching routines. */ + +#ifndef emacs /* Emacs never uses this. */ +/* re_match is like re_match_2 except it takes only a single string. */ + +int +re_match (bufp, string, size, pos, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, pos; + struct re_registers *regs; +{ + int result = re_match_2_internal (bufp, NULL, 0, string, size, + pos, regs, size); +# ifndef REGEX_MALLOC +# ifdef C_ALLOCA + alloca (0); +# endif +# endif + return result; +} +# ifdef _LIBC +weak_alias (__re_match, re_match) +# endif +#endif /* not emacs */ + +static boolean group_match_null_string_p _RE_ARGS ((unsigned char **p, + unsigned char *end, + register_info_type *reg_info)); +static boolean alt_match_null_string_p _RE_ARGS ((unsigned char *p, + unsigned char *end, + register_info_type *reg_info)); +static boolean common_op_match_null_string_p _RE_ARGS ((unsigned char **p, + unsigned char *end, + register_info_type *reg_info)); +static int bcmp_translate _RE_ARGS ((const char *s1, const char *s2, + int len, char *translate)); + +/* re_match_2 matches the compiled pattern in BUFP against the + the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 + and SIZE2, respectively). We start matching at POS, and stop + matching at STOP. + + If REGS is non-null and the `no_sub' field of BUFP is nonzero, we + store offsets for the substring each group matched in REGS. See the + documentation for exactly how many groups we fill. + + We return -1 if no match, -2 if an internal error (such as the + failure stack overflowing). Otherwise, we return the length of the + matched substring. */ + +int +re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int stop; +{ + int result = re_match_2_internal (bufp, string1, size1, string2, size2, + pos, regs, stop); +#ifndef REGEX_MALLOC +# ifdef C_ALLOCA + alloca (0); +# endif +#endif + return result; +} +#ifdef _LIBC +weak_alias (__re_match_2, re_match_2) +#endif + +/* This is a separate function so that we can force an alloca cleanup + afterwards. */ +static int +re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int stop; +{ + /* General temporaries. */ + int mcnt; + unsigned char *p1; + + /* Just past the end of the corresponding string. */ + const char *end1, *end2; + + /* Pointers into string1 and string2, just past the last characters in + each to consider matching. */ + const char *end_match_1, *end_match_2; + + /* Where we are in the data, and the end of the current string. */ + const char *d, *dend; + + /* Where we are in the pattern, and the end of the pattern. */ + unsigned char *p = bufp->buffer; + register unsigned char *pend = p + bufp->used; + + /* Mark the opcode just after a start_memory, so we can test for an + empty subpattern when we get to the stop_memory. */ + unsigned char *just_past_start_mem = 0; + + /* We use this to map every character in the string. */ + RE_TRANSLATE_TYPE translate = bufp->translate; + + /* Failure point stack. Each place that can handle a failure further + down the line pushes a failure point on this stack. It consists of + restart, regend, and reg_info for all registers corresponding to + the subexpressions we're currently inside, plus the number of such + registers, and, finally, two char *'s. The first char * is where + to resume scanning the pattern; the second one is where to resume + scanning the strings. If the latter is zero, the failure point is + a ``dummy''; if a failure happens and the failure point is a dummy, + it gets discarded and the next next one is tried. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ + fail_stack_type fail_stack; +#endif +#ifdef DEBUG + static unsigned failure_id; + unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; +#endif + +#ifdef REL_ALLOC + /* This holds the pointer to the failure stack, when + it is allocated relocatably. */ + fail_stack_elt_t *failure_stack_ptr; +#endif + + /* We fill all the registers internally, independent of what we + return, for use in backreferences. The number here includes + an element for register zero. */ + size_t num_regs = bufp->re_nsub + 1; + + /* The currently active registers. */ + active_reg_t lowest_active_reg = NO_LOWEST_ACTIVE_REG; + active_reg_t highest_active_reg = NO_HIGHEST_ACTIVE_REG; + + /* Information on the contents of registers. These are pointers into + the input strings; they record just what was matched (on this + attempt) by a subexpression part of the pattern, that is, the + regnum-th regstart pointer points to where in the pattern we began + matching and the regnum-th regend points to right after where we + stopped matching the regnum-th subexpression. (The zeroth register + keeps track of what the whole pattern matches.) */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const char **regstart, **regend; +#endif + + /* If a group that's operated upon by a repetition operator fails to + match anything, then the register for its start will need to be + restored because it will have been set to wherever in the string we + are when we last see its open-group operator. Similarly for a + register's end. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const char **old_regstart, **old_regend; +#endif + + /* The is_active field of reg_info helps us keep track of which (possibly + nested) subexpressions we are currently in. The matched_something + field of reg_info[reg_num] helps us tell whether or not we have + matched any of the pattern so far this time through the reg_num-th + subexpression. These two fields get reset each time through any + loop their register is in. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ + register_info_type *reg_info; +#endif + + /* The following record the register info as found in the above + variables when we find a match better than any we've seen before. + This happens as we backtrack through the failure points, which in + turn happens only if we have not yet matched the entire string. */ + unsigned best_regs_set = false; +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const char **best_regstart, **best_regend; +#endif + + /* Logically, this is `best_regend[0]'. But we don't want to have to + allocate space for that if we're not allocating space for anything + else (see below). Also, we never need info about register 0 for + any of the other register vectors, and it seems rather a kludge to + treat `best_regend' differently than the rest. So we keep track of + the end of the best match so far in a separate variable. We + initialize this to NULL so that when we backtrack the first time + and need to test it, it's not garbage. */ + const char *match_end = NULL; + + /* This helps SET_REGS_MATCHED avoid doing redundant work. */ + int set_regs_matched_done = 0; + + /* Used when we pop values we don't care about. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const char **reg_dummy; + register_info_type *reg_info_dummy; +#endif + +#ifdef DEBUG + /* Counts the total number of registers pushed. */ + unsigned num_regs_pushed = 0; +#endif + + DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); + + INIT_FAIL_STACK (); + +#ifdef MATCH_MAY_ALLOCATE + /* Do not bother to initialize all the register variables if there are + no groups in the pattern, as it takes a fair amount of time. If + there are groups, we include space for register 0 (the whole + pattern), even though we never use it, since it simplifies the + array indexing. We should fix this. */ + if (bufp->re_nsub) + { + regstart = REGEX_TALLOC (num_regs, const char *); + regend = REGEX_TALLOC (num_regs, const char *); + old_regstart = REGEX_TALLOC (num_regs, const char *); + old_regend = REGEX_TALLOC (num_regs, const char *); + best_regstart = REGEX_TALLOC (num_regs, const char *); + best_regend = REGEX_TALLOC (num_regs, const char *); + reg_info = REGEX_TALLOC (num_regs, register_info_type); + reg_dummy = REGEX_TALLOC (num_regs, const char *); + reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type); + + if (!(regstart && regend && old_regstart && old_regend && reg_info + && best_regstart && best_regend && reg_dummy && reg_info_dummy)) + { + FREE_VARIABLES (); + return -2; + } + } + else + { + /* We must initialize all our variables to NULL, so that + `FREE_VARIABLES' doesn't try to free them. */ + regstart = regend = old_regstart = old_regend = best_regstart + = best_regend = reg_dummy = NULL; + reg_info = reg_info_dummy = (register_info_type *) NULL; + } +#endif /* MATCH_MAY_ALLOCATE */ + + /* The starting position is bogus. */ + if (pos < 0 || pos > size1 + size2) + { + FREE_VARIABLES (); + return -1; + } + + /* Initialize subexpression text positions to -1 to mark ones that no + start_memory/stop_memory has been seen for. Also initialize the + register information struct. */ + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) + { + regstart[mcnt] = regend[mcnt] + = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; + + REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; + IS_ACTIVE (reg_info[mcnt]) = 0; + MATCHED_SOMETHING (reg_info[mcnt]) = 0; + EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; + } + + /* We move `string1' into `string2' if the latter's empty -- but not if + `string1' is null. */ + if (size2 == 0 && string1 != NULL) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings. */ + if (stop <= size1) + { + end_match_1 = string1 + stop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + stop - size1; + } + + /* `p' scans through the pattern as `d' scans through the data. + `dend' is the end of the input string that `d' points within. `d' + is advanced into the following input string whenever necessary, but + this happens before fetching; therefore, at the beginning of the + loop, `d' can be pointing at the end of a string, but it cannot + equal `string2'. */ + if (size1 > 0 && pos <= size1) + { + d = string1 + pos; + dend = end_match_1; + } + else + { + d = string2 + pos - size1; + dend = end_match_2; + } + + DEBUG_PRINT1 ("The compiled pattern is:\n"); + DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); + DEBUG_PRINT1 ("The string to match is: `"); + DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); + DEBUG_PRINT1 ("'\n"); + + /* This loops over pattern commands. It exits by returning from the + function if the match is complete, or it drops through if the match + fails at this starting point in the input data. */ + for (;;) + { +#ifdef _LIBC + DEBUG_PRINT2 ("\n%p: ", p); +#else + DEBUG_PRINT2 ("\n0x%x: ", p); +#endif + + if (p == pend) + { /* End of pattern means we might have succeeded. */ + DEBUG_PRINT1 ("end of pattern ... "); + + /* If we haven't matched the entire string, and we want the + longest match, try backtracking. */ + if (d != end_match_2) + { + /* 1 if this match ends in the same string (string1 or string2) + as the best previous match. */ + boolean same_str_p = (FIRST_STRING_P (match_end) + == MATCHING_IN_FIRST_STRING); + /* 1 if this match is the best seen so far. */ + boolean best_match_p; + + /* AIX compiler got confused when this was combined + with the previous declaration. */ + if (same_str_p) + best_match_p = d > match_end; + else + best_match_p = !MATCHING_IN_FIRST_STRING; + + DEBUG_PRINT1 ("backtracking.\n"); + + if (!FAIL_STACK_EMPTY ()) + { /* More failure points to try. */ + + /* If exceeds best match so far, save it. */ + if (!best_regs_set || best_match_p) + { + best_regs_set = true; + match_end = d; + + DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); + + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) + { + best_regstart[mcnt] = regstart[mcnt]; + best_regend[mcnt] = regend[mcnt]; + } + } + goto fail; + } + + /* If no failure points, don't restore garbage. And if + last match is real best match, don't restore second + best one. */ + else if (best_regs_set && !best_match_p) + { + restore_best_regs: + /* Restore best match. It may happen that `dend == + end_match_1' while the restored d is in string2. + For example, the pattern `x.*y.*z' against the + strings `x-' and `y-z-', if the two strings are + not consecutive in memory. */ + DEBUG_PRINT1 ("Restoring best registers.\n"); + + d = match_end; + dend = ((d >= string1 && d <= end1) + ? end_match_1 : end_match_2); + + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) + { + regstart[mcnt] = best_regstart[mcnt]; + regend[mcnt] = best_regend[mcnt]; + } + } + } /* d != end_match_2 */ + + succeed_label: + DEBUG_PRINT1 ("Accepting match.\n"); + + /* If caller wants register contents data back, do it. */ + if (regs && !bufp->no_sub) + { + /* Have the register data arrays been allocated? */ + if (bufp->regs_allocated == REGS_UNALLOCATED) + { /* No. So allocate them with malloc. We need one + extra element beyond `num_regs' for the `-1' marker + GNU code uses. */ + regs->num_regs = MAX (RE_NREGS, num_regs + 1); + regs->start = TALLOC (regs->num_regs, regoff_t); + regs->end = TALLOC (regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + { + FREE_VARIABLES (); + return -2; + } + bufp->regs_allocated = REGS_REALLOCATE; + } + else if (bufp->regs_allocated == REGS_REALLOCATE) + { /* Yes. If we need more elements than were already + allocated, reallocate them. If we need fewer, just + leave it alone. */ + if (regs->num_regs < num_regs + 1) + { + regs->num_regs = num_regs + 1; + RETALLOC (regs->start, regs->num_regs, regoff_t); + RETALLOC (regs->end, regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + { + FREE_VARIABLES (); + return -2; + } + } + } + else + { + /* These braces fend off a "empty body in an else-statement" + warning under GCC when assert expands to nothing. */ + assert (bufp->regs_allocated == REGS_FIXED); + } + + /* Convert the pointer data in `regstart' and `regend' to + indices. Register zero has to be set differently, + since we haven't kept track of any info for it. */ + if (regs->num_regs > 0) + { + regs->start[0] = pos; + regs->end[0] = (MATCHING_IN_FIRST_STRING + ? ((regoff_t) (d - string1)) + : ((regoff_t) (d - string2 + size1))); + } + + /* Go through the first `min (num_regs, regs->num_regs)' + registers, since that is all we initialized. */ + for (mcnt = 1; (unsigned) mcnt < MIN (num_regs, regs->num_regs); + mcnt++) + { + if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) + regs->start[mcnt] = regs->end[mcnt] = -1; + else + { + regs->start[mcnt] + = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]); + regs->end[mcnt] + = (regoff_t) POINTER_TO_OFFSET (regend[mcnt]); + } + } + + /* If the regs structure we return has more elements than + were in the pattern, set the extra elements to -1. If + we (re)allocated the registers, this is the case, + because we always allocate enough to have at least one + -1 at the end. */ + for (mcnt = num_regs; (unsigned) mcnt < regs->num_regs; mcnt++) + regs->start[mcnt] = regs->end[mcnt] = -1; + } /* regs && !bufp->no_sub */ + + DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", + nfailure_points_pushed, nfailure_points_popped, + nfailure_points_pushed - nfailure_points_popped); + DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); + + mcnt = d - pos - (MATCHING_IN_FIRST_STRING + ? string1 + : string2 - size1); + + DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); + + FREE_VARIABLES (); + return mcnt; + } + + /* Otherwise match next pattern command. */ + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) + { + /* Ignore these. Used to ignore the n of succeed_n's which + currently have n == 0. */ + case no_op: + DEBUG_PRINT1 ("EXECUTING no_op.\n"); + break; + + case succeed: + DEBUG_PRINT1 ("EXECUTING succeed.\n"); + goto succeed_label; + + /* Match the next n pattern characters exactly. The following + byte in the pattern defines n, and the n bytes after that + are the characters to match. */ + case exactn: + mcnt = *p++; + DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); + + /* This is written out as an if-else so we don't waste time + testing `translate' inside the loop. */ + if (translate) + { + do + { + PREFETCH (); + if ((unsigned char) translate[(unsigned char) *d++] + != (unsigned char) *p++) + goto fail; + } + while (--mcnt); + } + else + { + do + { + PREFETCH (); + if (*d++ != (char) *p++) goto fail; + } + while (--mcnt); + } + SET_REGS_MATCHED (); + break; + + + /* Match any character except possibly a newline or a null. */ + case anychar: + DEBUG_PRINT1 ("EXECUTING anychar.\n"); + + PREFETCH (); + + if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') + || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) + goto fail; + + SET_REGS_MATCHED (); + DEBUG_PRINT2 (" Matched `%d'.\n", *d); + d++; + break; + + + case charset: + case charset_not: + { + register unsigned char c; + boolean not = (re_opcode_t) *(p - 1) == charset_not; + + DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); + + PREFETCH (); + c = TRANSLATE (*d); /* The character to match. */ + + /* Cast to `unsigned' instead of `unsigned char' in case the + bit list is a full 32 bytes long. */ + if (c < (unsigned) (*p * BYTEWIDTH) + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + p += 1 + *p; + + if (!not) goto fail; + + SET_REGS_MATCHED (); + d++; + break; + } + + + /* The beginning of a group is represented by start_memory. + The arguments are the register number in the next byte, and the + number of groups inner to this one in the next. The text + matched within the group is recorded (in the internal + registers data structure) under the register number. */ + case start_memory: + DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]); + + /* Find out if this group can match the empty string. */ + p1 = p; /* To send to group_match_null_string_p. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[*p]) + = group_match_null_string_p (&p1, pend, reg_info); + + /* Save the position in the string where we were the last time + we were at this open-group operator in case the group is + operated upon by a repetition operator, e.g., with `(a*)*b' + against `ab'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regstart[*p]) ? d : regstart[*p] + : regstart[*p]; + DEBUG_PRINT2 (" old_regstart: %d\n", + POINTER_TO_OFFSET (old_regstart[*p])); + + regstart[*p] = d; + DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); + + IS_ACTIVE (reg_info[*p]) = 1; + MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* Clear this whenever we change the register activity status. */ + set_regs_matched_done = 0; + + /* This is the new highest active register. */ + highest_active_reg = *p; + + /* If nothing was active before, this is the new lowest active + register. */ + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *p; + + /* Move past the register number and inner group count. */ + p += 2; + just_past_start_mem = p; + + break; + + + /* The stop_memory opcode represents the end of a group. Its + arguments are the same as start_memory's: the register + number, and the number of inner groups. */ + case stop_memory: + DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]); + + /* We need to save the string position the last time we were at + this close-group operator in case the group is operated + upon by a repetition operator, e.g., with `((a*)*(b*)*)*' + against `aba'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regend[*p]) ? d : regend[*p] + : regend[*p]; + DEBUG_PRINT2 (" old_regend: %d\n", + POINTER_TO_OFFSET (old_regend[*p])); + + regend[*p] = d; + DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); + + /* This register isn't active anymore. */ + IS_ACTIVE (reg_info[*p]) = 0; + + /* Clear this whenever we change the register activity status. */ + set_regs_matched_done = 0; + + /* If this was the only register active, nothing is active + anymore. */ + if (lowest_active_reg == highest_active_reg) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + { /* We must scan for the new highest active register, since + it isn't necessarily one less than now: consider + (a(b)c(d(e)f)g). When group 3 ends, after the f), the + new highest active register is 1. */ + unsigned char r = *p - 1; + while (r > 0 && !IS_ACTIVE (reg_info[r])) + r--; + + /* If we end up at register zero, that means that we saved + the registers as the result of an `on_failure_jump', not + a `start_memory', and we jumped to past the innermost + `stop_memory'. For example, in ((.)*) we save + registers 1 and 2 as a result of the *, but when we pop + back to the second ), we are at the stop_memory 1. + Thus, nothing is active. */ + if (r == 0) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + highest_active_reg = r; + } + + /* If just failed to match something this time around with a + group that's operated on by a repetition operator, try to + force exit from the ``loop'', and restore the register + information for this group that we had before trying this + last match. */ + if ((!MATCHED_SOMETHING (reg_info[*p]) + || just_past_start_mem == p - 1) + && (p + 2) < pend) + { + boolean is_a_jump_n = false; + + p1 = p + 2; + mcnt = 0; + switch ((re_opcode_t) *p1++) + { + case jump_n: + is_a_jump_n = true; + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (is_a_jump_n) + p1 += 2; + break; + + default: + /* do nothing */ ; + } + p1 += mcnt; + + /* If the next operation is a jump backwards in the pattern + to an on_failure_jump right before the start_memory + corresponding to this stop_memory, exit from the loop + by forcing a failure after pushing on the stack the + on_failure_jump's jump in the pattern, and d. */ + if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump + && (re_opcode_t) p1[3] == start_memory && p1[4] == *p) + { + /* If this group ever matched anything, then restore + what its registers were before trying this last + failed match, e.g., with `(a*)*b' against `ab' for + regstart[1], and, e.g., with `((a*)*(b*)*)*' + against `aba' for regend[3]. + + Also restore the registers for inner groups for, + e.g., `((a*)(b*))*' against `aba' (register 3 would + otherwise get trashed). */ + + if (EVER_MATCHED_SOMETHING (reg_info[*p])) + { + unsigned r; + + EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* Restore this and inner groups' (if any) registers. */ + for (r = *p; r < (unsigned) *p + (unsigned) *(p + 1); + r++) + { + regstart[r] = old_regstart[r]; + + /* xx why this test? */ + if (old_regend[r] >= regstart[r]) + regend[r] = old_regend[r]; + } + } + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + PUSH_FAILURE_POINT (p1 + mcnt, d, -2); + + goto fail; + } + } + + /* Move past the register number and the inner group count. */ + p += 2; + break; + + + /* \ has been turned into a `duplicate' command which is + followed by the numeric value of as the register number. */ + case duplicate: + { + register const char *d2, *dend2; + int regno = *p++; /* Get which register to match against. */ + DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); + + /* Can't back reference a group which we've never matched. */ + if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) + goto fail; + + /* Where in input to try to start matching. */ + d2 = regstart[regno]; + + /* Where to stop matching; if both the place to start and + the place to stop matching are in the same string, then + set to the place to stop, otherwise, for now have to use + the end of the first string. */ + + dend2 = ((FIRST_STRING_P (regstart[regno]) + == FIRST_STRING_P (regend[regno])) + ? regend[regno] : end_match_1); + for (;;) + { + /* If necessary, advance to next segment in register + contents. */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + + /* End of string1 => advance to string2. */ + d2 = string2; + dend2 = regend[regno]; + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* If necessary, advance to next segment in data. */ + PREFETCH (); + + /* How many characters left in this segment to match. */ + mcnt = dend - d; + + /* Want how many consecutive characters we can match in + one shot, so, if necessary, adjust the count. */ + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + + /* Compare that many; failure if mismatch, else move + past them. */ + if (translate + ? bcmp_translate (d, d2, mcnt, translate) + : memcmp (d, d2, mcnt)) + goto fail; + d += mcnt, d2 += mcnt; + + /* Do this because we've match some characters. */ + SET_REGS_MATCHED (); + } + } + break; + + + /* begline matches the empty string at the beginning of the string + (unless `not_bol' is set in `bufp'), and, if + `newline_anchor' is set, after newlines. */ + case begline: + DEBUG_PRINT1 ("EXECUTING begline.\n"); + + if (AT_STRINGS_BEG (d)) + { + if (!bufp->not_bol) break; + } + else if (d[-1] == '\n' && bufp->newline_anchor) + { + break; + } + /* In all other cases, we fail. */ + goto fail; + + + /* endline is the dual of begline. */ + case endline: + DEBUG_PRINT1 ("EXECUTING endline.\n"); + + if (AT_STRINGS_END (d)) + { + if (!bufp->not_eol) break; + } + + /* We have to ``prefetch'' the next character. */ + else if ((d == end1 ? *string2 : *d) == '\n' + && bufp->newline_anchor) + { + break; + } + goto fail; + + + /* Match at the very beginning of the data. */ + case begbuf: + DEBUG_PRINT1 ("EXECUTING begbuf.\n"); + if (AT_STRINGS_BEG (d)) + break; + goto fail; + + + /* Match at the very end of the data. */ + case endbuf: + DEBUG_PRINT1 ("EXECUTING endbuf.\n"); + if (AT_STRINGS_END (d)) + break; + goto fail; + + + /* on_failure_keep_string_jump is used to optimize `.*\n'. It + pushes NULL as the value for the string on the stack. Then + `pop_failure_point' will keep the current value for the + string, instead of restoring it. To see why, consider + matching `foo\nbar' against `.*\n'. The .* matches the foo; + then the . fails against the \n. But the next thing we want + to do is match the \n against the \n; if we restored the + string value, we would be back at the foo. + + Because this is used only in specific cases, we don't need to + check all the things that `on_failure_jump' does, to make + sure the right things get saved on the stack. Hence we don't + share its code. The only reason to push anything on the + stack at all is that otherwise we would have to change + `anychar's code to do something besides goto fail in this + case; that seems worse than this. */ + case on_failure_keep_string_jump: + DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); +#ifdef _LIBC + DEBUG_PRINT3 (" %d (to %p):\n", mcnt, p + mcnt); +#else + DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); +#endif + + PUSH_FAILURE_POINT (p + mcnt, NULL, -2); + break; + + + /* Uses of on_failure_jump: + + Each alternative starts with an on_failure_jump that points + to the beginning of the next alternative. Each alternative + except the last ends with a jump that in effect jumps past + the rest of the alternatives. (They really jump to the + ending jump of the following alternative, because tensioning + these jumps is a hassle.) + + Repeats start with an on_failure_jump that points past both + the repetition text and either the following jump or + pop_failure_jump back to this on_failure_jump. */ + case on_failure_jump: + on_failure: + DEBUG_PRINT1 ("EXECUTING on_failure_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); +#ifdef _LIBC + DEBUG_PRINT3 (" %d (to %p)", mcnt, p + mcnt); +#else + DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); +#endif + + /* If this on_failure_jump comes right before a group (i.e., + the original * applied to a group), save the information + for that group and all inner ones, so that if we fail back + to this point, the group's information will be correct. + For example, in \(a*\)*\1, we need the preceding group, + and in \(zz\(a*\)b*\)\2, we need the inner group. */ + + /* We can't use `p' to check ahead because we push + a failure point to `p + mcnt' after we do this. */ + p1 = p; + + /* We need to skip no_op's before we look for the + start_memory in case this on_failure_jump is happening as + the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 + against aba. */ + while (p1 < pend && (re_opcode_t) *p1 == no_op) + p1++; + + if (p1 < pend && (re_opcode_t) *p1 == start_memory) + { + /* We have a new highest active register now. This will + get reset at the start_memory we are about to get to, + but we will have saved all the registers relevant to + this repetition op, as described above. */ + highest_active_reg = *(p1 + 1) + *(p1 + 2); + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *(p1 + 1); + } + + DEBUG_PRINT1 (":\n"); + PUSH_FAILURE_POINT (p + mcnt, d, -2); + break; + + + /* A smart repeat ends with `maybe_pop_jump'. + We change it to either `pop_failure_jump' or `jump'. */ + case maybe_pop_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); + { + register unsigned char *p2 = p; + + /* Compare the beginning of the repeat with what in the + pattern follows its end. If we can establish that there + is nothing that they would both match, i.e., that we + would have to backtrack because of (as in, e.g., `a*a') + then we can change to pop_failure_jump, because we'll + never have to backtrack. + + This is not true in the case of alternatives: in + `(a|ab)*' we do need to backtrack to the `ab' alternative + (e.g., if the string was `ab'). But instead of trying to + detect that here, the alternative has put on a dummy + failure point which is what we will end up popping. */ + + /* Skip over open/close-group commands. + If what follows this loop is a ...+ construct, + look at what begins its body, since we will have to + match at least one of that. */ + while (1) + { + if (p2 + 2 < pend + && ((re_opcode_t) *p2 == stop_memory + || (re_opcode_t) *p2 == start_memory)) + p2 += 3; + else if (p2 + 6 < pend + && (re_opcode_t) *p2 == dummy_failure_jump) + p2 += 6; + else + break; + } + + p1 = p + mcnt; + /* p1[0] ... p1[2] are the `on_failure_jump' corresponding + to the `maybe_finalize_jump' of this case. Examine what + follows. */ + + /* If we're at the end of the pattern, we can change. */ + if (p2 == pend) + { + /* Consider what happens when matching ":\(.*\)" + against ":/". I don't really understand this code + yet. */ + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 + (" End of pattern: change to `pop_failure_jump'.\n"); + } + + else if ((re_opcode_t) *p2 == exactn + || (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) + { + register unsigned char c + = *p2 == (unsigned char) endline ? '\n' : p2[2]; + + if ((re_opcode_t) p1[3] == exactn && p1[5] != c) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", + c, p1[5]); + } + + else if ((re_opcode_t) p1[3] == charset + || (re_opcode_t) p1[3] == charset_not) + { + int not = (re_opcode_t) p1[3] == charset_not; + + if (c < (unsigned char) (p1[4] * BYTEWIDTH) + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + /* `not' is equal to 1 if c would match, which means + that we can't change to pop_failure_jump. */ + if (!not) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + } + else if ((re_opcode_t) *p2 == charset) + { +#ifdef DEBUG + register unsigned char c + = *p2 == (unsigned char) endline ? '\n' : p2[2]; +#endif + +#if 0 + if ((re_opcode_t) p1[3] == exactn + && ! ((int) p2[1] * BYTEWIDTH > (int) p1[5] + && (p2[2 + p1[5] / BYTEWIDTH] + & (1 << (p1[5] % BYTEWIDTH))))) +#else + if ((re_opcode_t) p1[3] == exactn + && ! ((int) p2[1] * BYTEWIDTH > (int) p1[4] + && (p2[2 + p1[4] / BYTEWIDTH] + & (1 << (p1[4] % BYTEWIDTH))))) +#endif + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", + c, p1[5]); + } + + else if ((re_opcode_t) p1[3] == charset_not) + { + int idx; + /* We win if the charset_not inside the loop + lists every character listed in the charset after. */ + for (idx = 0; idx < (int) p2[1]; idx++) + if (! (p2[2 + idx] == 0 + || (idx < (int) p1[4] + && ((p2[2 + idx] & ~ p1[5 + idx]) == 0)))) + break; + + if (idx == p2[1]) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + else if ((re_opcode_t) p1[3] == charset) + { + int idx; + /* We win if the charset inside the loop + has no overlap with the one after the loop. */ + for (idx = 0; + idx < (int) p2[1] && idx < (int) p1[4]; + idx++) + if ((p2[2 + idx] & p1[5 + idx]) != 0) + break; + + if (idx == p2[1] || idx == p1[4]) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + } + } + p -= 2; /* Point at relative address again. */ + if ((re_opcode_t) p[-1] != pop_failure_jump) + { + p[-1] = (unsigned char) jump; + DEBUG_PRINT1 (" Match => jump.\n"); + goto unconditional_jump; + } + /* Note fall through. */ + + + /* The end of a simple repeat has a pop_failure_jump back to + its matching on_failure_jump, where the latter will push a + failure point. The pop_failure_jump takes off failure + points put on by this pop_failure_jump's matching + on_failure_jump; we got through the pattern to here from the + matching on_failure_jump, so didn't fail. */ + case pop_failure_jump: + { + /* We need to pass separate storage for the lowest and + highest registers, even though we don't care about the + actual values. Otherwise, we will restore only one + register from the stack, since lowest will == highest in + `pop_failure_point'. */ + active_reg_t dummy_low_reg, dummy_high_reg; + unsigned char *pdummy; + const char *sdummy; + + DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); + POP_FAILURE_POINT (sdummy, pdummy, + dummy_low_reg, dummy_high_reg, + reg_dummy, reg_dummy, reg_info_dummy); + } + /* Note fall through. */ + + unconditional_jump: +#ifdef _LIBC + DEBUG_PRINT2 ("\n%p: ", p); +#else + DEBUG_PRINT2 ("\n0x%x: ", p); +#endif + /* Note fall through. */ + + /* Unconditionally jump (without popping any failure points). */ + case jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ + DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); + p += mcnt; /* Do the jump. */ +#ifdef _LIBC + DEBUG_PRINT2 ("(to %p).\n", p); +#else + DEBUG_PRINT2 ("(to 0x%x).\n", p); +#endif + break; + + + /* We need this opcode so we can detect where alternatives end + in `group_match_null_string_p' et al. */ + case jump_past_alt: + DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); + goto unconditional_jump; + + + /* Normally, the on_failure_jump pushes a failure point, which + then gets popped at pop_failure_jump. We will end up at + pop_failure_jump, also, and with a pattern of, say, `a+', we + are skipping over the on_failure_jump, so we have to push + something meaningless for pop_failure_jump to pop. */ + case dummy_failure_jump: + DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); + /* It doesn't matter what we push for the string here. What + the code at `fail' tests is the value for the pattern. */ + PUSH_FAILURE_POINT (NULL, NULL, -2); + goto unconditional_jump; + + + /* At the end of an alternative, we need to push a dummy failure + point in case we are followed by a `pop_failure_jump', because + we don't want the failure point for the alternative to be + popped. For example, matching `(a|ab)*' against `aab' + requires that we match the `ab' alternative. */ + case push_dummy_failure: + DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); + /* See comments just above at `dummy_failure_jump' about the + two zeroes. */ + PUSH_FAILURE_POINT (NULL, NULL, -2); + break; + + /* Have to succeed matching what follows at least n times. + After that, handle like `on_failure_jump'. */ + case succeed_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); + + assert (mcnt >= 0); + /* Originally, this is how many times we HAVE to succeed. */ + if (mcnt > 0) + { + mcnt--; + p += 2; + STORE_NUMBER_AND_INCR (p, mcnt); +#ifdef _LIBC + DEBUG_PRINT3 (" Setting %p to %d.\n", p - 2, mcnt); +#else + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p - 2, mcnt); +#endif + } + else if (mcnt == 0) + { +#ifdef _LIBC + DEBUG_PRINT2 (" Setting two bytes from %p to no_op.\n", p+2); +#else + DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2); +#endif + p[2] = (unsigned char) no_op; + p[3] = (unsigned char) no_op; + goto on_failure; + } + break; + + case jump_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); + + /* Originally, this is how many times we CAN jump. */ + if (mcnt) + { + mcnt--; + STORE_NUMBER (p + 2, mcnt); +#ifdef _LIBC + DEBUG_PRINT3 (" Setting %p to %d.\n", p + 2, mcnt); +#else + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p + 2, mcnt); +#endif + goto unconditional_jump; + } + /* If don't have to jump any more, skip over the rest of command. */ + else + p += 4; + break; + + case set_number_at: + { + DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p1 = p + mcnt; + EXTRACT_NUMBER_AND_INCR (mcnt, p); +#ifdef _LIBC + DEBUG_PRINT3 (" Setting %p to %d.\n", p1, mcnt); +#else + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); +#endif + STORE_NUMBER (p1, mcnt); + break; + } + +#if 0 + /* The DEC Alpha C compiler 3.x generates incorrect code for the + test WORDCHAR_P (d - 1) != WORDCHAR_P (d) in the expansion of + AT_WORD_BOUNDARY, so this code is disabled. Expanding the + macro and introducing temporary variables works around the bug. */ + + case wordbound: + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + break; + goto fail; + + case notwordbound: + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + goto fail; + break; +#else + case wordbound: + { + boolean prevchar, thischar; + + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) + break; + + prevchar = WORDCHAR_P (d - 1); + thischar = WORDCHAR_P (d); + if (prevchar != thischar) + break; + goto fail; + } + + case notwordbound: + { + boolean prevchar, thischar; + + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) + goto fail; + + prevchar = WORDCHAR_P (d - 1); + thischar = WORDCHAR_P (d); + if (prevchar != thischar) + goto fail; + break; + } +#endif + + case wordbeg: + DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); + if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) + break; + goto fail; + + case wordend: + DEBUG_PRINT1 ("EXECUTING wordend.\n"); + if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) + && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) + break; + goto fail; + +#ifdef emacs + case before_dot: + DEBUG_PRINT1 ("EXECUTING before_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) >= point) + goto fail; + break; + + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) != point) + goto fail; + break; + + case after_dot: + DEBUG_PRINT1 ("EXECUTING after_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) <= point) + goto fail; + break; + + case syntaxspec: + DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchsyntax; + + case wordchar: + DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); + mcnt = (int) Sword; + matchsyntax: + PREFETCH (); + /* Can't use *d++ here; SYNTAX may be an unsafe macro. */ + d++; + if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + + case notsyntaxspec: + DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchnotsyntax; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); + mcnt = (int) Sword; + matchnotsyntax: + PREFETCH (); + /* Can't use *d++ here; SYNTAX may be an unsafe macro. */ + d++; + if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + +#else /* not emacs */ + case wordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); + PREFETCH (); + if (!WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); + PREFETCH (); + if (WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; +#endif /* not emacs */ + + default: + abort (); + } + continue; /* Successfully executed one pattern command; keep going. */ + + + /* We goto here if a matching operation fails. */ + fail: + if (!FAIL_STACK_EMPTY ()) + { /* A restart point is known. Restore to that state. */ + DEBUG_PRINT1 ("\nFAIL:\n"); + POP_FAILURE_POINT (d, p, + lowest_active_reg, highest_active_reg, + regstart, regend, reg_info); + + /* If this failure point is a dummy, try the next one. */ + if (!p) + goto fail; + + /* If we failed to the end of the pattern, don't examine *p. */ + assert (p <= pend); + if (p < pend) + { + boolean is_a_jump_n = false; + + /* If failed to a backwards jump that's part of a repetition + loop, need to pop this failure point and use the next one. */ + switch ((re_opcode_t) *p) + { + case jump_n: + is_a_jump_n = true; + case maybe_pop_jump: + case pop_failure_jump: + case jump: + p1 = p + 1; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + + if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) + || (!is_a_jump_n + && (re_opcode_t) *p1 == on_failure_jump)) + goto fail; + break; + default: + /* do nothing */ ; + } + } + + if (d >= string1 && d <= end1) + dend = end_match_1; + } + else + break; /* Matching at this starting point really fails. */ + } /* for (;;) */ + + if (best_regs_set) + goto restore_best_regs; + + FREE_VARIABLES (); + + return -1; /* Failure to match. */ +} /* re_match_2 */ + +/* Subroutine definitions for re_match_2. */ + + +/* We are passed P pointing to a register number after a start_memory. + + Return true if the pattern up to the corresponding stop_memory can + match the empty string, and false otherwise. + + If we find the matching stop_memory, sets P to point to one past its number. + Otherwise, sets P to an undefined byte less than or equal to END. + + We don't handle duplicates properly (yet). */ + +static boolean +group_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + /* Point to after the args to the start_memory. */ + unsigned char *p1 = *p + 2; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and return true or + false, as appropriate, when we get to one that can't, or to the + matching stop_memory. */ + + switch ((re_opcode_t) *p1) + { + /* Could be either a loop or a series of alternatives. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + /* If the next operation is not a jump backwards in the + pattern. */ + + if (mcnt >= 0) + { + /* Go through the on_failure_jumps of the alternatives, + seeing if any of the alternatives cannot match nothing. + The last alternative starts with only a jump, + whereas the rest start with on_failure_jump and end + with a jump, e.g., here is the pattern for `a|b|c': + + /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 + /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 + /exactn/1/c + + So, we have to first go through the first (n-1) + alternatives and then deal with the last one separately. */ + + + /* Deal with the first (n-1) alternatives, which start + with an on_failure_jump (see above) that jumps to right + past a jump_past_alt. */ + + while ((re_opcode_t) p1[mcnt-3] == jump_past_alt) + { + /* `mcnt' holds how many bytes long the alternative + is, including the ending `jump_past_alt' and + its number. */ + + if (!alt_match_null_string_p (p1, p1 + mcnt - 3, + reg_info)) + return false; + + /* Move to right after this alternative, including the + jump_past_alt. */ + p1 += mcnt; + + /* Break if it's the beginning of an n-th alternative + that doesn't begin with an on_failure_jump. */ + if ((re_opcode_t) *p1 != on_failure_jump) + break; + + /* Still have to check that it's not an n-th + alternative that starts with an on_failure_jump. */ + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if ((re_opcode_t) p1[mcnt-3] != jump_past_alt) + { + /* Get to the beginning of the n-th alternative. */ + p1 -= 3; + break; + } + } + + /* Deal with the last alternative: go back and get number + of the `jump_past_alt' just before it. `mcnt' contains + the length of the alternative. */ + EXTRACT_NUMBER (mcnt, p1 - 2); + + if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) + return false; + + p1 += mcnt; /* Get past the n-th alternative. */ + } /* if mcnt > 0 */ + break; + + + case stop_memory: + assert (p1[1] == **p); + *p = p1 + 2; + return true; + + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return false; +} /* group_match_null_string_p */ + + +/* Similar to group_match_null_string_p, but doesn't deal with alternatives: + It expects P to be the first byte of a single alternative and END one + byte past the last. The alternative can contain groups. */ + +static boolean +alt_match_null_string_p (p, end, reg_info) + unsigned char *p, *end; + register_info_type *reg_info; +{ + int mcnt; + unsigned char *p1 = p; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and break when we get + to one that can't. */ + + switch ((re_opcode_t) *p1) + { + /* It's a loop. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + break; + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return true; +} /* alt_match_null_string_p */ + + +/* Deals with the ops common to group_match_null_string_p and + alt_match_null_string_p. + + Sets P to one after the op and its arguments, if any. */ + +static boolean +common_op_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + boolean ret; + int reg_no; + unsigned char *p1 = *p; + + switch ((re_opcode_t) *p1++) + { + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbeg: + case wordend: + case wordbound: + case notwordbound: +#ifdef emacs + case before_dot: + case at_dot: + case after_dot: +#endif + break; + + case start_memory: + reg_no = *p1; + assert (reg_no > 0 && reg_no <= MAX_REGNUM); + ret = group_match_null_string_p (&p1, end, reg_info); + + /* Have to set this here in case we're checking a group which + contains a group and a back reference to it. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; + + if (!ret) + return false; + break; + + /* If this is an optimized succeed_n for zero times, make the jump. */ + case jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (mcnt >= 0) + p1 += mcnt; + else + return false; + break; + + case succeed_n: + /* Get to the number of times to succeed. */ + p1 += 2; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + if (mcnt == 0) + { + p1 -= 4; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + } + else + return false; + break; + + case duplicate: + if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) + return false; + break; + + case set_number_at: + p1 += 4; + + default: + /* All other opcodes mean we cannot match the empty string. */ + return false; + } + + *p = p1; + return true; +} /* common_op_match_null_string_p */ + + +/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN + bytes; nonzero otherwise. */ + +static int +bcmp_translate (s1, s2, len, translate) + const char *s1, *s2; + register int len; + RE_TRANSLATE_TYPE translate; +{ + register const unsigned char *p1 = (const unsigned char *) s1; + register const unsigned char *p2 = (const unsigned char *) s2; + while (len) + { + if (translate[*p1++] != translate[*p2++]) return 1; + len--; + } + return 0; +} + +/* Entry points for GNU code. */ + +/* re_compile_pattern is the GNU regular expression compiler: it + compiles PATTERN (of length SIZE) and puts the result in BUFP. + Returns 0 if the pattern was valid, otherwise an error string. + + Assumes the `allocated' (and perhaps `buffer') and `translate' fields + are set in BUFP on entry. + + We call regex_compile to do the actual compilation. */ + +const char * +re_compile_pattern (pattern, length, bufp) + const char *pattern; + size_t length; + struct re_pattern_buffer *bufp; +{ + reg_errcode_t ret; + + /* GNU code is written to assume at least RE_NREGS registers will be set + (and at least one extra will be -1). */ + bufp->regs_allocated = REGS_UNALLOCATED; + + /* And GNU code determines whether or not to get register information + by passing null for the REGS argument to re_match, etc., not by + setting no_sub. */ + bufp->no_sub = 0; + + /* Match anchors at newline. */ + bufp->newline_anchor = 1; + + ret = regex_compile (pattern, length, re_syntax_options, bufp); + + if (!ret) + return NULL; + return gettext (re_error_msgid + re_error_msgid_idx[(int) ret]); +} +#ifdef _LIBC +weak_alias (__re_compile_pattern, re_compile_pattern) +#endif + +/* Entry points compatible with 4.2 BSD regex library. We don't define + them unless specifically requested. */ + +#if defined _REGEX_RE_COMP || defined _LIBC + +/* BSD has one and only one pattern buffer. */ +static struct re_pattern_buffer re_comp_buf; + +char * +#ifdef _LIBC +/* Make these definitions weak in libc, so POSIX programs can redefine + these names if they don't use our functions, and still use + regcomp/regexec below without link errors. */ +weak_function +#endif +re_comp (s) + const char *s; +{ + reg_errcode_t ret; + + if (!s) + { + if (!re_comp_buf.buffer) + return gettext ("No previous regular expression"); + return 0; + } + + if (!re_comp_buf.buffer) + { + re_comp_buf.buffer = (unsigned char *) malloc (200); + if (re_comp_buf.buffer == NULL) + return (char *) gettext (re_error_msgid + + re_error_msgid_idx[(int) REG_ESPACE]); + re_comp_buf.allocated = 200; + + re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); + if (re_comp_buf.fastmap == NULL) + return (char *) gettext (re_error_msgid + + re_error_msgid_idx[(int) REG_ESPACE]); + } + + /* Since `re_exec' always passes NULL for the `regs' argument, we + don't need to initialize the pattern buffer fields which affect it. */ + + /* Match anchors at newlines. */ + re_comp_buf.newline_anchor = 1; + + ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); + + if (!ret) + return NULL; + + /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ + return (char *) gettext (re_error_msgid + re_error_msgid_idx[(int) ret]); +} + + +int +#ifdef _LIBC +weak_function +#endif +re_exec (s) + const char *s; +{ + const int len = strlen (s); + return + 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); +} + +#endif /* _REGEX_RE_COMP */ + +/* POSIX.2 functions. Don't define these for Emacs. */ + +#ifndef emacs + +/* regcomp takes a regular expression as a string and compiles it. + + PREG is a regex_t *. We do not expect any fields to be initialized, + since POSIX says we shouldn't. Thus, we set + + `buffer' to the compiled pattern; + `used' to the length of the compiled pattern; + `syntax' to RE_SYNTAX_POSIX_EXTENDED if the + REG_EXTENDED bit in CFLAGS is set; otherwise, to + RE_SYNTAX_POSIX_BASIC; + `newline_anchor' to REG_NEWLINE being set in CFLAGS; + `fastmap' to an allocated space for the fastmap; + `fastmap_accurate' to zero; + `re_nsub' to the number of subexpressions in PATTERN. + + PATTERN is the address of the pattern string. + + CFLAGS is a series of bits which affect compilation. + + If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we + use POSIX basic syntax. + + If REG_NEWLINE is set, then . and [^...] don't match newline. + Also, regexec will try a match beginning after every newline. + + If REG_ICASE is set, then we considers upper- and lowercase + versions of letters to be equivalent when matching. + + If REG_NOSUB is set, then when PREG is passed to regexec, that + routine will report only success or failure, and nothing about the + registers. + + It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for + the return codes and their meanings.) */ + +int +regcomp (preg, pattern, cflags) + regex_t *preg; + const char *pattern; + int cflags; +{ + reg_errcode_t ret; + reg_syntax_t syntax + = (cflags & REG_EXTENDED) ? + RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; + + /* regex_compile will allocate the space for the compiled pattern. */ + preg->buffer = 0; + preg->allocated = 0; + preg->used = 0; + + /* Try to allocate space for the fastmap. */ + preg->fastmap = (char *) malloc (1 << BYTEWIDTH); + + if (cflags & REG_ICASE) + { + unsigned i; + + preg->translate + = (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE + * sizeof (*(RE_TRANSLATE_TYPE)0)); + if (preg->translate == NULL) + return (int) REG_ESPACE; + + /* Map uppercase characters to corresponding lowercase ones. */ + for (i = 0; i < CHAR_SET_SIZE; i++) + preg->translate[i] = ISUPPER (i) ? TOLOWER (i) : i; + } + else + preg->translate = NULL; + + /* If REG_NEWLINE is set, newlines are treated differently. */ + if (cflags & REG_NEWLINE) + { /* REG_NEWLINE implies neither . nor [^...] match newline. */ + syntax &= ~RE_DOT_NEWLINE; + syntax |= RE_HAT_LISTS_NOT_NEWLINE; + /* It also changes the matching behavior. */ + preg->newline_anchor = 1; + } + else + preg->newline_anchor = 0; + + preg->no_sub = !!(cflags & REG_NOSUB); + + /* POSIX says a null character in the pattern terminates it, so we + can use strlen here in compiling the pattern. */ + ret = regex_compile (pattern, strlen (pattern), syntax, preg); + + /* POSIX doesn't distinguish between an unmatched open-group and an + unmatched close-group: both are REG_EPAREN. */ + if (ret == REG_ERPAREN) ret = REG_EPAREN; + + if (ret == REG_NOERROR && preg->fastmap) + { + /* Compute the fastmap now, since regexec cannot modify the pattern + buffer. */ + if (re_compile_fastmap (preg) == -2) + { + /* Some error occured while computing the fastmap, just forget + about it. */ + free (preg->fastmap); + preg->fastmap = NULL; + } + } + + return (int) ret; +} +#ifdef _LIBC +weak_alias (__regcomp, regcomp) +#endif + + +/* regexec searches for a given pattern, specified by PREG, in the + string STRING. + + If NMATCH is zero or REG_NOSUB was set in the cflags argument to + `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at + least NMATCH elements, and we set them to the offsets of the + corresponding matched substrings. + + EFLAGS specifies `execution flags' which affect matching: if + REG_NOTBOL is set, then ^ does not match at the beginning of the + string; if REG_NOTEOL is set, then $ does not match at the end. + + We return 0 if we find a match and REG_NOMATCH if not. */ + +int +regexec (preg, string, nmatch, pmatch, eflags) + const regex_t *preg; + const char *string; + size_t nmatch; + regmatch_t pmatch[]; + int eflags; +{ + int ret; + struct re_registers regs; + regex_t private_preg; + int len = strlen (string); + boolean want_reg_info = !preg->no_sub && nmatch > 0; + + private_preg = *preg; + + private_preg.not_bol = !!(eflags & REG_NOTBOL); + private_preg.not_eol = !!(eflags & REG_NOTEOL); + + /* The user has told us exactly how many registers to return + information about, via `nmatch'. We have to pass that on to the + matching routines. */ + private_preg.regs_allocated = REGS_FIXED; + + if (want_reg_info) + { + regs.num_regs = nmatch; + regs.start = TALLOC (nmatch * 2, regoff_t); + if (regs.start == NULL) + return (int) REG_NOMATCH; + regs.end = regs.start + nmatch; + } + + /* Perform the searching operation. */ + ret = re_search (&private_preg, string, len, + /* start: */ 0, /* range: */ len, + want_reg_info ? ®s : (struct re_registers *) 0); + + /* Copy the register information to the POSIX structure. */ + if (want_reg_info) + { + if (ret >= 0) + { + unsigned r; + + for (r = 0; r < nmatch; r++) + { + pmatch[r].rm_so = regs.start[r]; + pmatch[r].rm_eo = regs.end[r]; + } + } + + /* If we needed the temporary register info, free the space now. */ + free (regs.start); + } + + /* We want zero return to mean success, unlike `re_search'. */ + return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; +} +#ifdef _LIBC +weak_alias (__regexec, regexec) +#endif + + +/* Returns a message corresponding to an error code, ERRCODE, returned + from either regcomp or regexec. We don't use PREG here. */ + +size_t +regerror (errcode, preg, errbuf, errbuf_size) + int errcode; + const regex_t *preg; + char *errbuf; + size_t errbuf_size; +{ + const char *msg; + size_t msg_size; + + if (errcode < 0 + || errcode >= (int) (sizeof (re_error_msgid_idx) + / sizeof (re_error_msgid_idx[0]))) + /* Only error codes returned by the rest of the code should be passed + to this routine. If we are given anything else, or if other regex + code generates an invalid error code, then the program has a bug. + Dump core so we can fix it. */ + abort (); + + msg = gettext (re_error_msgid + re_error_msgid_idx[errcode]); + + msg_size = strlen (msg) + 1; /* Includes the null. */ + + if (errbuf_size != 0) + { + if (msg_size > errbuf_size) + { +#if defined HAVE_MEMPCPY || defined _LIBC + *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0'; +#else + memcpy (errbuf, msg, errbuf_size - 1); + errbuf[errbuf_size - 1] = 0; +#endif + } + else + memcpy (errbuf, msg, msg_size); + } + + return msg_size; +} +#ifdef _LIBC +weak_alias (__regerror, regerror) +#endif + + +/* Free dynamically allocated space used by PREG. */ + +void +regfree (preg) + regex_t *preg; +{ + if (preg->buffer != NULL) + free (preg->buffer); + preg->buffer = NULL; + + preg->allocated = 0; + preg->used = 0; + + if (preg->fastmap != NULL) + free (preg->fastmap); + preg->fastmap = NULL; + preg->fastmap_accurate = 0; + + if (preg->translate != NULL) + free (preg->translate); + preg->translate = NULL; +} +#ifdef _LIBC +weak_alias (__regfree, regfree) +#endif + +#endif /* not emacs */ diff --git a/lib/routemap.c b/lib/routemap.c new file mode 100644 index 0000000..af96709 --- /dev/null +++ b/lib/routemap.c @@ -0,0 +1,1151 @@ +/* Route map function. + Copyright (C) 1998, 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "linklist.h" +#include "memory.h" +#include "vector.h" +#include "prefix.h" +#include "routemap.h" +#include "command.h" + +/* Vector for route match rules. */ +static vector route_match_vec; + +/* Vector for route set rules. */ +static vector route_set_vec; + +/* Route map rule. This rule has both `match' rule and `set' rule. */ +struct route_map_rule +{ + /* Rule type. */ + struct route_map_rule_cmd *cmd; + + /* For pretty printing. */ + char *rule_str; + + /* Pre-compiled match rule. */ + void *value; + + /* Linked list. */ + struct route_map_rule *next; + struct route_map_rule *prev; +}; + +/* Making route map list. */ +struct route_map_list +{ + struct route_map *head; + struct route_map *tail; + + void (*add_hook) (char *); + void (*delete_hook) (char *); + void (*event_hook) (route_map_event_t, char *); +}; + +/* Master list of route map. */ +static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL }; + +static void +route_map_rule_delete (struct route_map_rule_list *, + struct route_map_rule *); + +static void +route_map_index_delete (struct route_map_index *, int); + +/* New route map allocation. Please note route map's name must be + specified. */ +static struct route_map * +route_map_new (char *name) +{ + struct route_map *new; + + new = XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map)); + new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name); + return new; +} + +/* Add new name to route_map. */ +static struct route_map * +route_map_add (char *name) +{ + struct route_map *map; + struct route_map_list *list; + + map = route_map_new (name); + list = &route_map_master; + + map->next = NULL; + map->prev = list->tail; + if (list->tail) + list->tail->next = map; + else + list->head = map; + list->tail = map; + + /* Execute hook. */ + if (route_map_master.add_hook) + (*route_map_master.add_hook) (name); + + return map; +} + +/* Route map delete from list. */ +static void +route_map_delete (struct route_map *map) +{ + struct route_map_list *list; + struct route_map_index *index; + char *name; + + while ((index = map->head) != NULL) + route_map_index_delete (index, 0); + + name = map->name; + + list = &route_map_master; + + if (map->next) + map->next->prev = map->prev; + else + list->tail = map->prev; + + if (map->prev) + map->prev->next = map->next; + else + list->head = map->next; + + XFREE (MTYPE_ROUTE_MAP, map); + + /* Execute deletion hook. */ + if (route_map_master.delete_hook) + (*route_map_master.delete_hook) (name); + + if (name) + XFREE (MTYPE_ROUTE_MAP_NAME, name); + +} + +/* Lookup route map by route map name string. */ +struct route_map * +route_map_lookup_by_name (char *name) +{ + struct route_map *map; + + for (map = route_map_master.head; map; map = map->next) + if (strcmp (map->name, name) == 0) + return map; + return NULL; +} + +/* Lookup route map. If there isn't route map create one and return + it. */ +struct route_map * +route_map_get (char *name) +{ + struct route_map *map; + + map = route_map_lookup_by_name (name); + if (map == NULL) + map = route_map_add (name); + return map; +} + +/* Return route map's type string. */ +static char * +route_map_type_str (enum route_map_type type) +{ + switch (type) + { + case RMAP_PERMIT: + return "permit"; + break; + case RMAP_DENY: + return "deny"; + break; + default: + return ""; + break; + } +} + +int +route_map_empty (struct route_map *map) +{ + if (map->head == NULL && map->tail == NULL) + return 1; + else + return 0; +} + +/* show route-map */ +void +vty_show_route_map_entry (struct vty *vty, struct route_map *map) +{ + struct route_map_rule *rule; + struct route_map_index *index; + + for (index = map->head; index; index = index->next) + { + vty_out (vty, "route-map %s, %s, sequence %d%s", + map->name, + route_map_type_str (index->type), + index->pref, + VTY_NEWLINE); + + /* Match clauses */ + vty_out (vty, " Match clauses:%s", VTY_NEWLINE); + for (rule = index->match_list.head; rule; rule = rule->next) + vty_out (vty, " %s %s%s", rule->cmd->str, rule->rule_str, VTY_NEWLINE); + if (index->exitpolicy == RMAP_GOTO) + vty_out (vty, " Continue: sequence %d%s", index->nextpref, VTY_NEWLINE); + if (index->exitpolicy == RMAP_NEXT) + { + vty_out (vty, " Continue: to next entry"); + if (index->next) + vty_out (vty, " %d%s", index->next->pref, VTY_NEWLINE); + else + vty_out (vty, " is undefined%s", VTY_NEWLINE); + } + + /* Set clauses */ + vty_out (vty, " Set clauses:%s", VTY_NEWLINE); + for (rule = index->set_list.head; rule; rule = rule->next) + vty_out (vty, " %s %s%s", rule->cmd->str, rule->rule_str, VTY_NEWLINE); + } +} + +int +vty_show_route_map (struct vty *vty, char *name) +{ + struct route_map *map; + + if (name) + { + map = route_map_lookup_by_name (name); + + if (map) + { + vty_show_route_map_entry (vty, map); + return CMD_SUCCESS; + } + else + { + vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE); + return CMD_WARNING; + } + } + + for (map = route_map_master.head; map; map = map->next) + vty_show_route_map_entry (vty, map); + + return CMD_SUCCESS; +} + +/* New route map allocation. Please note route map's name must be + specified. */ +struct route_map_index * +route_map_index_new () +{ + struct route_map_index *new; + + new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index)); + new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */ + return new; +} + +/* Free route map index. */ +static void +route_map_index_delete (struct route_map_index *index, int notify) +{ + struct route_map_rule *rule; + + /* Free route match. */ + while ((rule = index->match_list.head) != NULL) + route_map_rule_delete (&index->match_list, rule); + + /* Free route set. */ + while ((rule = index->set_list.head) != NULL) + route_map_rule_delete (&index->set_list, rule); + + /* Remove index from route map list. */ + if (index->next) + index->next->prev = index->prev; + else + index->map->tail = index->prev; + + if (index->prev) + index->prev->next = index->next; + else + index->map->head = index->next; + + /* Execute event hook. */ + if (route_map_master.event_hook && notify) + (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED, + index->map->name); + + XFREE (MTYPE_ROUTE_MAP_INDEX, index); +} + +/* Lookup index from route map. */ +struct route_map_index * +route_map_index_lookup (struct route_map *map, enum route_map_type type, + int pref) +{ + struct route_map_index *index; + + for (index = map->head; index; index = index->next) + if ((index->type == type || type == RMAP_ANY) + && index->pref == pref) + return index; + return NULL; +} + +/* Add new index to route map. */ +struct route_map_index * +route_map_index_add (struct route_map *map, enum route_map_type type, + int pref) +{ + struct route_map_index *index; + struct route_map_index *point; + + /* Allocate new route map inex. */ + index = route_map_index_new (); + index->map = map; + index->type = type; + index->pref = pref; + + /* Compare preference. */ + for (point = map->head; point; point = point->next) + if (point->pref >= pref) + break; + + if (map->head == NULL) + { + map->head = map->tail = index; + } + else if (point == NULL) + { + index->prev = map->tail; + map->tail->next = index; + map->tail = index; + } + else if (point == map->head) + { + index->next = map->head; + map->head->prev = index; + map->head = index; + } + else + { + index->next = point; + index->prev = point->prev; + if (point->prev) + point->prev->next = index; + point->prev = index; + } + + /* Execute event hook. */ + if (route_map_master.event_hook) + (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED, + map->name); + + return index; +} + +/* Get route map index. */ +struct route_map_index * +route_map_index_get (struct route_map *map, enum route_map_type type, + int pref) +{ + struct route_map_index *index; + + index = route_map_index_lookup (map, RMAP_ANY, pref); + if (index && index->type != type) + { + /* Delete index from route map. */ + route_map_index_delete (index, 1); + index = NULL; + } + if (index == NULL) + index = route_map_index_add (map, type, pref); + return index; +} + +/* New route map rule */ +struct route_map_rule * +route_map_rule_new () +{ + struct route_map_rule *new; + + new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule)); + return new; +} + +/* Install rule command to the match list. */ +void +route_map_install_match (struct route_map_rule_cmd *cmd) +{ + vector_set (route_match_vec, cmd); +} + +/* Install rule command to the set list. */ +void +route_map_install_set (struct route_map_rule_cmd *cmd) +{ + vector_set (route_set_vec, cmd); +} + +/* Lookup rule command from match list. */ +struct route_map_rule_cmd * +route_map_lookup_match (char *name) +{ + int i; + struct route_map_rule_cmd *rule; + + for (i = 0; i < vector_max (route_match_vec); i++) + if ((rule = vector_slot (route_match_vec, i)) != NULL) + if (strcmp (rule->str, name) == 0) + return rule; + return NULL; +} + +/* Lookup rule command from set list. */ +struct route_map_rule_cmd * +route_map_lookup_set (char *name) +{ + int i; + struct route_map_rule_cmd *rule; + + for (i = 0; i < vector_max (route_set_vec); i++) + if ((rule = vector_slot (route_set_vec, i)) != NULL) + if (strcmp (rule->str, name) == 0) + return rule; + return NULL; +} + +/* Add match and set rule to rule list. */ +static void +route_map_rule_add (struct route_map_rule_list *list, + struct route_map_rule *rule) +{ + rule->next = NULL; + rule->prev = list->tail; + if (list->tail) + list->tail->next = rule; + else + list->head = rule; + list->tail = rule; +} + +/* Delete rule from rule list. */ +static void +route_map_rule_delete (struct route_map_rule_list *list, + struct route_map_rule *rule) +{ + if (rule->cmd->func_free) + (*rule->cmd->func_free) (rule->value); + + if (rule->rule_str) + XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str); + + if (rule->next) + rule->next->prev = rule->prev; + else + list->tail = rule->prev; + if (rule->prev) + rule->prev->next = rule->next; + else + list->head = rule->next; + + XFREE (MTYPE_ROUTE_MAP_RULE, rule); +} + +/* strcmp wrapper function which don't crush even argument is NULL. */ +int +rulecmp (char *dst, char *src) +{ + if (dst == NULL) + { + if (src == NULL) + return 0; + else + return 1; + } + else + { + if (src == NULL) + return 1; + else + return strcmp (dst, src); + } + return 1; +} + +/* Add match statement to route map. */ +int +route_map_add_match (struct route_map_index *index, char *match_name, + char *match_arg) +{ + struct route_map_rule *rule; + struct route_map_rule *next; + struct route_map_rule_cmd *cmd; + void *compile; + int replaced = 0; + + /* First lookup rule for add match statement. */ + cmd = route_map_lookup_match (match_name); + if (cmd == NULL) + return RMAP_RULE_MISSING; + + /* Next call compile function for this match statement. */ + if (cmd->func_compile) + { + compile= (*cmd->func_compile)(match_arg); + if (compile == NULL) + return RMAP_COMPILE_ERROR; + } + else + compile = NULL; + + /* If argument is completely same ignore it. */ + for (rule = index->match_list.head; rule; rule = next) + { + next = rule->next; + if (rule->cmd == cmd) + { + route_map_rule_delete (&index->match_list, rule); + replaced = 1; + } + } + + /* Add new route map match rule. */ + rule = route_map_rule_new (); + rule->cmd = cmd; + rule->value = compile; + if (match_arg) + rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg); + else + rule->rule_str = NULL; + + /* Add new route match rule to linked list. */ + route_map_rule_add (&index->match_list, rule); + + /* Execute event hook. */ + if (route_map_master.event_hook) + (*route_map_master.event_hook) (replaced ? + RMAP_EVENT_MATCH_REPLACED: + RMAP_EVENT_MATCH_ADDED, + index->map->name); + + return 0; +} + +/* Delete specified route match rule. */ +int +route_map_delete_match (struct route_map_index *index, char *match_name, + char *match_arg) +{ + struct route_map_rule *rule; + struct route_map_rule_cmd *cmd; + + cmd = route_map_lookup_match (match_name); + if (cmd == NULL) + return 1; + + for (rule = index->match_list.head; rule; rule = rule->next) + if (rule->cmd == cmd && + (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL)) + { + route_map_rule_delete (&index->match_list, rule); + /* Execute event hook. */ + if (route_map_master.event_hook) + (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED, + index->map->name); + return 0; + } + /* Can't find matched rule. */ + return 1; +} + +/* Add route-map set statement to the route map. */ +int +route_map_add_set (struct route_map_index *index, char *set_name, + char *set_arg) +{ + struct route_map_rule *rule; + struct route_map_rule *next; + struct route_map_rule_cmd *cmd; + void *compile; + int replaced = 0; + + cmd = route_map_lookup_set (set_name); + if (cmd == NULL) + return RMAP_RULE_MISSING; + + /* Next call compile function for this match statement. */ + if (cmd->func_compile) + { + compile= (*cmd->func_compile)(set_arg); + if (compile == NULL) + return RMAP_COMPILE_ERROR; + } + else + compile = NULL; + + /* Add by WJL. if old set command of same kind exist, delete it first + to ensure only one set command of same kind exist under a + route_map_index. */ + for (rule = index->set_list.head; rule; rule = next) + { + next = rule->next; + if (rule->cmd == cmd) + { + route_map_rule_delete (&index->set_list, rule); + replaced = 1; + } + } + + /* Add new route map match rule. */ + rule = route_map_rule_new (); + rule->cmd = cmd; + rule->value = compile; + if (set_arg) + rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg); + else + rule->rule_str = NULL; + + /* Add new route match rule to linked list. */ + route_map_rule_add (&index->set_list, rule); + + /* Execute event hook. */ + if (route_map_master.event_hook) + (*route_map_master.event_hook) (replaced ? + RMAP_EVENT_SET_REPLACED: + RMAP_EVENT_SET_ADDED, + index->map->name); + return 0; +} + +/* Delete route map set rule. */ +int +route_map_delete_set (struct route_map_index *index, char *set_name, + char *set_arg) +{ + struct route_map_rule *rule; + struct route_map_rule_cmd *cmd; + + cmd = route_map_lookup_set (set_name); + if (cmd == NULL) + return 1; + + for (rule = index->set_list.head; rule; rule = rule->next) + if ((rule->cmd == cmd) && + (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL)) + { + route_map_rule_delete (&index->set_list, rule); + /* Execute event hook. */ + if (route_map_master.event_hook) + (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED, + index->map->name); + return 0; + } + /* Can't find matched rule. */ + return 1; +} + +/* Apply route map's each index to the object. + + The matrix for a route-map looks like this: + (note, this includes the description for the "NEXT" + and "GOTO" frobs now + + Match | No Match + | + permit a | c + | + ------------------+--------------- + | + deny b | d + | + + a) Apply Set statements, accept route + If NEXT is specified, goto NEXT statement + If GOTO is specified, goto the first clause where pref > nextpref + If nothing is specified, do as Cisco and finish + b) If NEXT is specified, goto NEXT statement + If nothing is specified, finally will be denied by route-map. + c) & d) Goto Next index + + If we get no matches after we've processed all updates, then the route + is dropped too. + + Some notes on the new "NEXT" and "GOTO" + continue - If this clause is matched, then the set statements + are executed and then we drop through to the next clause + continue n - If this clause is matched, then the set statments + are executed and then we goto the nth clause, or the + first clause greater than this. In order to ensure + route-maps *always* exit, you cannot jump backwards. + Sorry ;) + + We need to make sure our route-map processing matches the above +*/ +route_map_result_t +route_map_apply_index (struct route_map_index *index, struct prefix *prefix, + route_map_object_t type, void *object) +{ + int ret = 0; + struct route_map_rule *match; + struct route_map_rule *set; + + /* Check all match rule and if there is no match rule, go to the + set statement. */ + if (! index->match_list.head) + ret = RMAP_MATCH; + else + { + for (match = index->match_list.head; match; match = match->next) + { + /* Try each match statement in turn, If any return + RMAP_MATCH, go direct to set statement, otherwise, walk + to next match statement. */ + ret = (*match->cmd->func_apply)(match->value, prefix, type, object); + + if (ret == RMAP_MATCH) + break; + } + } + + /* If end of match statement, still can't get any RMAP_MATCH return, + just return to next rout-map statement. */ + + if (ret != RMAP_MATCH) + return ret; + + /* We get here if all match statements matched From the matrix + above, if this is PERMIT we go on and apply the SET functions. + If we're deny, we return indicating we matched a deny */ + + /* Apply set statement to the object. */ + if (index->type == RMAP_PERMIT) + { + for (set = index->set_list.head; set; set = set->next) + ret = (*set->cmd->func_apply)(set->value, prefix, type, object); + + return RMAP_MATCH; + } + else + { + return RMAP_DENYMATCH; + } + /* Should not get here! */ + return RMAP_MATCH; +} + +/* Apply route map to the object. */ +route_map_result_t +route_map_apply (struct route_map *map, struct prefix *prefix, + route_map_object_t type, void *object) +{ + int ret = 0; + struct route_map_index *index; + + if (map == NULL) + return RMAP_DENYMATCH; + + for (index = map->head; index; index = index->next) + { + /* Apply this index. End here if we get a RM_NOMATCH */ + ret = route_map_apply_index (index, prefix, type, object); + + if (ret == RMAP_DENYMATCH) + return ret; + else if (ret == RMAP_MATCH) + { + /* We now have to handle the NEXT and GOTO clauses */ + if(index->exitpolicy == RMAP_EXIT) + return ret; + + if(index->exitpolicy == RMAP_GOTO) + { + /* Find the next clause to jump to */ + struct route_map_index *next; + + next = index->next; + while (next && next->pref < index->nextpref) + { + index = next; + next = next->next; + } + if (next == NULL) + { + /* No clauses match! */ + return ret; + } + } + /* Otherwise, we fall through as it was a NEXT */ + } + } + /* Finally route-map does not match at all. */ + return RMAP_DENYMATCH; +} + +void +route_map_add_hook (void (*func) (char *)) +{ + route_map_master.add_hook = func; +} + +void +route_map_delete_hook (void (*func) (char *)) +{ + route_map_master.delete_hook = func; +} + +void +route_map_event_hook (void (*func) (route_map_event_t, char *)) +{ + route_map_master.event_hook = func; +} + +void +route_map_init () +{ + /* Make vector for match and set. */ + route_match_vec = vector_init (1); + route_set_vec = vector_init (1); +} + +/* VTY related functions. */ +DEFUN (route_map, + route_map_cmd, + "route-map WORD (deny|permit) <1-65535>", + "Create route-map or enter route-map command mode\n" + "Route map tag\n" + "Route map denies set operations\n" + "Route map permits set operations\n" + "Sequence to insert to/delete from existing route-map entry\n") +{ + int permit; + unsigned long pref; + struct route_map *map; + struct route_map_index *index; + char *endptr = NULL; + + /* Permit check. */ + if (strncmp (argv[1], "permit", strlen (argv[1])) == 0) + permit = RMAP_PERMIT; + else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0) + permit = RMAP_DENY; + else + { + vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Preference check. */ + pref = strtoul (argv[2], &endptr, 10); + if (pref == ULONG_MAX || *endptr != '\0') + { + vty_out (vty, "the fourth field must be positive integer%s", + VTY_NEWLINE); + return CMD_WARNING; + } + if (pref == 0 || pref > 65535) + { + vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get route map. */ + map = route_map_get (argv[0]); + index = route_map_index_get (map, permit, pref); + + vty->index = index; + vty->node = RMAP_NODE; + return CMD_SUCCESS; +} + +DEFUN (no_route_map_all, + no_route_map_all_cmd, + "no route-map WORD", + NO_STR + "Create route-map or enter route-map command mode\n" + "Route map tag\n") +{ + struct route_map *map; + + map = route_map_lookup_by_name (argv[0]); + if (map == NULL) + { + vty_out (vty, "%% Could not find route-map %s%s", + argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + route_map_delete (map); + + return CMD_SUCCESS; +} + +DEFUN (no_route_map, + no_route_map_cmd, + "no route-map WORD (deny|permit) <1-65535>", + NO_STR + "Create route-map or enter route-map command mode\n" + "Route map tag\n" + "Route map denies set operations\n" + "Route map permits set operations\n" + "Sequence to insert to/delete from existing route-map entry\n") +{ + int permit; + unsigned long pref; + struct route_map *map; + struct route_map_index *index; + char *endptr = NULL; + + /* Permit check. */ + if (strncmp (argv[1], "permit", strlen (argv[1])) == 0) + permit = RMAP_PERMIT; + else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0) + permit = RMAP_DENY; + else + { + vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Preference. */ + pref = strtoul (argv[2], &endptr, 10); + if (pref == ULONG_MAX || *endptr != '\0') + { + vty_out (vty, "the fourth field must be positive integer%s", + VTY_NEWLINE); + return CMD_WARNING; + } + if (pref == 0 || pref > 65535) + { + vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Existence check. */ + map = route_map_lookup_by_name (argv[0]); + if (map == NULL) + { + vty_out (vty, "%% Could not find route-map %s%s", + argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + /* Lookup route map index. */ + index = route_map_index_lookup (map, permit, pref); + if (index == NULL) + { + vty_out (vty, "%% Could not find route-map entry %s %s%s", + argv[0], argv[2], VTY_NEWLINE); + return CMD_WARNING; + } + + /* Delete index from route map. */ + route_map_index_delete (index, 1); + + /* If this route rule is the last one, delete route map itself. */ + if (route_map_empty (map)) + route_map_delete (map); + + return CMD_SUCCESS; +} + +DEFUN (rmap_continue, + rmap_continue_cmd, + "continue", + "Continue on a different entry within the route-map\n") +{ + struct route_map_index *index; + + index = vty->index; + + if (index) + index->exitpolicy = RMAP_NEXT; + + return CMD_SUCCESS; +} + +DEFUN (no_rmap_continue, + no_rmap_continue_cmd, + "no continue", + NO_STR + "Continue on a different entry within the route-map\n") +{ + struct route_map_index *index; + + index = vty->index; + + if (index) + index->exitpolicy = RMAP_EXIT; + + return CMD_SUCCESS; +} + +DEFUN (rmap_continue_seq, + rmap_continue_seq_cmd, + "continue <1-65535>", + "Continue on a different entry within the route-map\n" + "Route-map entry sequence number\n") +{ + struct route_map_index *index; + int d = 0; + + if (argv[0]) + d = atoi(argv[0]); + + index = vty->index; + if (index) + { + if (d <= index->pref) + { + /* Can't allow you to do that, Dave */ + vty_out (vty, "%%Loop in the route-map%s", VTY_NEWLINE); + return CMD_WARNING; + } + else + { + index->exitpolicy = RMAP_GOTO; + index->nextpref = d; + } + } + return CMD_SUCCESS; +} + +DEFUN (no_rmap_continue_seq, + no_rmap_continue_seq_cmd, + "no continue <1-65535>", + NO_STR + "Continue on a different entry within the route-map\n" + "Route-map entry sequence number\n") +{ + struct route_map_index *index; + + index = vty->index; + + if (index) + index->exitpolicy = RMAP_EXIT; + + return CMD_SUCCESS; +} + +DEFUN (rmap_show, + rmap_show_cmd, + "show route-map", + SHOW_STR + "route-map information\n") +{ + return vty_show_route_map (vty, NULL); +} + +DEFUN (rmap_show_name, + rmap_show_name_cmd, + "show route-map WORD", + SHOW_STR + "route-map information\n" + "route-map name\n") +{ + return vty_show_route_map (vty, argv[0]); +} + +/* Configuration write function. */ +int +route_map_config_write (struct vty *vty) +{ + struct route_map *map; + struct route_map_index *index; + struct route_map_rule *rule; + int first = 1; + int write = 0; + + for (map = route_map_master.head; map; map = map->next) + for (index = map->head; index; index = index->next) + { + if (!first) + vty_out (vty, "!%s", VTY_NEWLINE); + else + first = 0; + + vty_out (vty, "route-map %s %s %d%s", + map->name, + route_map_type_str (index->type), + index->pref, VTY_NEWLINE); + + for (rule = index->match_list.head; rule; rule = rule->next) + vty_out (vty, " match %s %s%s", rule->cmd->str, + rule->rule_str ? rule->rule_str : "", + VTY_NEWLINE); + + if (index->exitpolicy == RMAP_GOTO) + vty_out (vty, " continue %d%s", index->nextpref, + VTY_NEWLINE); + if (index->exitpolicy == RMAP_NEXT) + vty_out (vty," continue%s", VTY_NEWLINE); + + for (rule = index->set_list.head; rule; rule = rule->next) + vty_out (vty, " set %s %s%s", rule->cmd->str, + rule->rule_str ? rule->rule_str : "", + VTY_NEWLINE); + + write++; + } + return write; +} + +/* Route map node structure. */ +struct cmd_node rmap_node = +{ + RMAP_NODE, + "%s(config-route-map)# ", + 1 +}; + +/* Initialization of route map vector. */ +void +route_map_init_vty () +{ + /* Install route map top node. */ + install_node (&rmap_node, route_map_config_write); + + /* Install route map commands. */ + install_default (RMAP_NODE); + install_element (CONFIG_NODE, &route_map_cmd); + install_element (CONFIG_NODE, &no_route_map_cmd); + install_element (CONFIG_NODE, &no_route_map_all_cmd); + + /* Install the on-match stuff */ + install_element (RMAP_NODE, &route_map_cmd); + install_element (RMAP_NODE, &rmap_continue_cmd); + install_element (RMAP_NODE, &no_rmap_continue_cmd); + install_element (RMAP_NODE, &rmap_continue_seq_cmd); + install_element (RMAP_NODE, &no_rmap_continue_seq_cmd); + + /* Install show command */ + install_element (ENABLE_NODE, &rmap_show_cmd); + install_element (ENABLE_NODE, &rmap_show_name_cmd); +} diff --git a/lib/routemap.h b/lib/routemap.h new file mode 100644 index 0000000..e37f1e7 --- /dev/null +++ b/lib/routemap.h @@ -0,0 +1,194 @@ +/* Route map function. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_ROUTEMAP_H +#define _ZEBRA_ROUTEMAP_H + +/* Route map's type. */ +enum route_map_type +{ + RMAP_PERMIT, + RMAP_DENY, + RMAP_ANY +}; + +typedef enum +{ + RMAP_MATCH, + RMAP_DENYMATCH, + RMAP_NOMATCH, + RMAP_ERROR, + RMAP_OKAY +} route_map_result_t; + +typedef enum +{ + RMAP_RIP, + RMAP_RIPNG, + RMAP_OSPF, + RMAP_OSPF6, + RMAP_BGP +} route_map_object_t; + +typedef enum +{ + RMAP_EXIT, + RMAP_GOTO, + RMAP_NEXT +} route_map_end_t; + +typedef enum +{ + RMAP_EVENT_SET_ADDED, + RMAP_EVENT_SET_DELETED, + RMAP_EVENT_SET_REPLACED, + RMAP_EVENT_MATCH_ADDED, + RMAP_EVENT_MATCH_DELETED, + RMAP_EVENT_MATCH_REPLACED, + RMAP_EVENT_INDEX_ADDED, + RMAP_EVENT_INDEX_DELETED +} route_map_event_t; + +/* Route map rule structure for matching and setting. */ +struct route_map_rule_cmd +{ + /* Route map rule name (e.g. as-path, metric) */ + char *str; + + /* Function for value set or match. */ + route_map_result_t (*func_apply)(void *, struct prefix *, + route_map_object_t, void *); + + /* Compile argument and return result as void *. */ + void *(*func_compile)(char *); + + /* Free allocated value by func_compile (). */ + void (*func_free)(void *); +}; + +/* Route map apply error. */ +enum +{ + /* Route map rule is missing. */ + RMAP_RULE_MISSING = 1, + + /* Route map rule can't compile */ + RMAP_COMPILE_ERROR +}; + +/* Route map rule list. */ +struct route_map_rule_list +{ + struct route_map_rule *head; + struct route_map_rule *tail; +}; + +/* Route map index structure. */ +struct route_map_index +{ + struct route_map *map; + + /* Preference of this route map rule. */ + int pref; + + /* Route map type permit or deny. */ + enum route_map_type type; + + /* Do we follow old rules, or hop forward? */ + route_map_end_t exitpolicy; + + /* If we're using "GOTO", to where do we go? */ + int nextpref; + + /* Matching rule list. */ + struct route_map_rule_list match_list; + struct route_map_rule_list set_list; + + /* Make linked list. */ + struct route_map_index *next; + struct route_map_index *prev; +}; + +/* Route map list structure. */ +struct route_map +{ + /* Name of route map. */ + char *name; + + /* Route map's rule. */ + struct route_map_index *head; + struct route_map_index *tail; + + /* Make linked list. */ + struct route_map *next; + struct route_map *prev; +}; + +/* Prototypes. */ +void route_map_init (); +void route_map_init_vty (); + +/* Add match statement to route map. */ +int +route_map_add_match (struct route_map_index *index, + char *match_name, + char *match_arg); + +/* Delete specified route match rule. */ +int +route_map_delete_match (struct route_map_index *index, + char *match_name, + char *match_arg); + +/* Add route-map set statement to the route map. */ +int +route_map_add_set (struct route_map_index *index, + char *set_name, + char *set_arg); + +/* Delete route map set rule. */ +int +route_map_delete_set (struct route_map_index *index, char *set_name, + char *set_arg); + +/* Install rule command to the match list. */ +void +route_map_install_match (struct route_map_rule_cmd *cmd); + +/* Install rule command to the set list. */ +void +route_map_install_set (struct route_map_rule_cmd *cmd); + +/* Lookup route map by name. */ +struct route_map * +route_map_lookup_by_name (char *name); + +/* Apply route map to the object. */ +route_map_result_t +route_map_apply (struct route_map *map, struct prefix *, + route_map_object_t object_type, void *object); + +void route_map_add_hook (void (*func) (char *)); +void route_map_delete_hook (void (*func) (char *)); +void route_map_event_hook (void (*func) (route_map_event_t, char *)); + + +#endif /* _ZEBRA_ROUTEMAP_H */ diff --git a/lib/smux.c b/lib/smux.c new file mode 100644 index 0000000..4d81cc0 --- /dev/null +++ b/lib/smux.c @@ -0,0 +1,1505 @@ +/* SNMP support + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#ifdef HAVE_SNMP + +#ifdef HAVE_NETSNMP +#include +#endif /* HAVE_NETSNMP */ + +#include +#include +#include + +#include "smux.h" +#include "log.h" +#include "thread.h" +#include "linklist.h" +#include "command.h" +#include "version.h" +#include "memory.h" +#include "sockunion.h" + +#define min(A,B) ((A) < (B) ? (A) : (B)) + +enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ}; + +void smux_event (enum smux_event, int); + + +/* SMUX socket. */ +int smux_sock = -1; + +/* SMUX subtree list. */ +struct list *treelist; + +/* SMUX oid. */ +oid *smux_oid; +size_t smux_oid_len; + +/* SMUX default oid. */ +oid *smux_default_oid; +size_t smux_default_oid_len; + +/* SMUX password. */ +char *smux_passwd; +char *smux_default_passwd = ""; + +/* SMUX read threads. */ +struct thread *smux_read_thread; + +/* SMUX connect thrads. */ +struct thread *smux_connect_thread; + +/* SMUX debug flag. */ +int debug_smux = 0; + +/* SMUX failure count. */ +int fail = 0; + +/* SMUX node. */ +struct cmd_node smux_node = +{ + SMUX_NODE, + "" /* SMUX has no interface. */ +}; + +void * +oid_copy (void *dest, void *src, size_t size) +{ + return memcpy (dest, src, size * sizeof (oid)); +} + +void +oid2in_addr (oid oid[], int len, struct in_addr *addr) +{ + int i; + u_char *pnt; + + if (len == 0) + return; + + pnt = (u_char *) addr; + + for (i = 0; i < len; i++) + *pnt++ = oid[i]; +} + +void +oid_copy_addr (oid oid[], struct in_addr *addr, int len) +{ + int i; + u_char *pnt; + + if (len == 0) + return; + + pnt = (u_char *) addr; + + for (i = 0; i < len; i++) + oid[i] = *pnt++; +} + +int +oid_compare (oid *o1, int o1_len, oid *o2, int o2_len) +{ + int i; + + for (i = 0; i < min (o1_len, o2_len); i++) + { + if (o1[i] < o2[i]) + return -1; + else if (o1[i] > o2[i]) + return 1; + } + if (o1_len < o2_len) + return -1; + if (o1_len > o2_len) + return 1; + + return 0; +} + +int +oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len) +{ + int i; + + for (i = 0; i < min (o1_len, o2_len); i++) + { + if (o1[i] < o2[i]) + return -1; + else if (o1[i] > o2[i]) + return 1; + } + if (o1_len < o2_len) + return -1; + + return 0; +} + +void +smux_oid_dump (char *prefix, oid *oid, size_t oid_len) +{ + int i; + int first = 1; + char buf[MAX_OID_LEN * 3]; + + buf[0] = '\0'; + + for (i = 0; i < oid_len; i++) + { + sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]); + first = 0; + } + zlog_info ("%s: %s", prefix, buf); +} + +int +smux_socket () +{ + int ret; +#ifdef HAVE_IPV6 + struct addrinfo hints, *res0, *res; + int gai; +#else + struct sockaddr_in serv; + struct servent *sp; +#endif + int sock = 0; + +#ifdef HAVE_IPV6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + gai = getaddrinfo(NULL, "smux", &hints, &res0); + if (gai == EAI_SERVICE) + { + char servbuf[NI_MAXSERV]; + sprintf(servbuf,"%d",SMUX_PORT_DEFAULT); + servbuf[sizeof (servbuf) - 1] = '\0'; + gai = getaddrinfo(NULL, servbuf, &hints, &res0); + } + if (gai) + { + zlog_warn("Cannot locate loopback service smux"); + return -1; + } + for(res=res0; res; res=res->ai_next) + { + if (res->ai_family != AF_INET +#ifdef HAVE_IPV6 + && res->ai_family != AF_INET6 +#endif /* HAVE_IPV6 */ + ) + continue; + + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock < 0) + continue; + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); + ret = connect (sock, res->ai_addr, res->ai_addrlen); + if (ret < 0) + { + close(sock); + sock = -1; + continue; + } + break; + } + freeaddrinfo(res0); + if (sock < 0) + zlog_warn ("Can't connect to SNMP agent with SMUX"); +#else + sock = socket (AF_INET, SOCK_STREAM, 0); + if (sock < 0) + { + zlog_warn ("Can't make socket for SNMP"); + return -1; + } + + memset (&serv, 0, sizeof (struct sockaddr_in)); + serv.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + serv.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + + sp = getservbyname ("smux", "tcp"); + if (sp != NULL) + serv.sin_port = sp->s_port; + else + serv.sin_port = htons (SMUX_PORT_DEFAULT); + + serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); + + ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in)); + if (ret < 0) + { + close (sock); + smux_sock = -1; + zlog_warn ("Can't connect to SNMP agent with SMUX"); + return -1; + } +#endif + return sock; +} + +void +smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat, + long errindex, u_char val_type, void *arg, size_t arg_len) +{ + int ret; + u_char buf[BUFSIZ]; + u_char *ptr, *h1, *h1e, *h2, *h2e; + int len, length; + + ptr = buf; + len = BUFSIZ; + length = len; + + if (debug_smux) + { + zlog_info ("SMUX GETRSP send"); + zlog_info ("SMUX GETRSP reqid: %ld", reqid); + } + + h1 = ptr; + /* Place holder h1 for complete sequence */ + ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0); + h1e = ptr; + + ptr = asn_build_int (ptr, &len, + (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), + &reqid, sizeof (reqid)); + + if (debug_smux) + zlog_info ("SMUX GETRSP errstat: %ld", errstat); + + ptr = asn_build_int (ptr, &len, + (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), + &errstat, sizeof (errstat)); + if (debug_smux) + zlog_info ("SMUX GETRSP errindex: %ld", errindex); + + ptr = asn_build_int (ptr, &len, + (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), + &errindex, sizeof (errindex)); + + h2 = ptr; + /* Place holder h2 for one variable */ + ptr = asn_build_sequence (ptr, &len, + (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), + 0); + h2e = ptr; + + ptr = snmp_build_var_op (ptr, objid, &objid_len, + val_type, arg_len, arg, &len); + + /* Now variable size is known, fill in size */ + asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e); + + /* Fill in size of whole sequence */ + asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e); + + if (debug_smux) + zlog_info ("SMUX getresp send: %d", ptr - buf); + + ret = send (smux_sock, buf, (ptr - buf), 0); +} + +char * +smux_var (char *ptr, int len, oid objid[], size_t *objid_len, + size_t *var_val_len, + u_char *var_val_type, + void **var_value) +{ + u_char type; + u_char val_type; + size_t val_len; + u_char *val; + + if (debug_smux) + zlog_info ("SMUX var parse: len %d", len); + + /* Parse header. */ + ptr = asn_parse_header (ptr, &len, &type); + + if (debug_smux) + { + zlog_info ("SMUX var parse: type %d len %d", type, len); + zlog_info ("SMUX var parse: type must be %d", + (ASN_SEQUENCE | ASN_CONSTRUCTOR)); + } + + /* Parse var option. */ + *objid_len = MAX_OID_LEN; + ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type, + &val_len, &val, &len); + + if (var_val_len) + *var_val_len = val_len; + + if (var_value) + *var_value = (void*) val; + + if (var_val_type) + *var_val_type = val_type; + + /* Requested object id length is objid_len. */ + if (debug_smux) + smux_oid_dump ("Request OID", objid, *objid_len); + + if (debug_smux) + zlog_info ("SMUX val_type: %d", val_type); + + /* Check request value type. */ + if (debug_smux) + switch (val_type) + { + case ASN_NULL: + /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to + ASN_NULL. */ + zlog_info ("ASN_NULL"); + break; + + case ASN_INTEGER: + zlog_info ("ASN_INTEGER"); + break; + case ASN_COUNTER: + case ASN_GAUGE: + case ASN_TIMETICKS: + case ASN_UINTEGER: + zlog_info ("ASN_COUNTER"); + break; + case ASN_COUNTER64: + zlog_info ("ASN_COUNTER64"); + break; + case ASN_IPADDRESS: + zlog_info ("ASN_IPADDRESS"); + break; + case ASN_OCTET_STR: + zlog_info ("ASN_OCTET_STR"); + break; + case ASN_OPAQUE: + case ASN_NSAP: + case ASN_OBJECT_ID: + zlog_info ("ASN_OPAQUE"); + break; + case SNMP_NOSUCHOBJECT: + zlog_info ("SNMP_NOSUCHOBJECT"); + break; + case SNMP_NOSUCHINSTANCE: + zlog_info ("SNMP_NOSUCHINSTANCE"); + break; + case SNMP_ENDOFMIBVIEW: + zlog_info ("SNMP_ENDOFMIBVIEW"); + break; + case ASN_BIT_STR: + zlog_info ("ASN_BIT_STR"); + break; + default: + zlog_info ("Unknown type"); + break; + } + return ptr; +} + +/* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on + ucd-snmp smux and as such suppose, that the peer receives in the message + only one variable. Fortunately, IBM seems to do the same in AIX. */ + +int +smux_set (oid *reqid, size_t *reqid_len, + u_char val_type, void *val, size_t val_len, int action) +{ + int j; + struct subtree *subtree; + struct variable *v; + int subresult; + oid *suffix; + int suffix_len; + int result; + u_char *statP = NULL; + WriteMethod *write_method = NULL; + struct listnode *node; + + /* Check */ + for (node = treelist->head; node; node = node->next) + { + subtree = node->data; + subresult = oid_compare_part (reqid, *reqid_len, + subtree->name, subtree->name_len); + + /* Subtree matched. */ + if (subresult == 0) + { + /* Prepare suffix. */ + suffix = reqid + subtree->name_len; + suffix_len = *reqid_len - subtree->name_len; + result = subresult; + + /* Check variables. */ + for (j = 0; j < subtree->variables_num; j++) + { + v = &subtree->variables[j]; + + /* Always check suffix */ + result = oid_compare_part (suffix, suffix_len, + v->name, v->namelen); + + /* This is exact match so result must be zero. */ + if (result == 0) + { + if (debug_smux) + zlog_info ("SMUX function call index is %d", v->magic); + + statP = (*v->findVar) (v, suffix, &suffix_len, 1, + &val_len, &write_method); + + if (write_method) + { + return (*write_method)(action, val, val_type, val_len, + statP, suffix, suffix_len, v); + } + else + { + return SNMP_ERR_READONLY; + } + } + + /* If above execution is failed or oid is small (so + there is no further match). */ + if (result < 0) + return SNMP_ERR_NOSUCHNAME; + } + } + } + return SNMP_ERR_NOSUCHNAME; +} + +int +smux_get (oid *reqid, size_t *reqid_len, int exact, + u_char *val_type,void **val, size_t *val_len) +{ + int j; + struct subtree *subtree; + struct variable *v; + int subresult; + oid *suffix; + int suffix_len; + int result; + WriteMethod *write_method=NULL; + struct listnode *node; + + /* Check */ + for (node = treelist->head; node; node = node->next) + { + subtree = node->data; + subresult = oid_compare_part (reqid, *reqid_len, + subtree->name, subtree->name_len); + + /* Subtree matched. */ + if (subresult == 0) + { + /* Prepare suffix. */ + suffix = reqid + subtree->name_len; + suffix_len = *reqid_len - subtree->name_len; + result = subresult; + + /* Check variables. */ + for (j = 0; j < subtree->variables_num; j++) + { + v = &subtree->variables[j]; + + /* Always check suffix */ + result = oid_compare_part (suffix, suffix_len, + v->name, v->namelen); + + /* This is exact match so result must be zero. */ + if (result == 0) + { + if (debug_smux) + zlog_info ("SMUX function call index is %d", v->magic); + + *val = (*v->findVar) (v, suffix, &suffix_len, exact, + val_len, &write_method); + + /* There is no instance. */ + if (*val == NULL) + return SNMP_NOSUCHINSTANCE; + + /* Call is suceed. */ + *val_type = v->type; + + return 0; + } + + /* If above execution is failed or oid is small (so + there is no further match). */ + if (result < 0) + return SNMP_ERR_NOSUCHNAME; + } + } + } + return SNMP_ERR_NOSUCHNAME; +} + +int +smux_getnext (oid *reqid, size_t *reqid_len, int exact, + u_char *val_type,void **val, size_t *val_len) +{ + int j; + oid save[MAX_OID_LEN]; + int savelen = 0; + struct subtree *subtree; + struct variable *v; + int subresult; + oid *suffix; + int suffix_len; + int result; + WriteMethod *write_method=NULL; + struct listnode *node; + + + /* Save incoming request. */ + oid_copy (save, reqid, *reqid_len); + savelen = *reqid_len; + + /* Check */ + for (node = treelist->head; node; node = node->next) + { + subtree = node->data; + subresult = oid_compare_part (reqid, *reqid_len, + subtree->name, subtree->name_len); + + /* If request is in the tree. The agent has to make sure we + only receive requests we have registered for. */ + /* Unfortunately, that's not true. In fact, a SMUX subagent has to + behave as if it manages the whole SNMP MIB tree itself. It's the + duty of the master agent to collect the best answer and return it + to the manager. See RFC 1227 chapter 3.1.6 for the glory details + :-). ucd-snmp really behaves bad here as it actually might ask + multiple times for the same GETNEXT request as it throws away the + answer when it expects it in a different subtree and might come + back later with the very same request. --jochen */ + + if (subresult <= 0) + { + /* Prepare suffix. */ + suffix = reqid + subtree->name_len; + suffix_len = *reqid_len - subtree->name_len; + if (subresult < 0) + { + oid_copy(reqid, subtree->name, subtree->name_len); + *reqid_len = subtree->name_len; + } + for (j = 0; j < subtree->variables_num; j++) + { + result = subresult; + v = &subtree->variables[j]; + + /* Next then check result >= 0. */ + if (result == 0) + result = oid_compare_part (suffix, suffix_len, + v->name, v->namelen); + + if (result <= 0) + { + if (debug_smux) + zlog_info ("SMUX function call index is %d", v->magic); + if(result<0) + { + oid_copy(suffix, v->name, v->namelen); + suffix_len = v->namelen; + } + *val = (*v->findVar) (v, suffix, &suffix_len, exact, + val_len, &write_method); + *reqid_len = suffix_len + subtree->name_len; + if (*val) + { + *val_type = v->type; + return 0; + } + } + } + } + } + memcpy (reqid, save, savelen * sizeof(oid)); + *reqid_len = savelen; + + return SNMP_ERR_NOSUCHNAME; +} + +/* GET message header. */ +char * +smux_parse_get_header (char *ptr, size_t *len, long *reqid) +{ + u_char type; + long errstat; + long errindex; + + /* Request ID. */ + ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid)); + + if (debug_smux) + zlog_info ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len); + + /* Error status. */ + ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat)); + + if (debug_smux) + zlog_info ("SMUX GET errstat %ld len: %d", errstat, *len); + + /* Error index. */ + ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex)); + + if (debug_smux) + zlog_info ("SMUX GET errindex %ld len: %d", errindex, *len); + + return ptr; +} + +void +smux_parse_set (char *ptr, size_t len, int action) +{ + long reqid; + oid oid[MAX_OID_LEN]; + size_t oid_len; + u_char val_type; + void *val; + size_t val_len; + int ret; + + if (debug_smux) + zlog_info ("SMUX SET(%s) message parse: len %d", + (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"), + len); + + /* Parse SET message header. */ + ptr = smux_parse_get_header (ptr, &len, &reqid); + + /* Parse SET message object ID. */ + ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val); + + ret = smux_set (oid, &oid_len, val_type, val, val_len, action); + if (debug_smux) + zlog_info ("SMUX SET ret %d", ret); + + /* Return result. */ + if (RESERVE1 == action) + smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0); +} + +void +smux_parse_get (char *ptr, size_t len, int exact) +{ + long reqid; + oid oid[MAX_OID_LEN]; + size_t oid_len; + u_char val_type; + void *val; + size_t val_len; + int ret; + + if (debug_smux) + zlog_info ("SMUX GET message parse: len %d", len); + + /* Parse GET message header. */ + ptr = smux_parse_get_header (ptr, &len, &reqid); + + /* Parse GET message object ID. We needn't the value come */ + ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL); + + /* Traditional getstatptr. */ + if (exact) + ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len); + else + ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len); + + /* Return result. */ + if (ret == 0) + smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len); + else + smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0); +} + +/* Parse SMUX_CLOSE message. */ +void +smux_parse_close (char *ptr, int len) +{ + long reason = 0; + + while (len--) + { + reason = (reason << 8) | (long) *ptr; + ptr++; + } + zlog_info ("SMUX_CLOSE with reason: %ld", reason); +} + +/* SMUX_RRSP message. */ +void +smux_parse_rrsp (char *ptr, int len) +{ + char val; + long errstat; + + ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat)); + + if (debug_smux) + zlog_info ("SMUX_RRSP value: %d errstat: %ld", val, errstat); +} + +/* Parse SMUX message. */ +int +smux_parse (char *ptr, int len) +{ + /* This buffer we'll use for SOUT message. We could allocate it with + malloc and save only static pointer/lenght, but IMHO static + buffer is a faster solusion. */ + static u_char sout_save_buff[SMUXMAXPKTSIZE]; + static int sout_save_len = 0; + + int len_income = len; /* see note below: YYY */ + u_char type; + u_char rollback; + + rollback = ptr[2]; /* important only for SMUX_SOUT */ + +process_rest: /* see note below: YYY */ + + /* Parse SMUX message type and subsequent length. */ + ptr = asn_parse_header (ptr, &len, &type); + + if (debug_smux) + zlog_info ("SMUX message received type: %d rest len: %d", type, len); + + switch (type) + { + case SMUX_OPEN: + /* Open must be not send from SNMP agent. */ + zlog_warn ("SMUX_OPEN received: resetting connection."); + return -1; + break; + case SMUX_RREQ: + /* SMUX_RREQ message is invalid for us. */ + zlog_warn ("SMUX_RREQ received: resetting connection."); + return -1; + break; + case SMUX_SOUT: + /* SMUX_SOUT message is now valied for us. */ + if (debug_smux) + zlog_info ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit"); + + if (sout_save_len > 0) + { + smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT); + sout_save_len = 0; + } + else + zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len); + + if (len_income > 3) + { + /* YYY: this strange code has to solve the "slow peer" + problem: When agent sends SMUX_SOUT message it doesn't + wait any responce and may send some next message to + subagent. Then the peer in 'smux_read()' will recieve + from socket the 'concatenated' buffer, contaning both + SMUX_SOUT message and the next one + (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if + the buffer is longer than 3 ( length of SMUX_SOUT ), we + must process the rest of it. This effect may be observed + if 'debug_smux' is set to '1' */ + ptr++; + len = len_income - 3; + goto process_rest; + } + break; + case SMUX_GETRSP: + /* SMUX_GETRSP message is invalid for us. */ + zlog_warn ("SMUX_GETRSP received: resetting connection."); + return -1; + break; + case SMUX_CLOSE: + /* Close SMUX connection. */ + if (debug_smux) + zlog_info ("SMUX_CLOSE"); + smux_parse_close (ptr, len); + return -1; + break; + case SMUX_RRSP: + /* This is response for register message. */ + if (debug_smux) + zlog_info ("SMUX_RRSP"); + smux_parse_rrsp (ptr, len); + break; + case SMUX_GET: + /* Exact request for object id. */ + if (debug_smux) + zlog_info ("SMUX_GET"); + smux_parse_get (ptr, len, 1); + break; + case SMUX_GETNEXT: + /* Next request for object id. */ + if (debug_smux) + zlog_info ("SMUX_GETNEXT"); + smux_parse_get (ptr, len, 0); + break; + case SMUX_SET: + /* SMUX_SET is supported with some limitations. */ + if (debug_smux) + zlog_info ("SMUX_SET"); + + /* save the data for future SMUX_SOUT */ + memcpy (sout_save_buff, ptr, len); + sout_save_len = len; + smux_parse_set (ptr, len, RESERVE1); + break; + default: + zlog_info ("Unknown type: %d", type); + break; + } + return 0; +} + +/* SMUX message read function. */ +int +smux_read (struct thread *t) +{ + int sock; + int len; + u_char buf[SMUXMAXPKTSIZE]; + int ret; + + /* Clear thread. */ + sock = THREAD_FD (t); + smux_read_thread = NULL; + + if (debug_smux) + zlog_info ("SMUX read start"); + + /* Read message from SMUX socket. */ + len = recv (sock, buf, SMUXMAXPKTSIZE, 0); + + if (len < 0) + { + zlog_warn ("Can't read all SMUX packet: %s", strerror (errno)); + close (sock); + smux_sock = -1; + smux_event (SMUX_CONNECT, 0); + return -1; + } + + if (len == 0) + { + zlog_warn ("SMUX connection closed: %d", sock); + close (sock); + smux_sock = -1; + smux_event (SMUX_CONNECT, 0); + return -1; + } + + if (debug_smux) + zlog_info ("SMUX read len: %d", len); + + /* Parse the message. */ + ret = smux_parse (buf, len); + + if (ret < 0) + { + close (sock); + smux_sock = -1; + smux_event (SMUX_CONNECT, 0); + return -1; + } + + /* Regiser read thread. */ + smux_event (SMUX_READ, sock); + + return 0; +} + +int +smux_open (int sock) +{ + u_char buf[BUFSIZ]; + u_char *ptr; + int len; + u_long version; + u_char progname[] = "zebra-" ZEBRA_VERSION; + + if (debug_smux) + { + smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len); + zlog_info ("SMUX open progname: %s", progname); + zlog_info ("SMUX open password: %s", smux_passwd); + } + + ptr = buf; + len = BUFSIZ; + + /* SMUX Header. As placeholder. */ + ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0); + + /* SMUX Open. */ + version = 0; + ptr = asn_build_int (ptr, &len, + (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), + &version, sizeof (u_long)); + + /* SMUX connection oid. */ + ptr = asn_build_objid (ptr, &len, + (u_char) + (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID), + smux_oid, smux_oid_len); + + /* SMUX connection description. */ + ptr = asn_build_string (ptr, &len, + (u_char) + (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), + progname, strlen (progname)); + + /* SMUX connection password. */ + ptr = asn_build_string (ptr, &len, + (u_char) + (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), + smux_passwd, strlen (smux_passwd)); + + /* Fill in real SMUX header. We exclude ASN header size (2). */ + len = BUFSIZ; + asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2); + + return send (sock, buf, (ptr - buf), 0); +} + +int +smux_trap (oid *name, size_t namelen, + oid *iname, size_t inamelen, + struct trap_object *trapobj, size_t trapobjlen, + unsigned int tick, u_char sptrap) +{ + int i; + u_char buf[BUFSIZ]; + u_char *ptr; + int len, length; + struct in_addr addr; + unsigned long val; + u_char *h1, *h1e; + + ptr = buf; + len = BUFSIZ; + length = len; + + /* When SMUX connection is not established. */ + if (smux_sock < 0) + return 0; + + /* SMUX header. */ + ptr = asn_build_header (ptr, &len, (u_char) SMUX_TRAP, 0); + + /* Sub agent enterprise oid. */ + ptr = asn_build_objid (ptr, &len, + (u_char) + (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID), + smux_oid, smux_oid_len); + + /* IP address. */ + addr.s_addr = 0; + ptr = asn_build_string (ptr, &len, + (u_char) + (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_IPADDRESS), + (u_char *)&addr, sizeof (struct in_addr)); + + /* Generic trap integer. */ + val = SNMP_TRAP_ENTERPRISESPECIFIC; + ptr = asn_build_int (ptr, &len, + (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), + &val, sizeof (int)); + + /* Specific trap integer. */ + val = sptrap; + ptr = asn_build_int (ptr, &len, + (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), + &val, sizeof (int)); + + /* Timeticks timestamp. */ + val = 0; + ptr = asn_build_unsigned_int (ptr, &len, + (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS), + &val, sizeof (int)); + + /* Variables. */ + h1 = ptr; + ptr = asn_build_sequence (ptr, &len, + (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), + 0); + + + /* Iteration for each objects. */ + h1e = ptr; + for (i = 0; i < trapobjlen; i++) + { + int ret; + oid oid[MAX_OID_LEN]; + size_t oid_len; + void *val; + size_t val_len; + u_char val_type; + + /* Make OID. */ + oid_copy (oid, name, namelen); + oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen); + oid_copy (oid + namelen + trapobj[i].namelen, iname, inamelen); + oid_len = namelen + trapobj[i].namelen + inamelen; + + if (debug_smux) + smux_oid_dump ("Trap", oid, oid_len); + + ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len); + + if (debug_smux) + zlog_info ("smux_get result %d", ret); + + if (ret == 0) + ptr = snmp_build_var_op (ptr, oid, &oid_len, + val_type, val_len, val, &len); + } + + /* Now variable size is known, fill in size */ + asn_build_sequence(h1, &length, + (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), + ptr - h1e); + + /* Fill in size of whole sequence */ + len = BUFSIZ; + asn_build_header (buf, &len, (u_char) SMUX_TRAP, (ptr - buf) - 2); + + return send (smux_sock, buf, (ptr - buf), 0); +} + +int +smux_register (int sock) +{ + u_char buf[BUFSIZ]; + u_char *ptr; + int len, ret; + long priority; + long operation; + struct subtree *subtree; + struct listnode *node; + + ret = 0; + + for (node = treelist->head; node; node = node->next) + { + ptr = buf; + len = BUFSIZ; + + subtree = node->data; + + /* SMUX RReq Header. */ + ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0); + + /* Register MIB tree. */ + ptr = asn_build_objid (ptr, &len, + (u_char) + (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID), + subtree->name, subtree->name_len); + + /* Priority. */ + priority = -1; + ptr = asn_build_int (ptr, &len, + (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), + &priority, sizeof (u_long)); + + /* Operation. */ + operation = 2; /* Register R/W */ + ptr = asn_build_int (ptr, &len, + (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), + &operation, sizeof (u_long)); + + if (debug_smux) + { + smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len); + zlog_info ("SMUX register priority: %ld", priority); + zlog_info ("SMUX register operation: %ld", operation); + } + + len = BUFSIZ; + asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2); + ret = send (sock, buf, (ptr - buf), 0); + if (ret < 0) + return ret; + } + return ret; +} + +/* Try to connect to SNMP agent. */ +int +smux_connect (struct thread *t) +{ + int ret; + + if (debug_smux) + zlog_info ("SMUX connect try %d", fail + 1); + + /* Clear thread poner of myself. */ + smux_connect_thread = NULL; + + /* Make socket. Try to connect. */ + smux_sock = smux_socket (); + if (smux_sock < 0) + { + if (++fail < SMUX_MAX_FAILURE) + smux_event (SMUX_CONNECT, 0); + return 0; + } + + /* Send OPEN PDU. */ + ret = smux_open (smux_sock); + if (ret < 0) + { + zlog_warn ("SMUX open message send failed: %s", strerror (errno)); + close (smux_sock); + smux_sock = -1; + if (++fail < SMUX_MAX_FAILURE) + smux_event (SMUX_CONNECT, 0); + return -1; + } + + /* Send any outstanding register PDUs. */ + ret = smux_register (smux_sock); + if (ret < 0) + { + zlog_warn ("SMUX register message send failed: %s", strerror (errno)); + close (smux_sock); + smux_sock = -1; + if (++fail < SMUX_MAX_FAILURE) + smux_event (SMUX_CONNECT, 0); + return -1; + } + + /* Everything goes fine. */ + smux_event (SMUX_READ, smux_sock); + + return 0; +} + +/* Clear all SMUX related resources. */ +void +smux_stop () +{ + if (smux_read_thread) + thread_cancel (smux_read_thread); + if (smux_connect_thread) + thread_cancel (smux_connect_thread); + + if (smux_sock >= 0) + { + close (smux_sock); + smux_sock = -1; + } +} + +extern struct thread_master *master; + +void +smux_event (enum smux_event event, int sock) +{ + switch (event) + { + case SMUX_SCHEDULE: + smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0); + break; + case SMUX_CONNECT: + smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10); + break; + case SMUX_READ: + smux_read_thread = thread_add_read (master, smux_read, NULL, sock); + break; + default: + break; + } +} + +int +smux_str2oid (char *str, oid *oid, size_t *oid_len) +{ + int len; + int val; + + len = 0; + val = 0; + *oid_len = 0; + + if (*str == '.') + str++; + if (*str == '\0') + return 0; + + while (1) + { + if (! isdigit (*str)) + return -1; + + while (isdigit (*str)) + { + val *= 10; + val += (*str - '0'); + str++; + } + + if (*str == '\0') + break; + if (*str != '.') + return -1; + + oid[len++] = val; + val = 0; + str++; + } + + oid[len++] = val; + *oid_len = len; + + return 0; +} + +oid * +smux_oid_dup (oid *objid, size_t objid_len) +{ + oid *new; + + new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len); + oid_copy (new, objid, objid_len); + + return new; +} + +int +smux_peer_oid (struct vty *vty, char *oid_str, char *passwd_str) +{ + int ret; + oid oid[MAX_OID_LEN]; + size_t oid_len; + + ret = smux_str2oid (oid_str, oid, &oid_len); + if (ret != 0) + { + vty_out (vty, "object ID malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (smux_oid && smux_oid != smux_default_oid) + free (smux_oid); + + if (smux_passwd && smux_passwd != smux_default_passwd) + { + free (smux_passwd); + smux_passwd = NULL; + } + + smux_oid = smux_oid_dup (oid, oid_len); + smux_oid_len = oid_len; + + if (passwd_str) + smux_passwd = strdup (passwd_str); + + return CMD_SUCCESS; +} + +int +smux_header_generic (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + oid fulloid[MAX_OID_LEN]; + int ret; + + oid_copy (fulloid, v->name, v->namelen); + fulloid[v->namelen] = 0; + /* Check against full instance. */ + ret = oid_compare (name, *length, fulloid, v->namelen + 1); + + /* Check single instance. */ + if ((exact && (ret != 0)) || (!exact && (ret >= 0))) + return MATCH_FAILED; + + /* In case of getnext, fill in full instance. */ + memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid)); + *length = v->namelen + 1; + + *write_method = 0; + *var_len = sizeof(long); /* default to 'long' results */ + + return MATCH_SUCCEEDED; +} + +int +smux_peer_default () +{ + if (smux_oid != smux_default_oid) + { + free (smux_oid); + smux_oid = smux_default_oid; + smux_oid_len = smux_default_oid_len; + } + if (smux_passwd != smux_default_passwd) + { + free (smux_passwd); + smux_passwd = smux_default_passwd; + } + return CMD_SUCCESS; +} + +DEFUN (smux_peer, + smux_peer_cmd, + "smux peer OID", + "SNMP MUX protocol settings\n" + "SNMP MUX peer settings\n" + "Object ID used in SMUX peering\n") +{ + return smux_peer_oid (vty, argv[0], NULL); +} + +DEFUN (smux_peer_password, + smux_peer_password_cmd, + "smux peer OID PASSWORD", + "SNMP MUX protocol settings\n" + "SNMP MUX peer settings\n" + "SMUX peering object ID\n" + "SMUX peering password\n") +{ + return smux_peer_oid (vty, argv[0], argv[1]); +} + +DEFUN (no_smux_peer, + no_smux_peer_cmd, + "no smux peer OID", + NO_STR + "SNMP MUX protocol settings\n" + "SNMP MUX peer settings\n" + "Object ID used in SMUX peering\n") +{ + return smux_peer_default (); +} + +DEFUN (no_smux_peer_password, + no_smux_peer_password_cmd, + "no smux peer OID PASSWORD", + NO_STR + "SNMP MUX protocol settings\n" + "SNMP MUX peer settings\n" + "SMUX peering object ID\n" + "SMUX peering password\n") +{ + return smux_peer_default (); +} + +int +config_write_smux (struct vty *vty) +{ + int first = 1; + int i; + + if (smux_oid != smux_default_oid || smux_passwd != smux_default_passwd) + { + vty_out (vty, "smux peer "); + for (i = 0; i < smux_oid_len; i++) + { + vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]); + first = 0; + } + vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE); + } + return 0; +} + +/* Register subtree to smux master tree. */ +void +smux_register_mib (char *descr, struct variable *var, size_t width, int num, + oid name[], size_t namelen) +{ + struct subtree *tree; + + tree = (struct subtree *)malloc(sizeof(struct subtree)); + oid_copy (tree->name, name, namelen); + tree->name_len = namelen; + tree->variables = var; + tree->variables_num = num; + tree->variables_width = width; + tree->registered = 0; + listnode_add_sort(treelist, tree); +} + +void +smux_reset () +{ + /* Setting configuration to default. */ + smux_peer_default (); +} + +/* Compare function to keep treelist sorted */ +static int +smux_tree_cmp(struct subtree *tree1, struct subtree *tree2) +{ + return oid_compare(tree1->name, tree1->name_len, + tree2->name, tree2->name_len); +} + +/* Initialize some values then schedule first SMUX connection. */ +void +smux_init (oid defoid[], size_t defoid_len) +{ + /* Set default SMUX oid. */ + smux_default_oid = defoid; + smux_default_oid_len = defoid_len; + + smux_oid = smux_default_oid; + smux_oid_len = smux_default_oid_len; + smux_passwd = smux_default_passwd; + + /* Make MIB tree. */ + treelist = list_new(); + treelist->cmp = (int (*)(void *, void *))smux_tree_cmp; + + /* Install commands. */ + install_node (&smux_node, config_write_smux); + + install_element (CONFIG_NODE, &smux_peer_cmd); + install_element (CONFIG_NODE, &smux_peer_password_cmd); + install_element (CONFIG_NODE, &no_smux_peer_cmd); + install_element (CONFIG_NODE, &no_smux_peer_password_cmd); +} + +void +smux_start(void) +{ + /* Schedule first connection. */ + smux_event (SMUX_SCHEDULE, 0); +} +#endif /* HAVE_SNMP */ diff --git a/lib/smux.h b/lib/smux.h new file mode 100644 index 0000000..27f3644 --- /dev/null +++ b/lib/smux.h @@ -0,0 +1,159 @@ +/* SNMP support + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_SNMP_H +#define _ZEBRA_SNMP_H + +#define SMUX_PORT_DEFAULT 199 + +#define SMUXMAXPKTSIZE 1500 +#define SMUXMAXSTRLEN 256 + +#define SMUX_OPEN (ASN_APPLICATION | ASN_CONSTRUCTOR | 0) +#define SMUX_CLOSE (ASN_APPLICATION | ASN_PRIMITIVE | 1) +#define SMUX_RREQ (ASN_APPLICATION | ASN_CONSTRUCTOR | 2) +#define SMUX_RRSP (ASN_APPLICATION | ASN_PRIMITIVE | 3) +#define SMUX_SOUT (ASN_APPLICATION | ASN_PRIMITIVE | 4) + +#define SMUX_GET (ASN_CONTEXT | ASN_CONSTRUCTOR | 0) +#define SMUX_GETNEXT (ASN_CONTEXT | ASN_CONSTRUCTOR | 1) +#define SMUX_GETRSP (ASN_CONTEXT | ASN_CONSTRUCTOR | 2) +#define SMUX_SET (ASN_CONTEXT | ASN_CONSTRUCTOR | 3) +#define SMUX_TRAP (ASN_CONTEXT | ASN_CONSTRUCTOR | 4) + +#define SMUX_MAX_FAILURE 3 + +/* Structures here are mostly compatible with UCD SNMP 4.1.1 */ +#define MATCH_FAILED (-1) +#define MATCH_SUCCEEDED 0 + +/* SYNTAX TruthValue from SNMPv2-TC. */ +#define SNMP_TRUE 1 +#define SNMP_FALSE 2 + +/* SYNTAX RowStatus from SNMPv2-TC. */ +#define SNMP_VALID 1 +#define SNMP_INVALID 2 + +#define IN_ADDR_SIZE sizeof(struct in_addr) + +struct variable; + +#define REGISTER_MIB(descr, var, vartype, theoid) \ + smux_register_mib(descr, (struct variable *)var, sizeof(struct vartype), \ + sizeof(var)/sizeof(struct vartype), \ + theoid, sizeof(theoid)/sizeof(oid)) + +typedef int (WriteMethod)(int action, + u_char *var_val, + u_char var_val_type, + size_t var_val_len, + u_char *statP, + oid *name, + size_t length, + struct variable *v); + +typedef u_char *(FindVarMethod)(struct variable *v, + oid *name, + size_t *length, + int exact, + size_t *var_len, + WriteMethod **write_method); + +/* SNMP variable */ +struct variable +{ + /* Index of the MIB.*/ + u_char magic; + + /* Type of variable. */ + char type; + + /* Access control list. */ + u_short acl; + + /* Callback function. */ + FindVarMethod *findVar; + + /* Suffix of the MIB. */ + u_char namelen; + oid name[MAX_OID_LEN]; +}; + +/* SNMP tree. */ +struct subtree +{ + /* Tree's oid. */ + oid name[MAX_OID_LEN]; + u_char name_len; + + /* List of the variables. */ + struct variable *variables; + + /* Length of the variables list. */ + int variables_num; + + /* Width of the variables list. */ + int variables_width; + + /* Registered flag. */ + int registered; +}; + +struct trap_object +{ + FindVarMethod *findVar; + u_char namelen; + oid name[MAX_OID_LEN]; +}; + +/* Declare SMUX return value. */ +#define SNMP_LOCAL_VARIABLES \ + static int32_t snmp_int_val; \ + static struct in_addr snmp_in_addr_val; + +#define SNMP_INTEGER(V) \ + ( \ + *var_len = sizeof (int32_t), \ + snmp_int_val = V, \ + (u_char *) &snmp_int_val \ + ) + +#define SNMP_IPADDRESS(V) \ + ( \ + *var_len = sizeof (struct in_addr), \ + snmp_in_addr_val = V, \ + (u_char *) &snmp_in_addr_val \ + ) + +void smux_init (oid [], size_t); +void smux_start (void); +void smux_register_mib(char *, struct variable *, size_t, int, oid [], size_t); +int smux_header_generic (struct variable *, oid [], size_t *, int, size_t *, + WriteMethod **); +int smux_trap (oid *, size_t, oid *, size_t, struct trap_object *, size_t, unsigned int, u_char); + +int oid_compare (oid *, int, oid *, int); +void oid2in_addr (oid [], int, struct in_addr *); +void *oid_copy (void *, void *, size_t); +void oid_copy_addr (oid [], struct in_addr *, int); + +#endif /* _ZEBRA_SNMP_H */ diff --git a/lib/sockopt.c b/lib/sockopt.c new file mode 100644 index 0000000..e2beca9 --- /dev/null +++ b/lib/sockopt.c @@ -0,0 +1,199 @@ +/* setsockopt functions + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include "log.h" + +#ifdef HAVE_IPV6 +/* Set IPv6 packet info to the socket. */ +int +setsockopt_ipv6_pktinfo (int sock, int val) +{ + int ret; + +#ifdef IPV6_RECVPKTINFO /*2292bis-01*/ + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_RECVPKTINFO : %s", strerror (errno)); +#else /*RFC2292*/ + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_PKTINFO : %s", strerror (errno)); +#endif /* INIA_IPV6 */ + return ret; +} + +/* Set multicast hops val to the socket. */ +int +setsockopt_ipv6_checksum (int sock, int val) +{ + int ret; + +#ifdef GNU_LINUX + ret = setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val)); +#else + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val)); +#endif /* GNU_LINUX */ + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_CHECKSUM"); + return ret; +} + +/* Set multicast hops val to the socket. */ +int +setsockopt_ipv6_multicast_hops (int sock, int val) +{ + int ret; + + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_MULTICAST_HOPS"); + return ret; +} + +/* Set multicast hops val to the socket. */ +int +setsockopt_ipv6_unicast_hops (int sock, int val) +{ + int ret; + + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_UNICAST_HOPS"); + return ret; +} + +int +setsockopt_ipv6_hoplimit (int sock, int val) +{ + int ret; + +#ifdef IPV6_RECVHOPLIMIT /*2292bis-01*/ + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_RECVHOPLIMIT"); +#else /*RFC2292*/ + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_HOPLIMIT"); +#endif + return ret; +} + +/* Set multicast loop zero to the socket. */ +int +setsockopt_ipv6_multicast_loop (int sock, int val) +{ + int ret; + + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, + sizeof (val)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_MULTICAST_LOOP"); + return ret; +} + +#endif /* HAVE_IPV6 */ + + +/* Set up a multicast socket options for IPv4 + This is here so that people only have to do their OS multicast mess + in one place rather than all through zebra, ospfd, and ripd + NB: This is a hookpoint for specific OS functionality */ +int +setsockopt_multicast_ipv4(int sock, + int optname, + struct in_addr if_addr, + unsigned int mcast_addr, + unsigned int ifindex) +{ + + /* Linux 2.2.0 and up */ +#if defined(GNU_LINUX) && LINUX_VERSION_CODE > 131584 + /* This is better because it uses ifindex directly */ + struct ip_mreqn mreqn; + + switch (optname) + { + case IP_MULTICAST_IF: + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + memset (&mreqn, 0, sizeof(mreqn)); + + if (mcast_addr) + mreqn.imr_multiaddr.s_addr = mcast_addr; + + if (ifindex) + mreqn.imr_ifindex = ifindex; + else + mreqn.imr_address = if_addr; + + return setsockopt(sock, IPPROTO_IP, optname, (void *)&mreqn, sizeof(mreqn)); + break; + + default: + /* Can out and give an understandable error */ + errno = EINVAL; + return -1; + break; + } + + /* Example defines for another OS, boilerplate off other code in this + function, AND handle optname as per other sections for consistency !! */ + /* #elif defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */ + /* Add your favourite OS here! */ + +#else /* #if OS_TYPE */ + /* default OS support */ + + struct in_addr m; + struct ip_mreq mreq; + + switch (optname) + { + case IP_MULTICAST_IF: + m = if_addr; + + return setsockopt (sock, IPPROTO_IP, optname, (void *)&m, sizeof(m)); + break; + + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + memset (&mreq, 0, sizeof(mreq)); + mreq.imr_multiaddr.s_addr = mcast_addr; + mreq.imr_interface = if_addr; + + return setsockopt (sock, + IPPROTO_IP, + optname, + (void *)&mreq, + sizeof(mreq)); + break; + + default: + /* Can out and give an understandable error */ + errno = EINVAL; + return -1; + break; + } +#endif /* #if OS_TYPE */ + +} diff --git a/lib/sockopt.h b/lib/sockopt.h new file mode 100644 index 0000000..7fb31c1 --- /dev/null +++ b/lib/sockopt.h @@ -0,0 +1,41 @@ +/* Router advertisement + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_SOCKOPT_H +#define _ZEBRA_SOCKOPT_H + +#ifdef HAVE_IPV6 +int setsockopt_ipv6_pktinfo (int, int); +int setsockopt_ipv6_checksum (int, int); +int setsockopt_ipv6_multicast_hops (int, int); +int setsockopt_ipv6_unicast_hops (int, int); +int setsockopt_ipv6_hoplimit (int, int); +int setsockopt_ipv6_multicast_loop (int, int); +#endif /* HAVE_IPV6 */ + +int setsockopt_multicast_ipv4(int sock, + int optname, + struct in_addr if_addr, + unsigned int mcast_addr, + unsigned int ifindex); + + +#endif /*_ZEBRA_SOCKOPT_H */ diff --git a/lib/sockunion.c b/lib/sockunion.c new file mode 100644 index 0000000..2137162 --- /dev/null +++ b/lib/sockunion.c @@ -0,0 +1,756 @@ +/* Socket union related function. + * Copyright (c) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "vty.h" +#include "sockunion.h" +#include "memory.h" +#include "str.h" +#include "log.h" + +#ifndef HAVE_INET_ATON +int +inet_aton (const char *cp, struct in_addr *inaddr) +{ + int dots = 0; + register u_long addr = 0; + register u_long val = 0, base = 10; + + do + { + register char c = *cp; + + switch (c) + { + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + val = (val * base) + (c - '0'); + break; + case '.': + if (++dots > 3) + return 0; + case '\0': + if (val > 255) + return 0; + addr = addr << 8 | val; + val = 0; + break; + default: + return 0; + } + } while (*cp++) ; + + if (dots < 3) + addr <<= 8 * (3 - dots); + if (inaddr) + inaddr->s_addr = htonl (addr); + return 1; +} +#endif /* ! HAVE_INET_ATON */ + + +#ifndef HAVE_INET_PTON +int +inet_pton (int family, const char *strptr, void *addrptr) +{ + if (family == AF_INET) + { + struct in_addr in_val; + + if (inet_aton (strptr, &in_val)) + { + memcpy (addrptr, &in_val, sizeof (struct in_addr)); + return 1; + } + return 0; + } + errno = EAFNOSUPPORT; + return -1; +} +#endif /* ! HAVE_INET_PTON */ + +#ifndef HAVE_INET_NTOP +const char * +inet_ntop (int family, const void *addrptr, char *strptr, size_t len) +{ + unsigned char *p = (unsigned char *) addrptr; + + if (family == AF_INET) + { + char temp[INET_ADDRSTRLEN]; + + snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + + if (strlen(temp) >= len) + { + errno = ENOSPC; + return NULL; + } + strcpy(strptr, temp); + return strptr; + } + + errno = EAFNOSUPPORT; + return NULL; +} +#endif /* ! HAVE_INET_NTOP */ + +const char * +inet_sutop (union sockunion *su, char *str) +{ + switch (su->sa.sa_family) + { + case AF_INET: + inet_ntop (AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN); + break; +#endif /* HAVE_IPV6 */ + } + return str; +} + +int +str2sockunion (char *str, union sockunion *su) +{ + int ret; + + memset (su, 0, sizeof (union sockunion)); + + ret = inet_pton (AF_INET, str, &su->sin.sin_addr); + if (ret > 0) /* Valid IPv4 address format. */ + { + su->sin.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + su->sin.sin_len = sizeof(struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + return 0; + } +#ifdef HAVE_IPV6 + ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr); + if (ret > 0) /* Valid IPv6 address format. */ + { + su->sin6.sin6_family = AF_INET6; +#ifdef SIN6_LEN + su->sin6.sin6_len = sizeof(struct sockaddr_in6); +#endif /* SIN6_LEN */ + return 0; + } +#endif /* HAVE_IPV6 */ + return -1; +} + +const char * +sockunion2str (union sockunion *su, char *buf, size_t len) +{ + if (su->sa.sa_family == AF_INET) + return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len); +#ifdef HAVE_IPV6 + else if (su->sa.sa_family == AF_INET6) + return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len); +#endif /* HAVE_IPV6 */ + return NULL; +} + +union sockunion * +sockunion_str2su (char *str) +{ + int ret; + union sockunion *su; + + su = XMALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); + memset (su, 0, sizeof (union sockunion)); + + ret = inet_pton (AF_INET, str, &su->sin.sin_addr); + if (ret > 0) /* Valid IPv4 address format. */ + { + su->sin.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + su->sin.sin_len = sizeof(struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + return su; + } +#ifdef HAVE_IPV6 + ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr); + if (ret > 0) /* Valid IPv6 address format. */ + { + su->sin6.sin6_family = AF_INET6; +#ifdef SIN6_LEN + su->sin6.sin6_len = sizeof(struct sockaddr_in6); +#endif /* SIN6_LEN */ + return su; + } +#endif /* HAVE_IPV6 */ + + XFREE (MTYPE_SOCKUNION, su); + return NULL; +} + +char * +sockunion_su2str (union sockunion *su) +{ + char str[INET6_ADDRSTRLEN]; + + switch (su->sa.sa_family) + { + case AF_INET: + inet_ntop (AF_INET, &su->sin.sin_addr, str, sizeof (str)); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, sizeof (str)); + break; +#endif /* HAVE_IPV6 */ + } + return strdup (str); +} + +/* Return socket of sockunion. */ +int +sockunion_socket (union sockunion *su) +{ + int sock; + + sock = socket (su->sa.sa_family, SOCK_STREAM, 0); + if (sock < 0) + { + zlog (NULL, LOG_WARNING, "Can't make socket : %s", strerror (errno)); + return -1; + } + + return sock; +} + +/* Return accepted new socket file descriptor. */ +int +sockunion_accept (int sock, union sockunion *su) +{ + socklen_t len; + int client_sock; + + len = sizeof (union sockunion); + client_sock = accept (sock, (struct sockaddr *) su, &len); + + /* Convert IPv4 compatible IPv6 address to IPv4 address. */ +#ifdef HAVE_IPV6 + if (su->sa.sa_family == AF_INET6) + { + if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr)) + { + struct sockaddr_in sin; + + memset (&sin, 0, sizeof (struct sockaddr_in)); + sin.sin_family = AF_INET; + memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4); + memcpy (su, &sin, sizeof (struct sockaddr_in)); + } + } +#endif /* HAVE_IPV6 */ + + return client_sock; +} + +/* Return sizeof union sockunion. */ +int +sockunion_sizeof (union sockunion *su) +{ + int ret; + + ret = 0; + switch (su->sa.sa_family) + { + case AF_INET: + ret = sizeof (struct sockaddr_in); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + ret = sizeof (struct sockaddr_in6); + break; +#endif /* AF_INET6 */ + } + return ret; +} + +/* return sockunion structure : this function should be revised. */ +char * +sockunion_log (union sockunion *su) +{ + static char buf[SU_ADDRSTRLEN]; + + switch (su->sa.sa_family) + { + case AF_INET: + snprintf (buf, BUFSIZ, "%s", inet_ntoa (su->sin.sin_addr)); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + snprintf (buf, BUFSIZ, "%s", + inet_ntop (AF_INET6, &(su->sin6.sin6_addr), buf, BUFSIZ)); + break; +#endif /* HAVE_IPV6 */ + default: + snprintf (buf, BUFSIZ, "af_unknown %d ", su->sa.sa_family); + break; + } + return buf; +} + +/* sockunion_connect returns + -1 : error occured + 0 : connect success + 1 : connect is in progress */ +enum connect_result +sockunion_connect (int fd, union sockunion *peersu, unsigned short port, + unsigned int ifindex) +{ + int ret; + int val; + union sockunion su; + + memcpy (&su, peersu, sizeof (union sockunion)); + + switch (su.sa.sa_family) + { + case AF_INET: + su.sin.sin_port = port; + break; +#ifdef HAVE_IPV6 + case AF_INET6: + su.sin6.sin6_port = port; +#ifdef KAME + if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex) + { +#ifdef HAVE_SIN6_SCOPE_ID + /* su.sin6.sin6_scope_id = ifindex; */ +#endif /* HAVE_SIN6_SCOPE_ID */ + SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex); + } +#endif /* KAME */ + break; +#endif /* HAVE_IPV6 */ + } + + /* Make socket non-block. */ + val = fcntl (fd, F_GETFL, 0); + fcntl (fd, F_SETFL, val|O_NONBLOCK); + + /* Call connect function. */ + ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su)); + + /* Immediate success */ + if (ret == 0) + { + fcntl (fd, F_SETFL, val); + return connect_success; + } + + /* If connect is in progress then return 1 else it's real error. */ + if (ret < 0) + { + if (errno != EINPROGRESS) + { + zlog_info ("can't connect to %s fd %d : %s", + sockunion_log (&su), fd, strerror (errno)); + return connect_error; + } + } + + fcntl (fd, F_SETFL, val); + + return connect_in_progress; +} + +/* Make socket from sockunion union. */ +int +sockunion_stream_socket (union sockunion *su) +{ + int sock; + + if (su->sa.sa_family == 0) + su->sa.sa_family = AF_INET_UNION; + + sock = socket (su->sa.sa_family, SOCK_STREAM, 0); + + if (sock < 0) + zlog (NULL, LOG_WARNING, "can't make socket sockunion_stream_socket"); + + return sock; +} + +/* Bind socket to specified address. */ +int +sockunion_bind (int sock, union sockunion *su, unsigned short port, + union sockunion *su_addr) +{ + int size = 0; + int ret; + + if (su->sa.sa_family == AF_INET) + { + size = sizeof (struct sockaddr_in); + su->sin.sin_port = htons (port); +#ifdef HAVE_SIN_LEN + su->sin.sin_len = size; +#endif /* HAVE_SIN_LEN */ + if (su_addr == NULL) + su->sin.sin_addr.s_addr = htonl (INADDR_ANY); + } +#ifdef HAVE_IPV6 + else if (su->sa.sa_family == AF_INET6) + { + size = sizeof (struct sockaddr_in6); + su->sin6.sin6_port = htons (port); +#ifdef SIN6_LEN + su->sin6.sin6_len = size; +#endif /* SIN6_LEN */ + if (su_addr == NULL) + { +#if defined(LINUX_IPV6) || defined(NRL) + memset (&su->sin6.sin6_addr, 0, sizeof (struct in6_addr)); +#else + su->sin6.sin6_addr = in6addr_any; +#endif /* LINUX_IPV6 */ + } + } +#endif /* HAVE_IPV6 */ + + + ret = bind (sock, (struct sockaddr *)su, size); + if (ret < 0) + zlog (NULL, LOG_WARNING, "can't bind socket : %s", strerror (errno)); + + return ret; +} + +int +sockopt_reuseaddr (int sock) +{ + int ret; + int on = 1; + + ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, + (void *) &on, sizeof (on)); + if (ret < 0) + { + zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock); + return -1; + } + return 0; +} + +#ifdef SO_REUSEPORT +int +sockopt_reuseport (int sock) +{ + int ret; + int on = 1; + + ret = setsockopt (sock, SOL_SOCKET, SO_REUSEPORT, + (void *) &on, sizeof (on)); + if (ret < 0) + { + zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock); + return -1; + } + return 0; +} +#else +int +sockopt_reuseport (int sock) +{ + return 0; +} +#endif /* 0 */ + +int +sockopt_ttl (int family, int sock, int ttl) +{ + int ret; + +#ifdef IP_TTL + if (family == AF_INET) + { + ret = setsockopt (sock, IPPROTO_IP, IP_TTL, + (void *) &ttl, sizeof (int)); + if (ret < 0) + { + zlog (NULL, LOG_WARNING, "can't set sockopt IP_TTL %d to socket %d", ttl, sock); + return -1; + } + return 0; + } +#endif /* IP_TTL */ +#ifdef HAVE_IPV6 + if (family == AF_INET6) + { + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, + (void *) &ttl, sizeof (int)); + if (ret < 0) + { + zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d", + ttl, sock); + return -1; + } + return 0; + } +#endif /* HAVE_IPV6 */ + return 0; +} + +/* If same family and same prefix return 1. */ +int +sockunion_same (union sockunion *su1, union sockunion *su2) +{ + int ret = 0; + + if (su1->sa.sa_family != su2->sa.sa_family) + return 0; + + switch (su1->sa.sa_family) + { + case AF_INET: + ret = memcmp (&su1->sin.sin_addr, &su2->sin.sin_addr, + sizeof (struct in_addr)); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr, + sizeof (struct in6_addr)); + break; +#endif /* HAVE_IPV6 */ + } + if (ret == 0) + return 1; + else + return 0; +} + +/* After TCP connection is established. Get local address and port. */ +union sockunion * +sockunion_getsockname (int fd) +{ + int ret; + int len; + union + { + struct sockaddr sa; + struct sockaddr_in sin; +#ifdef HAVE_IPV6 + struct sockaddr_in6 sin6; +#endif /* HAVE_IPV6 */ + char tmp_buffer[128]; + } name; + union sockunion *su; + + memset (&name, 0, sizeof name); + len = sizeof name; + + ret = getsockname (fd, (struct sockaddr *)&name, &len); + if (ret < 0) + { + zlog_warn ("Can't get local address and port by getsockname: %s", + strerror (errno)); + return NULL; + } + + if (name.sa.sa_family == AF_INET) + { + su = XCALLOC (MTYPE_TMP, sizeof (union sockunion)); + memcpy (su, &name, sizeof (struct sockaddr_in)); + return su; + } +#ifdef HAVE_IPV6 + if (name.sa.sa_family == AF_INET6) + { + su = XCALLOC (MTYPE_TMP, sizeof (union sockunion)); + memcpy (su, &name, sizeof (struct sockaddr_in6)); + + if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr)) + { + struct sockaddr_in sin; + + sin.sin_family = AF_INET; + memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4); + sin.sin_port = su->sin6.sin6_port; + memcpy (su, &sin, sizeof (struct sockaddr_in)); + } + return su; + } +#endif /* HAVE_IPV6 */ + return NULL; +} + +/* After TCP connection is established. Get remote address and port. */ +union sockunion * +sockunion_getpeername (int fd) +{ + int ret; + int len; + union + { + struct sockaddr sa; + struct sockaddr_in sin; +#ifdef HAVE_IPV6 + struct sockaddr_in6 sin6; +#endif /* HAVE_IPV6 */ + char tmp_buffer[128]; + } name; + union sockunion *su; + + memset (&name, 0, sizeof name); + len = sizeof name; + ret = getpeername (fd, (struct sockaddr *)&name, &len); + if (ret < 0) + { + zlog (NULL, LOG_WARNING, "Can't get remote address and port: %s", + strerror (errno)); + return NULL; + } + + if (name.sa.sa_family == AF_INET) + { + su = XCALLOC (MTYPE_TMP, sizeof (union sockunion)); + memcpy (su, &name, sizeof (struct sockaddr_in)); + return su; + } +#ifdef HAVE_IPV6 + if (name.sa.sa_family == AF_INET6) + { + su = XCALLOC (MTYPE_TMP, sizeof (union sockunion)); + memcpy (su, &name, sizeof (struct sockaddr_in6)); + + if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr)) + { + struct sockaddr_in sin; + + sin.sin_family = AF_INET; + memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4); + sin.sin_port = su->sin6.sin6_port; + memcpy (su, &sin, sizeof (struct sockaddr_in)); + } + return su; + } +#endif /* HAVE_IPV6 */ + return NULL; +} + +/* Print sockunion structure */ +void +sockunion_print (union sockunion *su) +{ + if (su == NULL) + return; + + switch (su->sa.sa_family) + { + case AF_INET: + printf ("%s\n", inet_ntoa (su->sin.sin_addr)); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + { + char buf [64]; + + printf ("%s\n", inet_ntop (AF_INET6, &(su->sin6.sin6_addr), + buf, sizeof (buf))); + } + break; +#endif /* HAVE_IPV6 */ + +#ifdef AF_LINK + case AF_LINK: + { + struct sockaddr_dl *sdl; + + sdl = (struct sockaddr_dl *)&(su->sa); + printf ("link#%d\n", sdl->sdl_index); + } + break; +#endif /* AF_LINK */ + default: + printf ("af_unknown %d\n", su->sa.sa_family); + break; + } +} + +#ifdef HAVE_IPV6 +int +in6addr_cmp (struct in6_addr *addr1, struct in6_addr *addr2) +{ + int i; + u_char *p1, *p2; + + p1 = (u_char *)addr1; + p2 = (u_char *)addr2; + + for (i = 0; i < sizeof (struct in6_addr); i++) + { + if (p1[i] > p2[i]) + return 1; + else if (p1[i] < p2[i]) + return -1; + } + return 0; +} +#endif /* HAVE_IPV6 */ + +int +sockunion_cmp (union sockunion *su1, union sockunion *su2) +{ + if (su1->sa.sa_family > su2->sa.sa_family) + return 1; + if (su1->sa.sa_family < su2->sa.sa_family) + return -1; + + if (su1->sa.sa_family == AF_INET) + { + if (ntohl (su1->sin.sin_addr.s_addr) == ntohl (su2->sin.sin_addr.s_addr)) + return 0; + if (ntohl (su1->sin.sin_addr.s_addr) > ntohl (su2->sin.sin_addr.s_addr)) + return 1; + else + return -1; + } +#ifdef HAVE_IPV6 + if (su1->sa.sa_family == AF_INET6) + return in6addr_cmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr); +#endif /* HAVE_IPV6 */ + return 0; +} + +/* Duplicate sockunion. */ +union sockunion * +sockunion_dup (union sockunion *su) +{ + union sockunion *dup = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); + memcpy (dup, su, sizeof (union sockunion)); + return dup; +} + +void +sockunion_free (union sockunion *su) +{ + XFREE (MTYPE_SOCKUNION, su); +} diff --git a/lib/sockunion.h b/lib/sockunion.h new file mode 100644 index 0000000..99bdf6a --- /dev/null +++ b/lib/sockunion.h @@ -0,0 +1,128 @@ +/* + * Socket union header. + * Copyright (c) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_SOCKUNION_H +#define _ZEBRA_SOCKUNION_H + +#if 0 +union sockunion { + struct sockinet { + u_char si_len; + u_char si_family; + u_short si_port; + } su_si; + struct sockaddr_in su_sin; + struct sockaddr_in6 su_sin6; +}; +#define su_len su_si.si_len +#define su_family su_si.si_family +#define su_port su_si.si_port +#endif /* 0 */ + +union sockunion +{ + struct sockaddr sa; + struct sockaddr_in sin; +#ifdef HAVE_IPV6 + struct sockaddr_in6 sin6; +#endif /* HAVE_IPV6 */ +}; + +enum connect_result +{ + connect_error, + connect_success, + connect_in_progress +}; + +/* Default address family. */ +#ifdef HAVE_IPV6 +#define AF_INET_UNION AF_INET6 +#else +#define AF_INET_UNION AF_INET +#endif + +/* Sockunion address string length. Same as INET6_ADDRSTRLEN. */ +#define SU_ADDRSTRLEN 46 + +/* Macro to set link local index to the IPv6 address. For KAME IPv6 + stack. */ +#ifdef KAME +#define IN6_LINKLOCAL_IFINDEX(a) ((a).s6_addr[2] << 8 | (a).s6_addr[3]) +#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ + do { \ + (a).s6_addr[2] = ((i) >> 8) & 0xff; \ + (a).s6_addr[3] = (i) & 0xff; \ + } while (0) +#else +#define IN6_LINKLOCAL_IFINDEX(a) +#define SET_IN6_LINKLOCAL_IFINDEX(a, i) +#endif /* KAME */ + +/* shortcut macro to specify address field of struct sockaddr */ +#define sock2ip(X) (((struct sockaddr_in *)(X))->sin_addr.s_addr) +#ifdef HAVE_IPV6 +#define sock2ip6(X) (((struct sockaddr_in6 *)(X))->sin6_addr.s6_addr) +#endif /* HAVE_IPV6 */ + +#define sockunion_family(X) (X)->sa.sa_family + +/* Prototypes. */ +int str2sockunion (char *, union sockunion *); +const char *sockunion2str (union sockunion *, char *, size_t); +int sockunion_cmp (union sockunion *, union sockunion *); +int sockunion_same (union sockunion *, union sockunion *); + +char *sockunion_su2str (union sockunion *su); +union sockunion *sockunion_str2su (char *str); +struct in_addr sockunion_get_in_addr (union sockunion *su); +int sockunion_accept (int sock, union sockunion *); +int sockunion_stream_socket (union sockunion *); +int sockopt_reuseaddr (int); +int sockopt_reuseport (int); +int sockunion_bind (int sock, union sockunion *, unsigned short, union sockunion *); +int sockopt_ttl (int family, int sock, int ttl); +int sockunion_socket (union sockunion *su); +const char *inet_sutop (union sockunion *su, char *str); +enum connect_result +sockunion_connect (int fd, union sockunion *su, unsigned short port, unsigned int); +union sockunion *sockunion_getsockname (int); +union sockunion *sockunion_getpeername (int); +union sockunion *sockunion_dup (union sockunion *); +void sockunion_free (union sockunion *); + +#ifndef HAVE_INET_NTOP +const char * +inet_ntop (int family, const void *addrptr, char *strptr, size_t len); +#endif /* HAVE_INET_NTOP */ + +#ifndef HAVE_INET_PTON +int +inet_pton (int family, const char *strptr, void *addrptr); +#endif /* HAVE_INET_PTON */ + +#ifndef HAVE_INET_ATON +int +inet_aton (const char *cp, struct in_addr *inaddr); +#endif + +#endif /* _ZEBRA_SOCKUNION_H */ diff --git a/lib/str.c b/lib/str.c new file mode 100644 index 0000000..797e9b8 --- /dev/null +++ b/lib/str.c @@ -0,0 +1,62 @@ +/* + * zebra string function + * + * these functions are just very basic wrappers around exiting ones and + * do not offer the protection that might be expected against buffer + * overruns etc + */ + +#include + +#include "str.h" + +#ifndef HAVE_SNPRINTF +/* + * snprint() is a real basic wrapper around the standard sprintf() + * without any bounds checking + */ +int +snprintf(char *str, size_t size, const char *format, ...) +{ + va_list args; + + va_start (args, format); + + return vsprintf (str, format, args); +} +#endif + +#ifndef HAVE_STRLCPY +/* + * strlcpy is a safer version of strncpy(), checking the total + * size of the buffer + */ +size_t +strlcpy(char *dst, const char *src, size_t size) +{ + strncpy(dst, src, size); + + return (strlen(dst)); +} +#endif + +#ifndef HAVE_STRLCAT +/* + * strlcat is a safer version of strncat(), checking the total + * size of the buffer + */ +size_t +strlcat(char *dst, const char *src, size_t size) +{ + /* strncpy(dst, src, size - strlen(dst)); */ + + /* I've just added below code only for workable under Linux. So + need rewrite -- Kunihiro. */ + if (strlen (dst) + strlen (src) >= size) + return -1; + + strcat (dst, src); + + return (strlen(dst)); +} +#endif diff --git a/lib/str.h b/lib/str.h new file mode 100644 index 0000000..7350442 --- /dev/null +++ b/lib/str.h @@ -0,0 +1,24 @@ +/* + * $Id: str.h,v 1.3 1999/02/19 17:01:49 developer Exp $ + */ + +#ifndef _ZEBRA_STR_H +#define _ZEBRA_STR_H + +#ifndef HAVE_SNPRINTF +int snprintf(char *, size_t, const char *, ...); +#endif + +#ifndef HAVE_VSNPRINTF +#define vsnprintf(buf, size, format, args) vsprintf(buf, format, args) +#endif + +#ifndef HAVE_STRLCPY +size_t strlcpy(char *, const char *, size_t); +#endif + +#ifndef HAVE_STRLCAT +size_t strlcat(char *, const char *, size_t); +#endif + +#endif diff --git a/lib/stream.c b/lib/stream.c new file mode 100644 index 0000000..2d4de76 --- /dev/null +++ b/lib/stream.c @@ -0,0 +1,479 @@ +/* + * Packet interface + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "stream.h" +#include "memory.h" +#include "network.h" +#include "prefix.h" + + +/*A macro to check pointers in order to not + go behind the allocated mem block + S -- stream reference + Z -- size of data to be written +*/ + +#define CHECK_SIZE(S, Z) \ + if (((S)->putp + (Z)) > (S)->size) \ + (Z) = (S)->size - (S)->putp; + +/* Stream is fixed length buffer for network output/input. */ + +/* Make stream buffer. */ +struct stream * +stream_new (size_t size) +{ + struct stream *s; + + s = XCALLOC (MTYPE_STREAM, sizeof (struct stream)); + + s->data = XCALLOC (MTYPE_STREAM_DATA, size); + s->size = size; + return s; +} + +/* Free it now. */ +void +stream_free (struct stream *s) +{ + XFREE (MTYPE_STREAM_DATA, s->data); + XFREE (MTYPE_STREAM, s); +} + +unsigned long +stream_get_getp (struct stream *s) +{ + return s->getp; +} + +unsigned long +stream_get_putp (struct stream *s) +{ + return s->putp; +} + +unsigned long +stream_get_endp (struct stream *s) +{ + return s->endp; +} + +unsigned long +stream_get_size (struct stream *s) +{ + return s->size; +} + +/* Stream structre' stream pointer related functions. */ +void +stream_set_getp (struct stream *s, unsigned long pos) +{ + s->getp = pos; +} + +void +stream_set_putp (struct stream *s, unsigned long pos) +{ + s->putp = pos; +} + +/* Forward pointer. */ +void +stream_forward (struct stream *s, int size) +{ + s->getp += size; +} + +/* Copy from stream to destination. */ +void +stream_get (void *dst, struct stream *s, size_t size) +{ + memcpy (dst, s->data + s->getp, size); + s->getp += size; +} + +/* Get next character from the stream. */ +u_char +stream_getc (struct stream *s) +{ + u_char c; + + c = s->data[s->getp]; + s->getp++; + return c; +} + +/* Get next character from the stream. */ +u_char +stream_getc_from (struct stream *s, unsigned long from) +{ + u_char c; + + c = s->data[from]; + return c; +} + +/* Get next word from the stream. */ +u_int16_t +stream_getw (struct stream *s) +{ + u_int16_t w; + + w = s->data[s->getp++] << 8; + w |= s->data[s->getp++]; + return w; +} + +/* Get next word from the stream. */ +u_int16_t +stream_getw_from (struct stream *s, unsigned long from) +{ + u_int16_t w; + + w = s->data[from++] << 8; + w |= s->data[from]; + return w; +} + +/* Get next long word from the stream. */ +u_int32_t +stream_getl (struct stream *s) +{ + u_int32_t l; + + l = s->data[s->getp++] << 24; + l |= s->data[s->getp++] << 16; + l |= s->data[s->getp++] << 8; + l |= s->data[s->getp++]; + return l; +} + +/* Get next long word from the stream. */ +u_int32_t +stream_get_ipv4 (struct stream *s) +{ + u_int32_t l; + + memcpy (&l, s->data + s->getp, 4); + s->getp += 4; + + return l; +} + +/* Copy to source to stream. */ +void +stream_put (struct stream *s, void *src, size_t size) +{ + + CHECK_SIZE(s, size); + + if (src) + memcpy (s->data + s->putp, src, size); + else + memset (s->data + s->putp, 0, size); + + s->putp += size; + if (s->putp > s->endp) + s->endp = s->putp; +} + +/* Put character to the stream. */ +int +stream_putc (struct stream *s, u_char c) +{ + if (s->putp >= s->size) return 0; + + s->data[s->putp] = c; + s->putp++; + if (s->putp > s->endp) + s->endp = s->putp; + return 1; +} + +/* Put word to the stream. */ +int +stream_putw (struct stream *s, u_int16_t w) +{ + if ((s->size - s->putp) < 2) return 0; + + s->data[s->putp++] = (u_char)(w >> 8); + s->data[s->putp++] = (u_char) w; + + if (s->putp > s->endp) + s->endp = s->putp; + return 2; +} + +/* Put long word to the stream. */ +int +stream_putl (struct stream *s, u_int32_t l) +{ + if ((s->size - s->putp) < 4) return 0; + + s->data[s->putp++] = (u_char)(l >> 24); + s->data[s->putp++] = (u_char)(l >> 16); + s->data[s->putp++] = (u_char)(l >> 8); + s->data[s->putp++] = (u_char)l; + + if (s->putp > s->endp) + s->endp = s->putp; + return 4; +} + +int +stream_putc_at (struct stream *s, unsigned long putp, u_char c) +{ + s->data[putp] = c; + return 1; +} + +int +stream_putw_at (struct stream *s, unsigned long putp, u_int16_t w) +{ + s->data[putp] = (u_char)(w >> 8); + s->data[putp + 1] = (u_char) w; + return 2; +} + +int +stream_putl_at (struct stream *s, unsigned long putp, u_int32_t l) +{ + s->data[putp] = (u_char)(l >> 24); + s->data[putp + 1] = (u_char)(l >> 16); + s->data[putp + 2] = (u_char)(l >> 8); + s->data[putp + 3] = (u_char)l; + return 4; +} + +/* Put long word to the stream. */ +int +stream_put_ipv4 (struct stream *s, u_int32_t l) +{ + if ((s->size - s->putp) < 4) + return 0; + + memcpy (s->data + s->putp, &l, 4); + s->putp += 4; + + if (s->putp > s->endp) + s->endp = s->putp; + return 4; +} + +/* Put long word to the stream. */ +int +stream_put_in_addr (struct stream *s, struct in_addr *addr) +{ + if ((s->size - s->putp) < 4) + return 0; + + memcpy (s->data + s->putp, addr, 4); + s->putp += 4; + + if (s->putp > s->endp) + s->endp = s->putp; + return 4; +} + +/* Put prefix by nlri type format. */ +int +stream_put_prefix (struct stream *s, struct prefix *p) +{ + u_char psize; + + psize = PSIZE (p->prefixlen); + + if ((s->size - s->putp) < psize) return 0; + + stream_putc (s, p->prefixlen); + memcpy (s->data + s->putp, &p->u.prefix, psize); + s->putp += psize; + + if (s->putp > s->endp) + s->endp = s->putp; + + return psize; +} + +/* Read size from fd. */ +int +stream_read (struct stream *s, int fd, size_t size) +{ + int nbytes; + + nbytes = readn (fd, s->data + s->putp, size); + + if (nbytes > 0) + { + s->putp += nbytes; + s->endp += nbytes; + } + return nbytes; +} + +/* Read size from fd. */ +int +stream_read_unblock (struct stream *s, int fd, size_t size) +{ + int nbytes; + int val; + + val = fcntl (fd, F_GETFL, 0); + fcntl (fd, F_SETFL, val|O_NONBLOCK); + nbytes = read (fd, s->data + s->putp, size); + fcntl (fd, F_SETFL, val); + + if (nbytes > 0) + { + s->putp += nbytes; + s->endp += nbytes; + } + return nbytes; +} + +/* Write data to buffer. */ +int +stream_write (struct stream *s, u_char *ptr, size_t size) +{ + + CHECK_SIZE(s, size); + + memcpy (s->data + s->putp, ptr, size); + s->putp += size; + if (s->putp > s->endp) + s->endp = s->putp; + return size; +} + +/* Return current read pointer. */ +u_char * +stream_pnt (struct stream *s) +{ + return s->data + s->getp; +} + +/* Check does this stream empty? */ +int +stream_empty (struct stream *s) +{ + if (s->putp == 0 && s->endp == 0 && s->getp == 0) + return 1; + else + return 0; +} + +/* Reset stream. */ +void +stream_reset (struct stream *s) +{ + s->putp = 0; + s->endp = 0; + s->getp = 0; +} + +/* Write stream contens to the file discriptor. */ +int +stream_flush (struct stream *s, int fd) +{ + int nbytes; + + nbytes = write (fd, s->data + s->getp, s->endp - s->getp); + + return nbytes; +} + +/* Stream first in first out queue. */ + +struct stream_fifo * +stream_fifo_new () +{ + struct stream_fifo *new; + + new = XCALLOC (MTYPE_STREAM_FIFO, sizeof (struct stream_fifo)); + return new; +} + +/* Add new stream to fifo. */ +void +stream_fifo_push (struct stream_fifo *fifo, struct stream *s) +{ + if (fifo->tail) + fifo->tail->next = s; + else + fifo->head = s; + + fifo->tail = s; + + fifo->count++; +} + +/* Delete first stream from fifo. */ +struct stream * +stream_fifo_pop (struct stream_fifo *fifo) +{ + struct stream *s; + + s = fifo->head; + + if (s) + { + fifo->head = s->next; + + if (fifo->head == NULL) + fifo->tail = NULL; + } + + fifo->count--; + + return s; +} + +/* Return first fifo entry. */ +struct stream * +stream_fifo_head (struct stream_fifo *fifo) +{ + return fifo->head; +} + +void +stream_fifo_clean (struct stream_fifo *fifo) +{ + struct stream *s; + struct stream *next; + + for (s = fifo->head; s; s = next) + { + next = s->next; + stream_free (s); + } + fifo->head = fifo->tail = NULL; + fifo->count = 0; +} + +void +stream_fifo_free (struct stream_fifo *fifo) +{ + stream_fifo_clean (fifo); + XFREE (MTYPE_STREAM_FIFO, fifo); +} diff --git a/lib/stream.h b/lib/stream.h new file mode 100644 index 0000000..c6ef3c8 --- /dev/null +++ b/lib/stream.h @@ -0,0 +1,113 @@ +/* + * Packet interface + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_STREAM_H +#define _ZEBRA_STREAM_H + +/* Stream buffer. */ +struct stream +{ + struct stream *next; + + unsigned char *data; + + /* Put pointer. */ + unsigned long putp; + + /* Get pointer. */ + unsigned long getp; + + /* End of pointer. */ + unsigned long endp; + + /* Data size. */ + unsigned long size; +}; + +/* First in first out queue structure. */ +struct stream_fifo +{ + unsigned long count; + + struct stream *head; + struct stream *tail; +}; + +/* Utility macros. */ +#define STREAM_PNT(S) ((S)->data + (S)->getp) +#define STREAM_SIZE(S) ((S)->size) +#define STREAM_REMAIN(S) ((S)->size - (S)->putp) +#define STREAM_DATA(S) ((S)->data) + +/* Stream prototypes. */ +struct stream *stream_new (size_t); +void stream_free (struct stream *); + +unsigned long stream_get_getp (struct stream *); +unsigned long stream_get_putp (struct stream *); +unsigned long stream_get_endp (struct stream *); +unsigned long stream_get_size (struct stream *); +u_char *stream_get_data (struct stream *); + +void stream_set_getp (struct stream *, unsigned long); +void stream_set_putp (struct stream *, unsigned long); + +void stream_forward (struct stream *, int); + +void stream_put (struct stream *, void *, size_t); +int stream_putc (struct stream *, u_char); +int stream_putc_at (struct stream *, unsigned long, u_char); +int stream_putw (struct stream *, u_int16_t); +int stream_putw_at (struct stream *, unsigned long, u_int16_t); +int stream_putl (struct stream *, u_int32_t); +int stream_putl_at (struct stream *, unsigned long, u_int32_t); +int stream_put_ipv4 (struct stream *, u_int32_t); +int stream_put_in_addr (struct stream *, struct in_addr *); + +void stream_get (void *, struct stream *, size_t); +u_char stream_getc (struct stream *); +u_char stream_getc_from (struct stream *, unsigned long); +u_int16_t stream_getw (struct stream *); +u_int16_t stream_getw_from (struct stream *, unsigned long); +u_int32_t stream_getl (struct stream *); +u_int32_t stream_get_ipv4 (struct stream *); + +#undef stream_read +#undef stream_write +int stream_read (struct stream *, int, size_t); +int stream_read_unblock (struct stream *, int, size_t); +int stream_write (struct stream *, u_char *, size_t); + +u_char *stream_pnt (struct stream *); +void stream_reset (struct stream *); +int stream_flush (struct stream *, int); +int stream_empty (struct stream *); + +/* Stream fifo. */ +struct stream_fifo *stream_fifo_new (); +void stream_fifo_push (struct stream_fifo *fifo, struct stream *s); +struct stream *stream_fifo_pop (struct stream_fifo *fifo); +struct stream *stream_fifo_head (struct stream_fifo *fifo); +void stream_fifo_clean (struct stream_fifo *fifo); +void stream_fifo_free (struct stream_fifo *fifo); + +#endif /* _ZEBRA_STREAM_H */ diff --git a/lib/table.c b/lib/table.c new file mode 100644 index 0000000..00ba58d --- /dev/null +++ b/lib/table.c @@ -0,0 +1,503 @@ +/* + * Routing Table functions. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "sockunion.h" + +void route_node_delete (struct route_node *); +void route_table_free (struct route_table *); + +struct route_table * +route_table_init (void) +{ + struct route_table *rt; + + rt = XCALLOC (MTYPE_ROUTE_TABLE, sizeof (struct route_table)); + return rt; +} + +void +route_table_finish (struct route_table *rt) +{ + route_table_free (rt); +} + +/* Allocate new route node. */ +struct route_node * +route_node_new () +{ + struct route_node *node; + node = XCALLOC (MTYPE_ROUTE_NODE, sizeof (struct route_node)); + return node; +} + +/* Allocate new route node with prefix set. */ +struct route_node * +route_node_set (struct route_table *table, struct prefix *prefix) +{ + struct route_node *node; + + node = route_node_new (); + + prefix_copy (&node->p, prefix); + node->table = table; + + return node; +} + +/* Free route node. */ +void +route_node_free (struct route_node *node) +{ + XFREE (MTYPE_ROUTE_NODE, node); +} + +/* Free route table. */ +void +route_table_free (struct route_table *rt) +{ + struct route_node *tmp_node; + struct route_node *node; + + if (rt == NULL) + return; + + node = rt->top; + + while (node) + { + if (node->l_left) + { + node = node->l_left; + continue; + } + + if (node->l_right) + { + node = node->l_right; + continue; + } + + tmp_node = node; + node = node->parent; + + if (node != NULL) + { + if (node->l_left == tmp_node) + node->l_left = NULL; + else + node->l_right = NULL; + + route_node_free (tmp_node); + } + else + { + route_node_free (tmp_node); + break; + } + } + + XFREE (MTYPE_ROUTE_TABLE, rt); + return; +} + +/* Utility mask array. */ +static u_char maskbit[] = +{ + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff +}; + +/* Common prefix route genaration. */ +static void +route_common (struct prefix *n, struct prefix *p, struct prefix *new) +{ + int i; + u_char diff; + u_char mask; + + u_char *np = (u_char *)&n->u.prefix; + u_char *pp = (u_char *)&p->u.prefix; + u_char *newp = (u_char *)&new->u.prefix; + + for (i = 0; i < p->prefixlen / 8; i++) + { + if (np[i] == pp[i]) + newp[i] = np[i]; + else + break; + } + + new->prefixlen = i * 8; + + if (new->prefixlen != p->prefixlen) + { + diff = np[i] ^ pp[i]; + mask = 0x80; + while (new->prefixlen < p->prefixlen && !(mask & diff)) + { + mask >>= 1; + new->prefixlen++; + } + newp[i] = np[i] & maskbit[new->prefixlen % 8]; + } +} + +/* Macro version of check_bit (). */ +#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1) + +/* Check bit of the prefix. */ +static int +check_bit (u_char *prefix, u_char prefixlen) +{ + int offset; + int shift; + u_char *p = (u_char *)prefix; + + assert (prefixlen <= 128); + + offset = prefixlen / 8; + shift = 7 - (prefixlen % 8); + + return (p[offset] >> shift & 1); +} + +/* Macro version of set_link (). */ +#define SET_LINK(X,Y) (X)->link[CHECK_BIT(&(Y)->prefix,(X)->prefixlen)] = (Y);\ + (Y)->parent = (X) + +static void +set_link (struct route_node *node, struct route_node *new) +{ + int bit; + + bit = check_bit (&new->p.u.prefix, node->p.prefixlen); + + assert (bit == 0 || bit == 1); + + node->link[bit] = new; + new->parent = node; +} + +/* Lock node. */ +struct route_node * +route_lock_node (struct route_node *node) +{ + node->lock++; + return node; +} + +/* Unlock node. */ +void +route_unlock_node (struct route_node *node) +{ + node->lock--; + + if (node->lock == 0) + route_node_delete (node); +} + +/* Dump routing table. */ +void +route_dump_node (struct route_table *t) +{ + struct route_node *node; + char buf[46]; + + for (node = route_top (t); node != NULL; node = route_next (node)) + { + printf ("[%d] %p %s/%d\n", + node->lock, + node->info, + inet_ntop (node->p.family, &node->p.u.prefix, buf, 46), + node->p.prefixlen); + } +} + +/* Find matched prefix. */ +struct route_node * +route_node_match (struct route_table *table, struct prefix *p) +{ + struct route_node *node; + struct route_node *matched; + + matched = NULL; + node = table->top; + + /* Walk down tree. If there is matched route then store it to + matched. */ + while (node && node->p.prefixlen <= p->prefixlen && + prefix_match (&node->p, p)) + { + if (node->info) + matched = node; + node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + } + + /* If matched route found, return it. */ + if (matched) + return route_lock_node (matched); + + return NULL; +} + +struct route_node * +route_node_match_ipv4 (struct route_table *table, struct in_addr *addr) +{ + struct prefix_ipv4 p; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = *addr; + + return route_node_match (table, (struct prefix *) &p); +} + +#ifdef HAVE_IPV6 +struct route_node * +route_node_match_ipv6 (struct route_table *table, struct in6_addr *addr) +{ + struct prefix_ipv6 p; + + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_PREFIXLEN; + p.prefix = *addr; + + return route_node_match (table, (struct prefix *) &p); +} +#endif /* HAVE_IPV6 */ + +/* Lookup same prefix node. Return NULL when we can't find route. */ +struct route_node * +route_node_lookup (struct route_table *table, struct prefix *p) +{ + struct route_node *node; + + node = table->top; + + while (node && node->p.prefixlen <= p->prefixlen && + prefix_match (&node->p, p)) + { + if (node->p.prefixlen == p->prefixlen && node->info) + return route_lock_node (node); + + node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + } + + return NULL; +} + +/* Add node to routing table. */ +struct route_node * +route_node_get (struct route_table *table, struct prefix *p) +{ + struct route_node *new; + struct route_node *node; + struct route_node *match; + + match = NULL; + node = table->top; + while (node && node->p.prefixlen <= p->prefixlen && + prefix_match (&node->p, p)) + { + if (node->p.prefixlen == p->prefixlen) + { + route_lock_node (node); + return node; + } + match = node; + node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + } + + if (node == NULL) + { + new = route_node_set (table, p); + if (match) + set_link (match, new); + else + table->top = new; + } + else + { + new = route_node_new (); + route_common (&node->p, p, &new->p); + new->p.family = p->family; + new->table = table; + set_link (new, node); + + if (match) + set_link (match, new); + else + table->top = new; + + if (new->p.prefixlen != p->prefixlen) + { + match = new; + new = route_node_set (table, p); + set_link (match, new); + } + } + route_lock_node (new); + + return new; +} + +/* Delete node from the routing table. */ +void +route_node_delete (struct route_node *node) +{ + struct route_node *child; + struct route_node *parent; + + assert (node->lock == 0); + assert (node->info == NULL); + + if (node->l_left && node->l_right) + return; + + if (node->l_left) + child = node->l_left; + else + child = node->l_right; + + parent = node->parent; + + if (child) + child->parent = parent; + + if (parent) + { + if (parent->l_left == node) + parent->l_left = child; + else + parent->l_right = child; + } + else + node->table->top = child; + + route_node_free (node); + + /* If parent node is stub then delete it also. */ + if (parent && parent->lock == 0) + route_node_delete (parent); +} + +/* Get fist node and lock it. This function is useful when one want + to lookup all the node exist in the routing table. */ +struct route_node * +route_top (struct route_table *table) +{ + /* If there is no node in the routing table return NULL. */ + if (table->top == NULL) + return NULL; + + /* Lock the top node and return it. */ + route_lock_node (table->top); + return table->top; +} + +/* Unlock current node and lock next node then return it. */ +struct route_node * +route_next (struct route_node *node) +{ + struct route_node *next; + struct route_node *start; + + /* Node may be deleted from route_unlock_node so we have to preserve + next node's pointer. */ + + if (node->l_left) + { + next = node->l_left; + route_lock_node (next); + route_unlock_node (node); + return next; + } + if (node->l_right) + { + next = node->l_right; + route_lock_node (next); + route_unlock_node (node); + return next; + } + + start = node; + while (node->parent) + { + if (node->parent->l_left == node && node->parent->l_right) + { + next = node->parent->l_right; + route_lock_node (next); + route_unlock_node (start); + return next; + } + node = node->parent; + } + route_unlock_node (start); + return NULL; +} + +/* Unlock current node and lock next node until limit. */ +struct route_node * +route_next_until (struct route_node *node, struct route_node *limit) +{ + struct route_node *next; + struct route_node *start; + + /* Node may be deleted from route_unlock_node so we have to preserve + next node's pointer. */ + + if (node->l_left) + { + next = node->l_left; + route_lock_node (next); + route_unlock_node (node); + return next; + } + if (node->l_right) + { + next = node->l_right; + route_lock_node (next); + route_unlock_node (node); + return next; + } + + start = node; + while (node->parent && node != limit) + { + if (node->parent->l_left == node && node->parent->l_right) + { + next = node->parent->l_right; + route_lock_node (next); + route_unlock_node (start); + return next; + } + node = node->parent; + } + route_unlock_node (start); + return NULL; +} diff --git a/lib/table.h b/lib/table.h new file mode 100644 index 0000000..6f09099 --- /dev/null +++ b/lib/table.h @@ -0,0 +1,74 @@ +/* + * Routing Table + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_TABLE_H +#define _ZEBRA_TABLE_H + +/* Routing table top structure. */ +struct route_table +{ + struct route_node *top; +}; + +/* Each routing entry. */ +struct route_node +{ + /* Actual prefix of this radix. */ + struct prefix p; + + /* Tree link. */ + struct route_table *table; + struct route_node *parent; + struct route_node *link[2]; +#define l_left link[0] +#define l_right link[1] + + /* Lock of this radix */ + unsigned int lock; + + /* Each node of route. */ + void *info; + + /* Aggregation. */ + void *aggregate; +}; + +/* Prototypes. */ +struct route_table *route_table_init (void); +void route_table_finish (struct route_table *); +void route_unlock_node (struct route_node *node); +void route_node_delete (struct route_node *node); +struct route_node *route_top (struct route_table *); +struct route_node *route_next (struct route_node *); +struct route_node *route_next_until (struct route_node *, struct route_node *); +struct route_node *route_node_get (struct route_table *, struct prefix *); +struct route_node *route_node_lookup (struct route_table *, struct prefix *); +struct route_node *route_lock_node (struct route_node *node); +struct route_node *route_node_match (struct route_table *, struct prefix *); +struct route_node *route_node_match_ipv4 (struct route_table *, + struct in_addr *); +#ifdef HAVE_IPV6 +struct route_node *route_node_match_ipv6 (struct route_table *, + struct in6_addr *); +#endif /* HAVE_IPV6 */ + +#endif /* _ZEBRA_TABLE_H */ diff --git a/lib/thread.c b/lib/thread.c new file mode 100644 index 0000000..e8dfc2e --- /dev/null +++ b/lib/thread.c @@ -0,0 +1,689 @@ +/* Thread management routine + * Copyright (C) 1998, 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* #define DEBUG */ + +#include + +#include "thread.h" +#include "memory.h" +#include "log.h" + +/* Struct timeval's tv_usec one second value. */ +#define TIMER_SECOND_MICRO 1000000L + +struct timeval +timeval_adjust (struct timeval a) +{ + while (a.tv_usec >= TIMER_SECOND_MICRO) + { + a.tv_usec -= TIMER_SECOND_MICRO; + a.tv_sec++; + } + + while (a.tv_usec < 0) + { + a.tv_usec += TIMER_SECOND_MICRO; + a.tv_sec--; + } + + if (a.tv_sec < 0) + { + a.tv_sec = 0; + a.tv_usec = 10; + } + + if (a.tv_sec > TIMER_SECOND_MICRO) + a.tv_sec = TIMER_SECOND_MICRO; + + return a; +} + +static struct timeval +timeval_subtract (struct timeval a, struct timeval b) +{ + struct timeval ret; + + ret.tv_usec = a.tv_usec - b.tv_usec; + ret.tv_sec = a.tv_sec - b.tv_sec; + + return timeval_adjust (ret); +} + +static int +timeval_cmp (struct timeval a, struct timeval b) +{ + return (a.tv_sec == b.tv_sec + ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec); +} + +static unsigned long +timeval_elapsed (struct timeval a, struct timeval b) +{ + return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO) + + (a.tv_usec - b.tv_usec)); +} + +/* List allocation and head/tail print out. */ +static void +thread_list_debug (struct thread_list *list) +{ + printf ("count [%d] head [%p] tail [%p]\n", + list->count, list->head, list->tail); +} + +/* Debug print for thread_master. */ +void +thread_master_debug (struct thread_master *m) +{ + printf ("-----------\n"); + printf ("readlist : "); + thread_list_debug (&m->read); + printf ("writelist : "); + thread_list_debug (&m->write); + printf ("timerlist : "); + thread_list_debug (&m->timer); + printf ("eventlist : "); + thread_list_debug (&m->event); + printf ("unuselist : "); + thread_list_debug (&m->unuse); + printf ("total alloc: [%ld]\n", m->alloc); + printf ("-----------\n"); +} + +/* Allocate new thread master. */ +struct thread_master * +thread_master_create () +{ + return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER, + sizeof (struct thread_master)); +} + +/* Add a new thread to the list. */ +static void +thread_list_add (struct thread_list *list, struct thread *thread) +{ + thread->next = NULL; + thread->prev = list->tail; + if (list->tail) + list->tail->next = thread; + else + list->head = thread; + list->tail = thread; + list->count++; +} + +/* Add a new thread just before the point. */ +static void +thread_list_add_before (struct thread_list *list, + struct thread *point, + struct thread *thread) +{ + thread->next = point; + thread->prev = point->prev; + if (point->prev) + point->prev->next = thread; + else + list->head = thread; + point->prev = thread; + list->count++; +} + +/* Delete a thread from the list. */ +static struct thread * +thread_list_delete (struct thread_list *list, struct thread *thread) +{ + if (thread->next) + thread->next->prev = thread->prev; + else + list->tail = thread->prev; + if (thread->prev) + thread->prev->next = thread->next; + else + list->head = thread->next; + thread->next = thread->prev = NULL; + list->count--; + return thread; +} + +/* Move thread to unuse list. */ +static void +thread_add_unuse (struct thread_master *m, struct thread *thread) +{ + assert (m != NULL); + assert (thread->next == NULL); + assert (thread->prev == NULL); + assert (thread->type == THREAD_UNUSED); + thread_list_add (&m->unuse, thread); +} + +/* Free all unused thread. */ +static void +thread_list_free (struct thread_master *m, struct thread_list *list) +{ + struct thread *t; + struct thread *next; + + for (t = list->head; t; t = next) + { + next = t->next; + XFREE (MTYPE_THREAD, t); + list->count--; + m->alloc--; + } +} + +/* Stop thread scheduler. */ +void +thread_master_free (struct thread_master *m) +{ + thread_list_free (m, &m->read); + thread_list_free (m, &m->write); + thread_list_free (m, &m->timer); + thread_list_free (m, &m->event); + thread_list_free (m, &m->ready); + thread_list_free (m, &m->unuse); + + XFREE (MTYPE_THREAD_MASTER, m); +} + +/* Delete top of the list and return it. */ +static struct thread * +thread_trim_head (struct thread_list *list) +{ + if (list->head) + return thread_list_delete (list, list->head); + return NULL; +} + +/* Thread list is empty or not. */ +int +thread_empty (struct thread_list *list) +{ + return list->head ? 0 : 1; +} + +/* Return remain time. */ +char * +thread_timer_remain_second (struct thread *thread) +{ + struct timeval timer_now; + struct tm *tm; + time_t remain_time; + char buf[25]; + int len = 25; + + gettimeofday (&timer_now, NULL); + + remain_time = thread->u.sands.tv_sec - timer_now.tv_sec; + + if (remain_time < 0) + remain_time = 0; + + tm = gmtime (&remain_time); + + /* Making formatted timer strings. */ +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + + if (remain_time < ONE_DAY_SECOND) + snprintf (buf, len, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (remain_time < ONE_WEEK_SECOND) + snprintf (buf, len, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + snprintf (buf, len, "%02dw%dd%02dh", + tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + return buf; +} + +/* Get new thread. */ +static struct thread * +thread_get (struct thread_master *m, u_char type, + int (*func) (struct thread *), void *arg) +{ + struct thread *thread; + + if (m->unuse.head) + thread = thread_trim_head (&m->unuse); + else + { + thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread)); + m->alloc++; + } + thread->type = type; + thread->master = m; + thread->func = func; + thread->arg = arg; + + return thread; +} + +/* Add new read thread. */ +struct thread * +thread_add_read (struct thread_master *m, + int (*func) (struct thread *), void *arg, int fd) +{ + struct thread *thread; + + assert (m != NULL); + + if (FD_ISSET (fd, &m->readfd)) + { + zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd); + return NULL; + } + + thread = thread_get (m, THREAD_READ, func, arg); + FD_SET (fd, &m->readfd); + thread->u.fd = fd; + thread_list_add (&m->read, thread); + + return thread; +} + +/* Add new write thread. */ +struct thread * +thread_add_write (struct thread_master *m, + int (*func) (struct thread *), void *arg, int fd) +{ + struct thread *thread; + + assert (m != NULL); + + if (FD_ISSET (fd, &m->writefd)) + { + zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd); + return NULL; + } + + thread = thread_get (m, THREAD_WRITE, func, arg); + FD_SET (fd, &m->writefd); + thread->u.fd = fd; + thread_list_add (&m->write, thread); + + return thread; +} + +/* Add timer event thread. */ +struct thread * +thread_add_timer (struct thread_master *m, + int (*func) (struct thread *), void *arg, long timer) +{ + struct timeval timer_now; + struct thread *thread; +#ifndef TIMER_NO_SORT + struct thread *tt; +#endif /* TIMER_NO_SORT */ + + assert (m != NULL); + + thread = thread_get (m, THREAD_TIMER, func, arg); + + /* Do we need jitter here? */ + gettimeofday (&timer_now, NULL); + timer_now.tv_sec += timer; + thread->u.sands = timer_now; + + /* Sort by timeval. */ +#ifdef TIMER_NO_SORT + thread_list_add (&m->timer, thread); +#else + for (tt = m->timer.head; tt; tt = tt->next) + if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0) + break; + + if (tt) + thread_list_add_before (&m->timer, tt, thread); + else + thread_list_add (&m->timer, thread); +#endif /* TIMER_NO_SORT */ + + return thread; +} + +/* Add simple event thread. */ +struct thread * +thread_add_event (struct thread_master *m, + int (*func) (struct thread *), void *arg, int val) +{ + struct thread *thread; + + assert (m != NULL); + + thread = thread_get (m, THREAD_EVENT, func, arg); + thread->u.val = val; + thread_list_add (&m->event, thread); + + return thread; +} + +/* Cancel thread from scheduler. */ +void +thread_cancel (struct thread *thread) +{ + switch (thread->type) + { + case THREAD_READ: + assert (FD_ISSET (thread->u.fd, &thread->master->readfd)); + FD_CLR (thread->u.fd, &thread->master->readfd); + thread_list_delete (&thread->master->read, thread); + break; + case THREAD_WRITE: + assert (FD_ISSET (thread->u.fd, &thread->master->writefd)); + FD_CLR (thread->u.fd, &thread->master->writefd); + thread_list_delete (&thread->master->write, thread); + break; + case THREAD_TIMER: + thread_list_delete (&thread->master->timer, thread); + break; + case THREAD_EVENT: + thread_list_delete (&thread->master->event, thread); + break; + case THREAD_READY: + thread_list_delete (&thread->master->ready, thread); + break; + default: + break; + } + thread->type = THREAD_UNUSED; + thread_add_unuse (thread->master, thread); +} + +/* Delete all events which has argument value arg. */ +void +thread_cancel_event (struct thread_master *m, void *arg) +{ + struct thread *thread; + + thread = m->event.head; + while (thread) + { + struct thread *t; + + t = thread; + thread = t->next; + + if (t->arg == arg) + { + thread_list_delete (&m->event, t); + t->type = THREAD_UNUSED; + thread_add_unuse (m, t); + } + } +} + +#ifdef TIMER_NO_SORT +struct timeval * +thread_timer_wait (struct thread_master *m, struct timeval *timer_val) +{ + struct timeval timer_now; + struct timeval timer_min; + struct timeval *timer_wait; + + gettimeofday (&timer_now, NULL); + + timer_wait = NULL; + for (thread = m->timer.head; thread; thread = thread->next) + { + if (! timer_wait) + timer_wait = &thread->u.sands; + else if (timeval_cmp (thread->u.sands, *timer_wait) < 0) + timer_wait = &thread->u.sands; + } + + if (m->timer.head) + { + timer_min = *timer_wait; + timer_min = timeval_subtract (timer_min, timer_now); + if (timer_min.tv_sec < 0) + { + timer_min.tv_sec = 0; + timer_min.tv_usec = 10; + } + timer_wait = &timer_min; + } + else + timer_wait = NULL; + + if (timer_wait) + { + *timer_val = timer_wait; + return timer_val; + } + return NULL; +} +#else /* ! TIMER_NO_SORT */ +struct timeval * +thread_timer_wait (struct thread_master *m, struct timeval *timer_val) +{ + struct timeval timer_now; + struct timeval timer_min; + + if (m->timer.head) + { + gettimeofday (&timer_now, NULL); + timer_min = m->timer.head->u.sands; + timer_min = timeval_subtract (timer_min, timer_now); + if (timer_min.tv_sec < 0) + { + timer_min.tv_sec = 0; + timer_min.tv_usec = 10; + } + *timer_val = timer_min; + return timer_val; + } + return NULL; +} +#endif /* TIMER_NO_SORT */ + +struct thread * +thread_run (struct thread_master *m, struct thread *thread, + struct thread *fetch) +{ + *fetch = *thread; + thread->type = THREAD_UNUSED; + thread_add_unuse (m, thread); + return fetch; +} + +int +thread_process_fd (struct thread_master *m, struct thread_list *list, + fd_set *fdset, fd_set *mfdset) +{ + struct thread *thread; + struct thread *next; + int ready = 0; + + for (thread = list->head; thread; thread = next) + { + next = thread->next; + + if (FD_ISSET (THREAD_FD (thread), fdset)) + { + assert (FD_ISSET (THREAD_FD (thread), mfdset)); + FD_CLR(THREAD_FD (thread), mfdset); + thread_list_delete (list, thread); + thread_list_add (&m->ready, thread); + thread->type = THREAD_READY; + ready++; + } + } + return ready; +} + +/* Fetch next ready thread. */ +struct thread * +thread_fetch (struct thread_master *m, struct thread *fetch) +{ + int num; + int ready; + struct thread *thread; + fd_set readfd; + fd_set writefd; + fd_set exceptfd; + struct timeval timer_now; + struct timeval timer_val; + struct timeval *timer_wait; + struct timeval timer_nowait; + + timer_nowait.tv_sec = 0; + timer_nowait.tv_usec = 0; + + while (1) + { + /* Normal event is the highest priority. */ + if ((thread = thread_trim_head (&m->event)) != NULL) + return thread_run (m, thread, fetch); + + /* Execute timer. */ + gettimeofday (&timer_now, NULL); + + for (thread = m->timer.head; thread; thread = thread->next) + if (timeval_cmp (timer_now, thread->u.sands) >= 0) + { + thread_list_delete (&m->timer, thread); + return thread_run (m, thread, fetch); + } + + /* If there are any ready threads, process top of them. */ + if ((thread = thread_trim_head (&m->ready)) != NULL) + return thread_run (m, thread, fetch); + + /* Structure copy. */ + readfd = m->readfd; + writefd = m->writefd; + exceptfd = m->exceptfd; + + /* Calculate select wait timer. */ + timer_wait = thread_timer_wait (m, &timer_val); + + num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); + + if (num == 0) + continue; + + if (num < 0) + { + if (errno == EINTR) + continue; + + zlog_warn ("select() error: %s", strerror (errno)); + return NULL; + } + + /* Normal priority read thead. */ + ready = thread_process_fd (m, &m->read, &readfd, &m->readfd); + + /* Write thead. */ + ready = thread_process_fd (m, &m->write, &writefd, &m->writefd); + + if ((thread = thread_trim_head (&m->ready)) != NULL) + return thread_run (m, thread, fetch); + } +} + +static unsigned long +thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start) +{ + unsigned long thread_time; + +#ifdef HAVE_RUSAGE + /* This is 'user + sys' time. */ + thread_time = timeval_elapsed (now->ru_utime, start->ru_utime); + thread_time += timeval_elapsed (now->ru_stime, start->ru_stime); +#else + /* When rusage is not available, simple elapsed time is used. */ + thread_time = timeval_elapsed (*now, *start); +#endif /* HAVE_RUSAGE */ + + return thread_time; +} + +/* We should aim to yield after THREAD_YIELD_TIME_SLOT + milliseconds. */ +int +thread_should_yield (struct thread *thread) +{ + RUSAGE_T ru; + + GETRUSAGE (&ru); + + if (thread_consumed_time (&ru, &thread->ru) > THREAD_YIELD_TIME_SLOT) + return 1; + else + return 0; +} + +/* We check thread consumed time. If the system has getrusage, we'll + use that to get indepth stats on the performance of the thread. If + not - we'll use gettimeofday for some guestimation. */ +void +thread_call (struct thread *thread) +{ + unsigned long thread_time; + RUSAGE_T ru; + + GETRUSAGE (&thread->ru); + + (*thread->func) (thread); + + GETRUSAGE (&ru); + + thread_time = thread_consumed_time (&ru, &thread->ru); + +#ifdef THREAD_CONSUMED_TIME_CHECK + if (thread_time > 200000L) + { + /* + * We have a CPU Hog on our hands. + * Whinge about it now, so we're aware this is yet another task + * to fix. + */ + zlog_err ("CPU HOG task %lx ran for %ldms", + /* FIXME: report the name of the function somehow */ + (unsigned long) thread->func, + thread_time / 1000L); + } +#endif /* THREAD_CONSUMED_TIME_CHECK */ +} + +/* Execute thread */ +struct thread * +thread_execute (struct thread_master *m, + int (*func)(struct thread *), + void *arg, + int val) +{ + struct thread dummy; + + memset (&dummy, 0, sizeof (struct thread)); + + dummy.type = THREAD_EVENT; + dummy.master = NULL; + dummy.func = func; + dummy.arg = arg; + dummy.u.val = val; + thread_call (&dummy); + + return NULL; +} diff --git a/lib/thread.h b/lib/thread.h new file mode 100644 index 0000000..cd62df0 --- /dev/null +++ b/lib/thread.h @@ -0,0 +1,139 @@ +/* Thread management routine header. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_THREAD_H +#define _ZEBRA_THREAD_H + +#ifdef HAVE_RUSAGE +#define RUSAGE_T struct rusage +#define GETRUSAGE(X) getrusage (RUSAGE_SELF, X); +#else +#define RUSAGE_T struct timeval +#define GETRUSAGE(X) gettimeofday (X, NULL); +#endif /* HAVE_RUSAGE */ + +/* Linked list of thread. */ +struct thread_list +{ + struct thread *head; + struct thread *tail; + int count; +}; + +/* Master of the theads. */ +struct thread_master +{ + struct thread_list read; + struct thread_list write; + struct thread_list timer; + struct thread_list event; + struct thread_list ready; + struct thread_list unuse; + fd_set readfd; + fd_set writefd; + fd_set exceptfd; + unsigned long alloc; +}; + +/* Thread itself. */ +struct thread +{ + unsigned char type; /* thread type */ + struct thread *next; /* next pointer of the thread */ + struct thread *prev; /* previous pointer of the thread */ + struct thread_master *master; /* pointer to the struct thread_master. */ + int (*func) (struct thread *); /* event function */ + void *arg; /* event argument */ + union { + int val; /* second argument of the event. */ + int fd; /* file descriptor in case of read/write. */ + struct timeval sands; /* rest of time sands value. */ + } u; + RUSAGE_T ru; /* Indepth usage info. */ +}; + +/* Thread types. */ +#define THREAD_READ 0 +#define THREAD_WRITE 1 +#define THREAD_TIMER 2 +#define THREAD_EVENT 3 +#define THREAD_READY 4 +#define THREAD_UNUSED 5 + +/* Thread yield time. */ +#define THREAD_YIELD_TIME_SLOT 100 * 1000L /* 100ms */ + +/* Macros. */ +#define THREAD_ARG(X) ((X)->arg) +#define THREAD_FD(X) ((X)->u.fd) +#define THREAD_VAL(X) ((X)->u.val) + +#define THREAD_READ_ON(master,thread,func,arg,sock) \ + do { \ + if (! thread) \ + thread = thread_add_read (master, func, arg, sock); \ + } while (0) + +#define THREAD_WRITE_ON(master,thread,func,arg,sock) \ + do { \ + if (! thread) \ + thread = thread_add_write (master, func, arg, sock); \ + } while (0) + +#define THREAD_TIMER_ON(master,thread,func,arg,time) \ + do { \ + if (! thread) \ + thread = thread_add_timer (master, func, arg, time); \ + } while (0) + +#define THREAD_OFF(thread) \ + do { \ + if (thread) \ + { \ + thread_cancel (thread); \ + thread = NULL; \ + } \ + } while (0) + +#define THREAD_READ_OFF(thread) THREAD_OFF(thread) +#define THREAD_WRITE_OFF(thread) THREAD_OFF(thread) +#define THREAD_TIMER_OFF(thread) THREAD_OFF(thread) + +/* Prototypes. */ +struct thread_master *thread_master_create (); +struct thread *thread_add_read (struct thread_master *, + int (*)(struct thread *), void *, int); +struct thread *thread_add_write (struct thread_master *, + int (*)(struct thread *), void *, int); +struct thread *thread_add_timer (struct thread_master *, + int (*)(struct thread *), void *, long); +struct thread *thread_add_event (struct thread_master *, + int (*)(struct thread *), void *, int ); +void thread_cancel (struct thread *); +void thread_cancel_event (struct thread_master *, void *); + +struct thread *thread_fetch (struct thread_master *, struct thread *); +struct thread *thread_execute (struct thread_master *, + int (*)(struct thread *), void *, int); +void thread_call (struct thread *); +char *thread_timer_remain_second (struct thread *); + +#endif /* _ZEBRA_THREAD_H */ diff --git a/lib/vector.c b/lib/vector.c new file mode 100644 index 0000000..31cdc77 --- /dev/null +++ b/lib/vector.c @@ -0,0 +1,189 @@ +/* Generic vector interface routine + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "vector.h" +#include "memory.h" + +/* Initialize vector : allocate memory and return vector. */ +vector +vector_init (unsigned int size) +{ + vector v = XCALLOC (MTYPE_VECTOR, sizeof (struct _vector)); + + /* allocate at least one slot */ + if (size == 0) + size = 1; + + v->alloced = size; + v->max = 0; + v->index = XCALLOC (MTYPE_VECTOR_INDEX, sizeof (void *) * size); + return v; +} + +void +vector_only_wrapper_free (vector v) +{ + XFREE (MTYPE_VECTOR, v); +} + +void +vector_only_index_free (void *index) +{ + XFREE (MTYPE_VECTOR_INDEX, index); +} + +void +vector_free (vector v) +{ + XFREE (MTYPE_VECTOR_INDEX, v->index); + XFREE (MTYPE_VECTOR, v); +} + +vector +vector_copy (vector v) +{ + unsigned int size; + vector new = XCALLOC (MTYPE_VECTOR, sizeof (struct _vector)); + + new->max = v->max; + new->alloced = v->alloced; + + size = sizeof (void *) * (v->alloced); + new->index = XCALLOC (MTYPE_VECTOR_INDEX, size); + memcpy (new->index, v->index, size); + + return new; +} + +/* Check assigned index, and if it runs short double index pointer */ +void +vector_ensure (vector v, unsigned int num) +{ + if (v->alloced > num) + return; + + v->index = XREALLOC (MTYPE_VECTOR_INDEX, + v->index, sizeof (void *) * (v->alloced * 2)); + memset (&v->index[v->alloced], 0, sizeof (void *) * v->alloced); + v->alloced *= 2; + + if (v->alloced <= num) + vector_ensure (v, num); +} + +/* This function only returns next empty slot index. It dose not mean + the slot's index memory is assigned, please call vector_ensure() + after calling this function. */ +int +vector_empty_slot (vector v) +{ + unsigned int i; + + if (v->max == 0) + return 0; + + for (i = 0; i < v->max; i++) + if (v->index[i] == 0) + return i; + + return i; +} + +/* Set value to the smallest empty slot. */ +int +vector_set (vector v, void *val) +{ + unsigned int i; + + i = vector_empty_slot (v); + vector_ensure (v, i); + + v->index[i] = val; + + if (v->max <= i) + v->max = i + 1; + + return i; +} + +/* Set value to specified index slot. */ +int +vector_set_index (vector v, unsigned int i, void *val) +{ + vector_ensure (v, i); + + v->index[i] = val; + + if (v->max <= i) + v->max = i + 1; + + return i; +} + +/* Look up vector. */ +void * +vector_lookup (vector v, unsigned int i) +{ + if (i >= v->max) + return NULL; + return v->index[i]; +} + +/* Lookup vector, ensure it. */ +void * +vector_lookup_ensure (vector v, unsigned int i) +{ + vector_ensure (v, i); + return v->index[i]; +} + +/* Unset value at specified index slot. */ +void +vector_unset (vector v, unsigned int i) +{ + if (i >= v->alloced) + return; + + v->index[i] = NULL; + + if (i + 1 == v->max) + { + v->max--; + while (i && v->index[--i] == NULL && v->max--) + ; /* Is this ugly ? */ + } +} + +/* Count the number of not emplty slot. */ +unsigned int +vector_count (vector v) +{ + unsigned int i; + unsigned count = 0; + + for (i = 0; i < v->max; i++) + if (v->index[i] != NULL) + count++; + + return count; +} diff --git a/lib/vector.h b/lib/vector.h new file mode 100644 index 0000000..7e00c39 --- /dev/null +++ b/lib/vector.h @@ -0,0 +1,58 @@ +/* + * Generic vector interface header. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_VECTOR_H +#define _ZEBRA_VECTOR_H + +/* struct for vector */ +struct _vector +{ + unsigned int max; /* max number of used slot */ + unsigned int alloced; /* number of allocated slot */ + void **index; /* index to data */ +}; +typedef struct _vector *vector; + +#define VECTOR_MIN_SIZE 1 + +/* (Sometimes) usefull macros. This macro convert index expression to + array expression. */ +#define vector_slot(V,I) ((V)->index[(I)]) +#define vector_max(V) ((V)->max) + +/* Prototypes. */ +vector vector_init (unsigned int size); +void vector_ensure (vector v, unsigned int num); +int vector_empty_slot (vector v); +int vector_set (vector v, void *val); +int vector_set_index (vector v, unsigned int i, void *val); +void vector_unset (vector v, unsigned int i); +unsigned int vector_count (vector v); +void vector_only_wrapper_free (vector v); +void vector_only_index_free (void *index); +void vector_free (vector v); +vector vector_copy (vector v); + +void *vector_lookup (vector, unsigned int); +void *vector_lookup_ensure (vector, unsigned int); + +#endif /* _ZEBRA_VECTOR_H */ diff --git a/lib/version.c b/lib/version.c new file mode 100644 index 0000000..e749b8e --- /dev/null +++ b/lib/version.c @@ -0,0 +1,2 @@ + +char *host_name = ""; diff --git a/lib/version.h b/lib/version.h new file mode 100644 index 0000000..49e1d94 --- /dev/null +++ b/lib/version.h @@ -0,0 +1,39 @@ +/* Zebra version + * Copyright (C) 1997, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_VERSION_H +#define _ZEBRA_VERSION_H + +#define ZEBRA_VERSION "0.95a" + +#define ZEBRA_BUG_ADDRESS "bug-zebra@gnu.org" + +extern char *host_name; + +void print_version(char *); +pid_t pid_output (char *); +pid_t pid_output_lock (char *); + +#ifndef HAVE_DAEMON +int daemon(int, int); +#endif + +#endif /* _ZEBRA_VERSION_H */ diff --git a/lib/vty.c b/lib/vty.c new file mode 100644 index 0000000..d85f21b --- /dev/null +++ b/lib/vty.c @@ -0,0 +1,2817 @@ +/* + * Virtual terminal [aka TeletYpe] interface routine. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "buffer.h" +#include "version.h" +#include "command.h" +#include "sockunion.h" +#include "thread.h" +#include "memory.h" +#include "str.h" +#include "log.h" +#include "prefix.h" +#include "filter.h" + +/* Vty events */ +enum event + { + VTY_SERV, + VTY_READ, + VTY_WRITE, + VTY_TIMEOUT_RESET, +#ifdef VTYSH + VTYSH_SERV, + VTYSH_READ +#endif /* VTYSH */ + }; + +static void vty_event (enum event, int, struct vty *); + +/* Extern host structure from command.c */ +extern struct host host; + +/* Vector which store each vty structure. */ +static vector vtyvec; + +/* Vty timeout value. */ +static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT; + +/* Vty access-class command */ +static char *vty_accesslist_name = NULL; + +/* Vty access-calss for IPv6. */ +static char *vty_ipv6_accesslist_name = NULL; + +/* VTY server thread. */ +vector Vvty_serv_thread; + +/* Current directory. */ +char *vty_cwd = NULL; + +/* Configure lock. */ +static int vty_config; + +/* Login password check. */ +static int no_password_check = 0; + +/* Integrated configuration file path */ +char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; + + +/* VTY standard output function. */ +int +vty_out (struct vty *vty, const char *format, ...) +{ + va_list args; + int len = 0; + int size = 1024; + char buf[1024]; + char *p = NULL; + + va_start (args, format); + + if (vty_shell (vty)) + vprintf (format, args); + else + { + /* Try to write to initial buffer. */ + len = vsnprintf (buf, sizeof buf, format, args); + + /* Initial buffer is not enough. */ + if (len < 0 || len >= size) + { + while (1) + { + if (len > -1) + size = len + 1; + else + size = size * 2; + + p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size); + if (! p) + return -1; + + len = vsnprintf (p, size, format, args); + + if (len > -1 && len < size) + break; + } + } + + /* When initial buffer is enough to store all output. */ + if (! p) + p = buf; + + /* Pointer p must point out buffer. */ + if (vty_shell_serv (vty)) + write (vty->fd, (u_char *) p, len); + else + buffer_write (vty->obuf, (u_char *) p, len); + + /* If p is not different with buf, it is allocated buffer. */ + if (p != buf) + XFREE (MTYPE_VTY_OUT_BUF, p); + } + + va_end (args); + + return len; +} + +#define TIME_BUF 27 + +/* current time string. */ +int +time_str (char *buf) +{ + time_t clock; + struct tm *tm; + int ret; + + time (&clock); + tm = localtime (&clock); + + ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm); + + return ret; +} + +int +vty_log_out (struct vty *vty, const char *proto_str, const char *format, + va_list va) +{ + int len; + int ret; + char buf[1024]; + char time_buf[TIME_BUF]; + + ret = time_str (time_buf); + + if (ret != 0) + { + snprintf (buf, sizeof buf, "%s ", time_buf); + write (vty->fd, buf, strlen (time_buf) + 1); + } + + snprintf (buf, sizeof buf, "%s: ", proto_str); + write (vty->fd, buf, strlen (proto_str) + 2); + + len = vsnprintf (buf, sizeof buf, format, va); + if (len < 0) + return -1; + write (vty->fd, (u_char *)buf, len); + + snprintf (buf, sizeof buf, "\r\n"); + write (vty->fd, buf, 2); + + return len; +} + +/* Output current time to the vty. */ +void +vty_time_print (struct vty *vty, int cr) +{ + int ret; + char buf [TIME_BUF]; + + ret = time_str (buf); + + if (ret == 0) + { + zlog (NULL, LOG_INFO, "strftime error"); + return; + } + + if (cr) + vty_out (vty, "%s\n", buf); + else + vty_out (vty, "%s ", buf); + + return; +} + +/* Say hello to vty interface. */ +void +vty_hello (struct vty *vty) +{ + if (host.motd) + vty_out (vty, host.motd); +} + +/* Put out prompt and wait input from user. */ +static void +vty_prompt (struct vty *vty) +{ + struct utsname names; + const char*hostname; + + if (vty->type == VTY_TERM) + { + hostname = host.name; + if (!hostname) + { + uname (&names); + hostname = names.nodename; + } + vty_out (vty, cmd_prompt (vty->node), hostname); + } +} + +/* Send WILL TELOPT_ECHO to remote server. */ +void +vty_will_echo (struct vty *vty) +{ + char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' }; + vty_out (vty, "%s", cmd); +} + +/* Make suppress Go-Ahead telnet option. */ +static void +vty_will_suppress_go_ahead (struct vty *vty) +{ + char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' }; + vty_out (vty, "%s", cmd); +} + +/* Make don't use linemode over telnet. */ +static void +vty_dont_linemode (struct vty *vty) +{ + char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' }; + vty_out (vty, "%s", cmd); +} + +/* Use window size. */ +static void +vty_do_window_size (struct vty *vty) +{ + char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' }; + vty_out (vty, "%s", cmd); +} + +#if 0 /* Currently not used. */ +/* Make don't use lflow vty interface. */ +static void +vty_dont_lflow_ahead (struct vty *vty) +{ + char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' }; + vty_out (vty, "%s", cmd); +} +#endif /* 0 */ + +/* Allocate new vty struct. */ +struct vty * +vty_new () +{ + struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty)); + + new->obuf = (struct buffer *) buffer_new (100); + new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ); + new->max = VTY_BUFSIZ; + new->sb_buffer = NULL; + + return new; +} + +/* Authentication of vty */ +static void +vty_auth (struct vty *vty, char *buf) +{ + char *passwd = NULL; + enum node_type next_node = 0; + int fail; + char *crypt (const char *, const char *); + + switch (vty->node) + { + case AUTH_NODE: + if (host.password_encrypt) + passwd = host.password_encrypt; + else + passwd = host.password; + if (host.advanced) + next_node = host.enable ? VIEW_NODE : ENABLE_NODE; + else + next_node = VIEW_NODE; + break; + case AUTH_ENABLE_NODE: + if (host.enable_encrypt) + passwd = host.enable_encrypt; + else + passwd = host.enable; + next_node = ENABLE_NODE; + break; + } + + if (passwd) + { + if (strcmp (crypt(buf, passwd), passwd) == 0 + || strcmp (buf, passwd) == 0) + fail = 0; + else + fail = 1; + } + else + fail = 1; + + if (! fail) + { + vty->fail = 0; + vty->node = next_node; /* Success ! */ + } + else + { + vty->fail++; + if (vty->fail >= 3) + { + if (vty->node == AUTH_NODE) + { + vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE); + vty->status = VTY_CLOSE; + } + else + { + /* AUTH_ENABLE_NODE */ + vty->fail = 0; + vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE); + vty->node = VIEW_NODE; + } + } + } +} + +/* Command execution over the vty interface. */ +int +vty_command (struct vty *vty, char *buf) +{ + int ret; + vector vline; + + /* Split readline string up into the vector */ + vline = cmd_make_strvec (buf); + + if (vline == NULL) + return CMD_SUCCESS; + + ret = cmd_execute_command (vline, vty, NULL); + + if (ret != CMD_SUCCESS) + switch (ret) + { + case CMD_WARNING: + if (vty->type == VTY_FILE) + vty_out (vty, "Warning...%s", VTY_NEWLINE); + break; + case CMD_ERR_AMBIGUOUS: + vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + break; + case CMD_ERR_NO_MATCH: + vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE); + break; + case CMD_ERR_INCOMPLETE: + vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE); + break; + } + cmd_free_strvec (vline); + + return ret; +} + +char telnet_backward_char = 0x08; +char telnet_space_char = ' '; + +/* Basic function to write buffer to vty. */ +static void +vty_write (struct vty *vty, char *buf, size_t nbytes) +{ + if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) + return; + + /* Should we do buffering here ? And make vty_flush (vty) ? */ + buffer_write (vty->obuf, (u_char *)buf, nbytes); +} + +/* Ensure length of input buffer. Is buffer is short, double it. */ +static void +vty_ensure (struct vty *vty, int length) +{ + if (vty->max <= length) + { + vty->max *= 2; + vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max); + } +} + +/* Basic function to insert character into vty. */ +static void +vty_self_insert (struct vty *vty, char c) +{ + int i; + int length; + + vty_ensure (vty, vty->length + 1); + length = vty->length - vty->cp; + memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length); + vty->buf[vty->cp] = c; + + vty_write (vty, &vty->buf[vty->cp], length + 1); + for (i = 0; i < length; i++) + vty_write (vty, &telnet_backward_char, 1); + + vty->cp++; + vty->length++; +} + +/* Self insert character 'c' in overwrite mode. */ +static void +vty_self_insert_overwrite (struct vty *vty, char c) +{ + vty_ensure (vty, vty->length + 1); + vty->buf[vty->cp++] = c; + + if (vty->cp > vty->length) + vty->length++; + + if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) + return; + + vty_write (vty, &c, 1); +} + +/* Insert a word into vty interface with overwrite mode. */ +static void +vty_insert_word_overwrite (struct vty *vty, char *str) +{ + int len = strlen (str); + vty_write (vty, str, len); + strcpy (&vty->buf[vty->cp], str); + vty->cp += len; + vty->length = vty->cp; +} + +/* Forward character. */ +static void +vty_forward_char (struct vty *vty) +{ + if (vty->cp < vty->length) + { + vty_write (vty, &vty->buf[vty->cp], 1); + vty->cp++; + } +} + +/* Backward character. */ +static void +vty_backward_char (struct vty *vty) +{ + if (vty->cp > 0) + { + vty->cp--; + vty_write (vty, &telnet_backward_char, 1); + } +} + +/* Move to the beginning of the line. */ +static void +vty_beginning_of_line (struct vty *vty) +{ + while (vty->cp) + vty_backward_char (vty); +} + +/* Move to the end of the line. */ +static void +vty_end_of_line (struct vty *vty) +{ + while (vty->cp < vty->length) + vty_forward_char (vty); +} + +static void vty_kill_line_from_beginning (struct vty *); +static void vty_redraw_line (struct vty *); + +/* Print command line history. This function is called from + vty_next_line and vty_previous_line. */ +static void +vty_history_print (struct vty *vty) +{ + int length; + + vty_kill_line_from_beginning (vty); + + /* Get previous line from history buffer */ + length = strlen (vty->hist[vty->hp]); + memcpy (vty->buf, vty->hist[vty->hp], length); + vty->cp = vty->length = length; + + /* Redraw current line */ + vty_redraw_line (vty); +} + +/* Show next command line history. */ +void +vty_next_line (struct vty *vty) +{ + int try_index; + + if (vty->hp == vty->hindex) + return; + + /* Try is there history exist or not. */ + try_index = vty->hp; + if (try_index == (VTY_MAXHIST - 1)) + try_index = 0; + else + try_index++; + + /* If there is not history return. */ + if (vty->hist[try_index] == NULL) + return; + else + vty->hp = try_index; + + vty_history_print (vty); +} + +/* Show previous command line history. */ +void +vty_previous_line (struct vty *vty) +{ + int try_index; + + try_index = vty->hp; + if (try_index == 0) + try_index = VTY_MAXHIST - 1; + else + try_index--; + + if (vty->hist[try_index] == NULL) + return; + else + vty->hp = try_index; + + vty_history_print (vty); +} + +/* This function redraw all of the command line character. */ +static void +vty_redraw_line (struct vty *vty) +{ + vty_write (vty, vty->buf, vty->length); + vty->cp = vty->length; +} + +/* Forward word. */ +static void +vty_forward_word (struct vty *vty) +{ + while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') + vty_forward_char (vty); + + while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') + vty_forward_char (vty); +} + +/* Backward word without skipping training space. */ +static void +vty_backward_pure_word (struct vty *vty) +{ + while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') + vty_backward_char (vty); +} + +/* Backward word. */ +static void +vty_backward_word (struct vty *vty) +{ + while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') + vty_backward_char (vty); + + while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') + vty_backward_char (vty); +} + +/* When '^D' is typed at the beginning of the line we move to the down + level. */ +static void +vty_down_level (struct vty *vty) +{ + vty_out (vty, "%s", VTY_NEWLINE); + config_exit (NULL, vty, 0, NULL); + vty_prompt (vty); + vty->cp = 0; +} + +/* When '^Z' is received from vty, move down to the enable mode. */ +void +vty_end_config (struct vty *vty) +{ + vty_out (vty, "%s", VTY_NEWLINE); + + switch (vty->node) + { + case VIEW_NODE: + case ENABLE_NODE: + /* Nothing to do. */ + break; + case CONFIG_NODE: + case INTERFACE_NODE: + case ZEBRA_NODE: + case RIP_NODE: + case RIPNG_NODE: + case BGP_NODE: + case BGP_VPNV4_NODE: + case BGP_IPV4_NODE: + case BGP_IPV4M_NODE: + case BGP_IPV6_NODE: + case RMAP_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case KEYCHAIN_NODE: + case KEYCHAIN_KEY_NODE: + case MASC_NODE: + case VTY_NODE: + vty_config_unlock (vty); + vty->node = ENABLE_NODE; + break; + default: + /* Unknown node, we have to ignore it. */ + break; + } + + vty_prompt (vty); + vty->cp = 0; +} + +/* Delete a charcter at the current point. */ +static void +vty_delete_char (struct vty *vty) +{ + int i; + int size; + + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + return; + + if (vty->length == 0) + { + vty_down_level (vty); + return; + } + + if (vty->cp == vty->length) + return; /* completion need here? */ + + size = vty->length - vty->cp; + + vty->length--; + memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1); + vty->buf[vty->length] = '\0'; + + vty_write (vty, &vty->buf[vty->cp], size - 1); + vty_write (vty, &telnet_space_char, 1); + + for (i = 0; i < size; i++) + vty_write (vty, &telnet_backward_char, 1); +} + +/* Delete a character before the point. */ +static void +vty_delete_backward_char (struct vty *vty) +{ + if (vty->cp == 0) + return; + + vty_backward_char (vty); + vty_delete_char (vty); +} + +/* Kill rest of line from current point. */ +static void +vty_kill_line (struct vty *vty) +{ + int i; + int size; + + size = vty->length - vty->cp; + + if (size == 0) + return; + + for (i = 0; i < size; i++) + vty_write (vty, &telnet_space_char, 1); + for (i = 0; i < size; i++) + vty_write (vty, &telnet_backward_char, 1); + + memset (&vty->buf[vty->cp], 0, size); + vty->length = vty->cp; +} + +/* Kill line from the beginning. */ +static void +vty_kill_line_from_beginning (struct vty *vty) +{ + vty_beginning_of_line (vty); + vty_kill_line (vty); +} + +/* Delete a word before the point. */ +static void +vty_forward_kill_word (struct vty *vty) +{ + while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') + vty_delete_char (vty); + while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') + vty_delete_char (vty); +} + +/* Delete a word before the point. */ +static void +vty_backward_kill_word (struct vty *vty) +{ + while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') + vty_delete_backward_char (vty); + while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') + vty_delete_backward_char (vty); +} + +/* Transpose chars before or at the point. */ +static void +vty_transpose_chars (struct vty *vty) +{ + char c1, c2; + + /* If length is short or point is near by the beginning of line then + return. */ + if (vty->length < 2 || vty->cp < 1) + return; + + /* In case of point is located at the end of the line. */ + if (vty->cp == vty->length) + { + c1 = vty->buf[vty->cp - 1]; + c2 = vty->buf[vty->cp - 2]; + + vty_backward_char (vty); + vty_backward_char (vty); + vty_self_insert_overwrite (vty, c1); + vty_self_insert_overwrite (vty, c2); + } + else + { + c1 = vty->buf[vty->cp]; + c2 = vty->buf[vty->cp - 1]; + + vty_backward_char (vty); + vty_self_insert_overwrite (vty, c1); + vty_self_insert_overwrite (vty, c2); + } +} + +/* Do completion at vty interface. */ +static void +vty_complete_command (struct vty *vty) +{ + int i; + int ret; + char **matched = NULL; + vector vline; + + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + return; + + vline = cmd_make_strvec (vty->buf); + if (vline == NULL) + return; + + /* In case of 'help \t'. */ + if (isspace ((int) vty->buf[vty->length - 1])) + vector_set (vline, '\0'); + + matched = cmd_complete_command (vline, vty, &ret); + + cmd_free_strvec (vline); + + vty_out (vty, "%s", VTY_NEWLINE); + switch (ret) + { + case CMD_ERR_AMBIGUOUS: + vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + vty_prompt (vty); + vty_redraw_line (vty); + break; + case CMD_ERR_NO_MATCH: + /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */ + vty_prompt (vty); + vty_redraw_line (vty); + break; + case CMD_COMPLETE_FULL_MATCH: + vty_prompt (vty); + vty_redraw_line (vty); + vty_backward_pure_word (vty); + vty_insert_word_overwrite (vty, matched[0]); + vty_self_insert (vty, ' '); + XFREE (MTYPE_TMP, matched[0]); + break; + case CMD_COMPLETE_MATCH: + vty_prompt (vty); + vty_redraw_line (vty); + vty_backward_pure_word (vty); + vty_insert_word_overwrite (vty, matched[0]); + XFREE (MTYPE_TMP, matched[0]); + vector_only_index_free (matched); + return; + break; + case CMD_COMPLETE_LIST_MATCH: + for (i = 0; matched[i] != NULL; i++) + { + if (i != 0 && ((i % 6) == 0)) + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "%-10s ", matched[i]); + XFREE (MTYPE_TMP, matched[i]); + } + vty_out (vty, "%s", VTY_NEWLINE); + + vty_prompt (vty); + vty_redraw_line (vty); + break; + case CMD_ERR_NOTHING_TODO: + vty_prompt (vty); + vty_redraw_line (vty); + break; + default: + break; + } + if (matched) + vector_only_index_free (matched); +} + +void +vty_describe_fold (struct vty *vty, int cmd_width, + int desc_width, struct desc *desc) +{ + char *buf, *cmd, *p; + int pos; + + cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd; + + if (desc_width <= 0) + { + vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE); + return; + } + + buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1); + + for (p = desc->str; strlen (p) > desc_width; p += pos + 1) + { + for (pos = desc_width; pos > 0; pos--) + if (*(p + pos) == ' ') + break; + + if (pos == 0) + break; + + strncpy (buf, p, pos); + buf[pos] = '\0'; + vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE); + + cmd = ""; + } + + vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE); + + XFREE (MTYPE_TMP, buf); +} + +/* Describe matched command function. */ +static void +vty_describe_command (struct vty *vty) +{ + int ret; + vector vline; + vector describe; + int i, width, desc_width; + struct desc *desc, *desc_cr = NULL; + + vline = cmd_make_strvec (vty->buf); + + /* In case of '> ?'. */ + if (vline == NULL) + { + vline = vector_init (1); + vector_set (vline, '\0'); + } + else + if (isspace ((int) vty->buf[vty->length - 1])) + vector_set (vline, '\0'); + + describe = cmd_describe_command (vline, vty, &ret); + + vty_out (vty, "%s", VTY_NEWLINE); + + /* Ambiguous error. */ + switch (ret) + { + case CMD_ERR_AMBIGUOUS: + cmd_free_strvec (vline); + vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + vty_prompt (vty); + vty_redraw_line (vty); + return; + break; + case CMD_ERR_NO_MATCH: + cmd_free_strvec (vline); + vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); + vty_prompt (vty); + vty_redraw_line (vty); + return; + break; + } + + /* Get width of command string. */ + width = 0; + for (i = 0; i < vector_max (describe); i++) + if ((desc = vector_slot (describe, i)) != NULL) + { + int len; + + if (desc->cmd[0] == '\0') + continue; + + len = strlen (desc->cmd); + if (desc->cmd[0] == '.') + len--; + + if (width < len) + width = len; + } + + /* Get width of description string. */ + desc_width = vty->width - (width + 6); + + /* Print out description. */ + for (i = 0; i < vector_max (describe); i++) + if ((desc = vector_slot (describe, i)) != NULL) + { + if (desc->cmd[0] == '\0') + continue; + + if (strcmp (desc->cmd, "") == 0) + { + desc_cr = desc; + continue; + } + + if (!desc->str) + vty_out (vty, " %-s%s", + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + VTY_NEWLINE); + else if (desc_width >= strlen (desc->str)) + vty_out (vty, " %-*s %s%s", width, + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + desc->str, VTY_NEWLINE); + else + vty_describe_fold (vty, width, desc_width, desc); + +#if 0 + vty_out (vty, " %-*s %s%s", width + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + desc->str ? desc->str : "", VTY_NEWLINE); +#endif /* 0 */ + } + + if ((desc = desc_cr)) + { + if (!desc->str) + vty_out (vty, " %-s%s", + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + VTY_NEWLINE); + else if (desc_width >= strlen (desc->str)) + vty_out (vty, " %-*s %s%s", width, + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + desc->str, VTY_NEWLINE); + else + vty_describe_fold (vty, width, desc_width, desc); + } + + cmd_free_strvec (vline); + vector_free (describe); + + vty_prompt (vty); + vty_redraw_line (vty); +} + +void +vty_clear_buf (struct vty *vty) +{ + memset (vty->buf, 0, vty->max); +} + +/* ^C stop current input and do not add command line to the history. */ +static void +vty_stop_input (struct vty *vty) +{ + vty->cp = vty->length = 0; + vty_clear_buf (vty); + vty_out (vty, "%s", VTY_NEWLINE); + + switch (vty->node) + { + case VIEW_NODE: + case ENABLE_NODE: + /* Nothing to do. */ + break; + case CONFIG_NODE: + case INTERFACE_NODE: + case ZEBRA_NODE: + case RIP_NODE: + case RIPNG_NODE: + case BGP_NODE: + case RMAP_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case KEYCHAIN_NODE: + case KEYCHAIN_KEY_NODE: + case MASC_NODE: + case VTY_NODE: + vty_config_unlock (vty); + vty->node = ENABLE_NODE; + break; + default: + /* Unknown node, we have to ignore it. */ + break; + } + vty_prompt (vty); + + /* Set history pointer to the latest one. */ + vty->hp = vty->hindex; +} + +/* Add current command line to the history buffer. */ +static void +vty_hist_add (struct vty *vty) +{ + int index; + + if (vty->length == 0) + return; + + index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1; + + /* Ignore the same string as previous one. */ + if (vty->hist[index]) + if (strcmp (vty->buf, vty->hist[index]) == 0) + { + vty->hp = vty->hindex; + return; + } + + /* Insert history entry. */ + if (vty->hist[vty->hindex]) + XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]); + vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf); + + /* History index rotation. */ + vty->hindex++; + if (vty->hindex == VTY_MAXHIST) + vty->hindex = 0; + + vty->hp = vty->hindex; +} + +/* #define TELNET_OPTION_DEBUG */ + +/* Get telnet window size. */ +static int +vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes) +{ +#ifdef TELNET_OPTION_DEBUG + int i; + + for (i = 0; i < nbytes; i++) + { + switch (buf[i]) + { + case IAC: + vty_out (vty, "IAC "); + break; + case WILL: + vty_out (vty, "WILL "); + break; + case WONT: + vty_out (vty, "WONT "); + break; + case DO: + vty_out (vty, "DO "); + break; + case DONT: + vty_out (vty, "DONT "); + break; + case SB: + vty_out (vty, "SB "); + break; + case SE: + vty_out (vty, "SE "); + break; + case TELOPT_ECHO: + vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE); + break; + case TELOPT_SGA: + vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE); + break; + case TELOPT_NAWS: + vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE); + break; + default: + vty_out (vty, "%x ", buf[i]); + break; + } + } + vty_out (vty, "%s", VTY_NEWLINE); + +#endif /* TELNET_OPTION_DEBUG */ + + switch (buf[0]) + { + case SB: + buffer_reset(vty->sb_buffer); + vty->iac_sb_in_progress = 1; + return 0; + break; + case SE: + { + char *buffer; + int length; + + if (!vty->iac_sb_in_progress) + return 0; + + buffer = (char *)vty->sb_buffer->head->data; + length = vty->sb_buffer->length; + + if (buffer == NULL) + return 0; + + if (buffer[0] == '\0') + { + vty->iac_sb_in_progress = 0; + return 0; + } + switch (buffer[0]) + { + case TELOPT_NAWS: + if (length < 5) + break; + vty->width = buffer[2]; + vty->height = vty->lines >= 0 ? vty->lines : buffer[4]; + break; + } + vty->iac_sb_in_progress = 0; + return 0; + break; + } + default: + break; + } + return 1; +} + +/* Execute current command line. */ +static int +vty_execute (struct vty *vty) +{ + int ret; + + ret = CMD_SUCCESS; + + switch (vty->node) + { + case AUTH_NODE: + case AUTH_ENABLE_NODE: + vty_auth (vty, vty->buf); + break; + default: + ret = vty_command (vty, vty->buf); + if (vty->type == VTY_TERM) + vty_hist_add (vty); + break; + } + + /* Clear command line buffer. */ + vty->cp = vty->length = 0; + vty_clear_buf (vty); + + if (vty->status != VTY_CLOSE + && vty->status != VTY_START + && vty->status != VTY_CONTINUE) + vty_prompt (vty); + + return ret; +} + +#define CONTROL(X) ((X) - '@') +#define VTY_NORMAL 0 +#define VTY_PRE_ESCAPE 1 +#define VTY_ESCAPE 2 + +/* Escape character command map. */ +static void +vty_escape_map (unsigned char c, struct vty *vty) +{ + switch (c) + { + case ('A'): + vty_previous_line (vty); + break; + case ('B'): + vty_next_line (vty); + break; + case ('C'): + vty_forward_char (vty); + break; + case ('D'): + vty_backward_char (vty); + break; + default: + break; + } + + /* Go back to normal mode. */ + vty->escape = VTY_NORMAL; +} + +/* Quit print out to the buffer. */ +static void +vty_buffer_reset (struct vty *vty) +{ + buffer_reset (vty->obuf); + vty_prompt (vty); + vty_redraw_line (vty); +} + +/* Read data via vty socket. */ +static int +vty_read (struct thread *thread) +{ + int i; + int ret; + int nbytes; + unsigned char buf[VTY_READ_BUFSIZ]; + + int vty_sock = THREAD_FD (thread); + struct vty *vty = THREAD_ARG (thread); + vty->t_read = NULL; + + /* Read raw data from socket */ + nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ); + if (nbytes <= 0) + vty->status = VTY_CLOSE; + + for (i = 0; i < nbytes; i++) + { + if (buf[i] == IAC) + { + if (!vty->iac) + { + vty->iac = 1; + continue; + } + else + { + vty->iac = 0; + } + } + + if (vty->iac_sb_in_progress && !vty->iac) + { + buffer_putc(vty->sb_buffer, buf[i]); + continue; + } + + if (vty->iac) + { + /* In case of telnet command */ + ret = vty_telnet_option (vty, buf + i, nbytes - i); + vty->iac = 0; + i += ret; + continue; + } + + if (vty->status == VTY_MORE) + { + switch (buf[i]) + { + case CONTROL('C'): + case 'q': + case 'Q': + if (vty->output_func) + (*vty->output_func) (vty, 1); + vty_buffer_reset (vty); + break; +#if 1 /* More line for "show ip bgp" is fixed */ + case '\n': + case '\r': + vty->status = VTY_MORELINE; + if (vty->output_func) + (*vty->output_func) (vty, 0); + break; +#endif + default: + if (vty->output_func) + (*vty->output_func) (vty, 0); + break; + } + continue; + } + + /* Escape character. */ + if (vty->escape == VTY_ESCAPE) + { + vty_escape_map (buf[i], vty); + continue; + } + + /* Pre-escape status. */ + if (vty->escape == VTY_PRE_ESCAPE) + { + switch (buf[i]) + { + case '[': + vty->escape = VTY_ESCAPE; + break; + case 'b': + vty_backward_word (vty); + vty->escape = VTY_NORMAL; + break; + case 'f': + vty_forward_word (vty); + vty->escape = VTY_NORMAL; + break; + case 'd': + vty_forward_kill_word (vty); + vty->escape = VTY_NORMAL; + break; + case CONTROL('H'): + case 0x7f: + vty_backward_kill_word (vty); + vty->escape = VTY_NORMAL; + break; + default: + vty->escape = VTY_NORMAL; + break; + } + continue; + } + + switch (buf[i]) + { + case CONTROL('A'): + vty_beginning_of_line (vty); + break; + case CONTROL('B'): + vty_backward_char (vty); + break; + case CONTROL('C'): + vty_stop_input (vty); + break; + case CONTROL('D'): + vty_delete_char (vty); + break; + case CONTROL('E'): + vty_end_of_line (vty); + break; + case CONTROL('F'): + vty_forward_char (vty); + break; + case CONTROL('H'): + case 0x7f: + vty_delete_backward_char (vty); + break; + case CONTROL('K'): + vty_kill_line (vty); + break; + case CONTROL('N'): + vty_next_line (vty); + break; + case CONTROL('P'): + vty_previous_line (vty); + break; + case CONTROL('T'): + vty_transpose_chars (vty); + break; + case CONTROL('U'): + vty_kill_line_from_beginning (vty); + break; + case CONTROL('W'): + vty_backward_kill_word (vty); + break; + case CONTROL('Z'): + vty_end_config (vty); + break; + case '\n': + case '\r': + vty_out (vty, "%s", VTY_NEWLINE); + vty_execute (vty); + break; + case '\t': + vty_complete_command (vty); + break; + case '?': + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + vty_self_insert (vty, buf[i]); + else + vty_describe_command (vty); + break; + case '\033': + if (i + 1 < nbytes && buf[i + 1] == '[') + { + vty->escape = VTY_ESCAPE; + i++; + } + else + vty->escape = VTY_PRE_ESCAPE; + break; + default: + if (buf[i] > 31 && buf[i] < 127) + vty_self_insert (vty, buf[i]); + break; + } + } + + /* Check status. */ + if (vty->status == VTY_CLOSE) + vty_close (vty); + else + { + vty_event (VTY_WRITE, vty_sock, vty); + vty_event (VTY_READ, vty_sock, vty); + } + return 0; +} + +/* Flush buffer to the vty. */ +static int +vty_flush (struct thread *thread) +{ + int erase; + int dont_more; + int vty_sock = THREAD_FD (thread); + struct vty *vty = THREAD_ARG (thread); + vty->t_write = NULL; + + /* Tempolary disable read thread. */ + if (vty->lines == 0) + if (vty->t_read) + { + thread_cancel (vty->t_read); + vty->t_read = NULL; + } + + /* Function execution continue. */ + if (vty->status == VTY_START || vty->status == VTY_CONTINUE) + { + if (vty->status == VTY_CONTINUE && vty->output_func) + erase = 1; + else + erase = 0; + + if (vty->output_func == NULL) + dont_more = 1; + else + dont_more = 0; + + if (vty->lines == 0) + { + erase = 0; + dont_more = 1; + } + + buffer_flush_vty_all (vty->obuf, vty->fd, erase, dont_more); + + if (vty->status == VTY_CLOSE) + { + vty_close (vty); + return 0; + } + + if (vty->output_func == NULL) + { + vty->status = VTY_NORMAL; + vty_prompt (vty); + vty_event (VTY_WRITE, vty_sock, vty); + } + else + vty->status = VTY_MORE; + + if (vty->lines == 0) + { + if (vty->output_func == NULL) + vty_event (VTY_READ, vty_sock, vty); + else + { + if (vty->output_func) + (*vty->output_func) (vty, 0); + vty_event (VTY_WRITE, vty_sock, vty); + } + } + } + else + { + if (vty->status == VTY_MORE || vty->status == VTY_MORELINE) + erase = 1; + else + erase = 0; + + if (vty->lines == 0) + buffer_flush_window (vty->obuf, vty->fd, vty->width, 25, 0, 1); + else if (vty->status == VTY_MORELINE) + buffer_flush_window (vty->obuf, vty->fd, vty->width, 1, erase, 0); + else + buffer_flush_window (vty->obuf, vty->fd, vty->width, + vty->lines >= 0 ? vty->lines : vty->height, + erase, 0); + + if (buffer_empty (vty->obuf)) + { + if (vty->status == VTY_CLOSE) + vty_close (vty); + else + { + vty->status = VTY_NORMAL; + + if (vty->lines == 0) + vty_event (VTY_READ, vty_sock, vty); + } + } + else + { + vty->status = VTY_MORE; + + if (vty->lines == 0) + vty_event (VTY_WRITE, vty_sock, vty); + } + } + + return 0; +} + +/* Create new vty structure. */ +struct vty * +vty_create (int vty_sock, union sockunion *su) +{ + struct vty *vty; + + /* Allocate new vty structure and set up default values. */ + vty = vty_new (); + vty->fd = vty_sock; + vty->type = VTY_TERM; + vty->address = sockunion_su2str (su); + if (no_password_check) + { + if (host.advanced) + vty->node = ENABLE_NODE; + else + vty->node = VIEW_NODE; + } + else + vty->node = AUTH_NODE; + vty->fail = 0; + vty->cp = 0; + vty_clear_buf (vty); + vty->length = 0; + memset (vty->hist, 0, sizeof (vty->hist)); + vty->hp = 0; + vty->hindex = 0; + vector_set_index (vtyvec, vty_sock, vty); + vty->status = VTY_NORMAL; + vty->v_timeout = vty_timeout_val; + if (host.lines >= 0) + vty->lines = host.lines; + else + vty->lines = -1; + vty->iac = 0; + vty->iac_sb_in_progress = 0; + vty->sb_buffer = buffer_new (1024); + + if (! no_password_check) + { + /* Vty is not available if password isn't set. */ + if (host.password == NULL && host.password_encrypt == NULL) + { + vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE); + vty->status = VTY_CLOSE; + vty_close (vty); + return NULL; + } + } + + /* Say hello to the world. */ + vty_hello (vty); + if (! no_password_check) + vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + /* Setting up terminal. */ + vty_will_echo (vty); + vty_will_suppress_go_ahead (vty); + + vty_dont_linemode (vty); + vty_do_window_size (vty); + /* vty_dont_lflow_ahead (vty); */ + + vty_prompt (vty); + + /* Add read/write thread. */ + vty_event (VTY_WRITE, vty_sock, vty); + vty_event (VTY_READ, vty_sock, vty); + + return vty; +} + +/* Accept connection from the network. */ +static int +vty_accept (struct thread *thread) +{ + int vty_sock; + struct vty *vty; + union sockunion su; + int ret; + unsigned int on; + int accept_sock; + struct prefix *p = NULL; + struct access_list *acl = NULL; + + accept_sock = THREAD_FD (thread); + + /* We continue hearing vty socket. */ + vty_event (VTY_SERV, accept_sock, NULL); + + memset (&su, 0, sizeof (union sockunion)); + + /* We can handle IPv4 or IPv6 socket. */ + vty_sock = sockunion_accept (accept_sock, &su); + if (vty_sock < 0) + { + zlog_warn ("can't accept vty socket : %s", strerror (errno)); + return -1; + } + + p = sockunion2hostprefix (&su); + + /* VTY's accesslist apply. */ + if (p->family == AF_INET && vty_accesslist_name) + { + if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) && + (access_list_apply (acl, p) == FILTER_DENY)) + { + char *buf; + zlog (NULL, LOG_INFO, "Vty connection refused from %s", + (buf = sockunion_su2str (&su))); + free (buf); + close (vty_sock); + + /* continue accepting connections */ + vty_event (VTY_SERV, accept_sock, NULL); + + prefix_free (p); + + return 0; + } + } + +#ifdef HAVE_IPV6 + /* VTY's ipv6 accesslist apply. */ + if (p->family == AF_INET6 && vty_ipv6_accesslist_name) + { + if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) && + (access_list_apply (acl, p) == FILTER_DENY)) + { + char *buf; + zlog (NULL, LOG_INFO, "Vty connection refused from %s", + (buf = sockunion_su2str (&su))); + free (buf); + close (vty_sock); + + /* continue accepting connections */ + vty_event (VTY_SERV, accept_sock, NULL); + + prefix_free (p); + + return 0; + } + } +#endif /* HAVE_IPV6 */ + + prefix_free (p); + + on = 1; + ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, + (char *) &on, sizeof (on)); + if (ret < 0) + zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", + strerror (errno)); + + vty = vty_create (vty_sock, &su); + + return 0; +} + +#if defined(HAVE_IPV6) || defined(HAVE_GETADDRINFO) +void +vty_serv_sock_addrinfo (const char *hostname, unsigned short port) +{ + int ret; + struct addrinfo req; + struct addrinfo *ainfo; + struct addrinfo *ainfo_save; + int sock; + char port_str[BUFSIZ]; + + memset (&req, 0, sizeof (struct addrinfo)); + req.ai_flags = AI_PASSIVE; + req.ai_family = AF_UNSPEC; + req.ai_socktype = SOCK_STREAM; + sprintf (port_str, "%d", port); + port_str[sizeof (port_str) - 1] = '\0'; + + ret = getaddrinfo (hostname, port_str, &req, &ainfo); + + if (ret != 0) + { + fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret)); + exit (1); + } + + ainfo_save = ainfo; + + do + { + if (ainfo->ai_family != AF_INET +#ifdef HAVE_IPV6 + && ainfo->ai_family != AF_INET6 +#endif /* HAVE_IPV6 */ + ) + continue; + + sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); + if (sock < 0) + continue; + + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); + + ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen); + if (ret < 0) + { + close (sock); /* Avoid sd leak. */ + continue; + } + + ret = listen (sock, 3); + if (ret < 0) + { + close (sock); /* Avoid sd leak. */ + continue; + } + + vty_event (VTY_SERV, sock, NULL); + } + while ((ainfo = ainfo->ai_next) != NULL); + + freeaddrinfo (ainfo_save); +} +#endif /* ! (defined(HAVE_IPV6) || defined(HAVE_GETADDRINFO)) */ + +/* Make vty server socket. */ +void +vty_serv_sock_family (unsigned short port, int family) +{ + int ret; + union sockunion su; + int accept_sock; + + memset (&su, 0, sizeof (union sockunion)); + su.sa.sa_family = family; + + /* Make new socket. */ + accept_sock = sockunion_stream_socket (&su); + if (accept_sock < 0) + return; + + /* This is server, so reuse address. */ + sockopt_reuseaddr (accept_sock); + sockopt_reuseport (accept_sock); + + /* Bind socket to universal address and given port. */ + ret = sockunion_bind (accept_sock, &su, port, NULL); + if (ret < 0) + { + close (accept_sock); /* Avoid sd leak. */ + return; + } + + /* Listen socket under queue 3. */ + ret = listen (accept_sock, 3); + if (ret < 0) + { + zlog (NULL, LOG_WARNING, "can't listen socket"); + close (accept_sock); /* Avoid sd leak. */ + return; + } + + /* Add vty server event. */ + vty_event (VTY_SERV, accept_sock, NULL); +} + +#ifdef VTYSH +/* For sockaddr_un. */ +#include + +/* VTY shell UNIX domain socket. */ +void +vty_serv_un (char *path) +{ + int ret; + int sock, len; + struct sockaddr_un serv; + mode_t old_mask; + + /* First of all, unlink existing socket */ + unlink (path); + + /* Set umask */ + old_mask = umask (0077); + + /* Make UNIX domain socket. */ + sock = socket (AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + { + perror ("sock"); + return; + } + + /* Make server socket. */ + memset (&serv, 0, sizeof (struct sockaddr_un)); + serv.sun_family = AF_UNIX; + strncpy (serv.sun_path, path, strlen (path)); +#ifdef HAVE_SUN_LEN + len = serv.sun_len = SUN_LEN(&serv); +#else + len = sizeof (serv.sun_family) + strlen (serv.sun_path); +#endif /* HAVE_SUN_LEN */ + + ret = bind (sock, (struct sockaddr *) &serv, len); + if (ret < 0) + { + perror ("bind"); + close (sock); /* Avoid sd leak. */ + return; + } + + ret = listen (sock, 5); + if (ret < 0) + { + perror ("listen"); + close (sock); /* Avoid sd leak. */ + return; + } + + umask (old_mask); + + vty_event (VTYSH_SERV, sock, NULL); +} + +/* #define VTYSH_DEBUG 1 */ + +static int +vtysh_accept (struct thread *thread) +{ + int accept_sock; + int sock; + int client_len; + struct sockaddr_un client; + struct vty *vty; + + accept_sock = THREAD_FD (thread); + + vty_event (VTYSH_SERV, accept_sock, NULL); + + memset (&client, 0, sizeof (struct sockaddr_un)); + client_len = sizeof (struct sockaddr_un); + + sock = accept (accept_sock, (struct sockaddr *) &client, &client_len); + + if (sock < 0) + { + zlog_warn ("can't accept vty socket : %s", strerror (errno)); + return -1; + } + +#ifdef VTYSH_DEBUG + printf ("VTY shell accept\n"); +#endif /* VTYSH_DEBUG */ + + vty = vty_new (); + vty->fd = sock; + vty->type = VTY_SHELL_SERV; + vty->node = VIEW_NODE; + + vty_event (VTYSH_READ, sock, vty); + + return 0; +} + +static int +vtysh_read (struct thread *thread) +{ + int ret; + int sock; + int nbytes; + struct vty *vty; + unsigned char buf[VTY_READ_BUFSIZ]; + u_char header[4] = {0, 0, 0, 0}; + + sock = THREAD_FD (thread); + vty = THREAD_ARG (thread); + vty->t_read = NULL; + + nbytes = read (sock, buf, VTY_READ_BUFSIZ); + if (nbytes <= 0) + { + vty_close (vty); +#ifdef VTYSH_DEBUG + printf ("close vtysh\n"); +#endif /* VTYSH_DEBUG */ + return 0; + } + +#ifdef VTYSH_DEBUG + printf ("line: %s\n", buf); +#endif /* VTYSH_DEBUG */ + + vty_ensure (vty, nbytes); + memcpy (vty->buf, buf, nbytes); + + /* Pass this line to parser. */ + ret = vty_execute (vty); + + vty_clear_buf (vty); + + /* Return result. */ +#ifdef VTYSH_DEBUG + printf ("result: %d\n", ret); + printf ("vtysh node: %d\n", vty->node); +#endif /* VTYSH_DEBUG */ + + header[3] = ret; + write (vty->fd, header, 4); + + vty_event (VTYSH_READ, sock, vty); + + return 0; +} +#endif /* VTYSH */ + +/* Determine address family to bind. */ +void +vty_serv_sock (const char *hostname, unsigned short port, char *path) +{ + /* If port is set to 0, do not listen on TCP/IP at all! */ + if (port) + { + +#if defined(HAVE_IPV6) || defined(HAVE_GETADDRINFO) + vty_serv_sock_addrinfo (hostname, port); +#else /* ! (defined(HAVE_IPV6) || defined(HAVE_GETADDRINFO)) */ + vty_serv_sock_family (port, AF_INET); +#endif /* HAVE_IPV6 */ + } + +#ifdef VTYSH + vty_serv_un (path); +#endif /* VTYSH */ +} + +/* Close vty interface. */ +void +vty_close (struct vty *vty) +{ + int i; + + /* Cancel threads.*/ + if (vty->t_read) + thread_cancel (vty->t_read); + if (vty->t_write) + thread_cancel (vty->t_write); + if (vty->t_timeout) + thread_cancel (vty->t_timeout); + if (vty->t_output) + thread_cancel (vty->t_output); + + /* Flush buffer. */ + if (! buffer_empty (vty->obuf)) + buffer_flush_all (vty->obuf, vty->fd); + + /* Free input buffer. */ + buffer_free (vty->obuf); + + /* Free SB buffer. */ + if (vty->sb_buffer) + buffer_free (vty->sb_buffer); + + /* Free command history. */ + for (i = 0; i < VTY_MAXHIST; i++) + if (vty->hist[i]) + XFREE (MTYPE_VTY_HIST, vty->hist[i]); + + /* Unset vector. */ + vector_unset (vtyvec, vty->fd); + + /* Close socket. */ + if (vty->fd > 0) + close (vty->fd); + + if (vty->address) + XFREE (0, vty->address); + if (vty->buf) + XFREE (MTYPE_VTY, vty->buf); + + /* Check configure. */ + vty_config_unlock (vty); + + /* OK free vty. */ + XFREE (MTYPE_VTY, vty); +} + +/* When time out occur output message then close connection. */ +static int +vty_timeout (struct thread *thread) +{ + struct vty *vty; + + vty = THREAD_ARG (thread); + vty->t_timeout = NULL; + vty->v_timeout = 0; + + /* Clear buffer*/ + buffer_reset (vty->obuf); + vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE); + + /* Close connection. */ + vty->status = VTY_CLOSE; + vty_close (vty); + + return 0; +} + +/* Read up configuration file from file_name. */ +static void +vty_read_file (FILE *confp) +{ + int ret; + struct vty *vty; + + vty = vty_new (); + vty->fd = 0; /* stdout */ + vty->type = VTY_TERM; + vty->node = CONFIG_NODE; + + /* Execute configuration file */ + ret = config_from_file (vty, confp); + + if (ret != CMD_SUCCESS) + { + switch (ret) + { + case CMD_ERR_AMBIGUOUS: + fprintf (stderr, "Ambiguous command.\n"); + break; + case CMD_ERR_NO_MATCH: + fprintf (stderr, "There is no such command.\n"); + break; + } + fprintf (stderr, "Error occured during reading below line.\n%s\n", + vty->buf); + vty_close (vty); + exit (1); + } + + vty_close (vty); +} + +FILE * +vty_use_backup_config (char *fullpath) +{ + char *fullpath_sav, *fullpath_tmp; + FILE *ret = NULL; + struct stat buf; + int tmp, sav; + int c; + char buffer[512]; + + fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1); + strcpy (fullpath_sav, fullpath); + strcat (fullpath_sav, CONF_BACKUP_EXT); + if (stat (fullpath_sav, &buf) == -1) + { + free (fullpath_sav); + return NULL; + } + + fullpath_tmp = malloc (strlen (fullpath) + 8); + sprintf (fullpath_tmp, "%s.XXXXXX", fullpath); + + /* Open file to configuration write. */ + tmp = mkstemp (fullpath_tmp); + if (tmp < 0) + { + free (fullpath_sav); + free (fullpath_tmp); + return NULL; + } + + sav = open (fullpath_sav, O_RDONLY); + if (sav < 0) + { + free (fullpath_sav); + free (fullpath_tmp); + unlink (fullpath_tmp); + return NULL; + } + + while((c = read (sav, buffer, 512)) > 0) + write (tmp, buffer, c); + + close (sav); + close (tmp); + + if (link (fullpath_tmp, fullpath) == 0) + ret = fopen (fullpath, "r"); + + unlink (fullpath_tmp); + + free (fullpath_sav); + free (fullpath_tmp); + return fopen (fullpath, "r"); +} + +/* Read up configuration file from file_name. */ +void +vty_read_config (char *config_file, + char *config_current_dir, + char *config_default_dir) +{ + char *cwd; + FILE *confp = NULL; + char *fullpath; + + /* If -f flag specified. */ + if (config_file != NULL) + { + if (! IS_DIRECTORY_SEP (config_file[0])) + { + cwd = getcwd (NULL, MAXPATHLEN); + fullpath = XMALLOC (MTYPE_TMP, + strlen (cwd) + strlen (config_file) + 2); + sprintf (fullpath, "%s/%s", cwd, config_file); + } + else + fullpath = config_file; + + confp = fopen (fullpath, "r"); + + if (confp == NULL) + { + confp = vty_use_backup_config (fullpath); + if (confp) + fprintf (stderr, "WARNING: using backup configuration file!\n"); + else + { + fprintf (stderr, "can't open configuration file [%s]\n", + config_file); + exit(1); + } + } + } + else + { + /* Relative path configuration file open. */ + if (config_current_dir) + { + confp = fopen (config_current_dir, "r"); + if (confp == NULL) + { + confp = vty_use_backup_config (config_current_dir); + if (confp) + fprintf (stderr, "WARNING: using backup configuration file!\n"); + } + } + + /* If there is no relative path exists, open system default file. */ + if (confp == NULL) + { +#ifdef VTYSH + int ret; + struct stat conf_stat; + + /* !!!!PLEASE LEAVE!!!! + This is NEEDED for use with vtysh -b, or else you can get + a real configuration food fight with a lot garbage in the + merged configuration file it creates coming from the per + daemon configuration files. This also allows the daemons + to start if there default configuration file is not + present or ignore them, as needed when using vtysh -b to + configure the daemons at boot - MAG */ + + /* Stat for vtysh Zebra.conf, if found startup and wait for + boot configuration */ + + if ( strstr(config_default_dir, "vtysh") == NULL) + { + ret = stat (integrate_default, &conf_stat); + if (ret >= 0) + { + return; + } + } +#endif /* VTYSH */ + + confp = fopen (config_default_dir, "r"); + if (confp == NULL) + { + confp = vty_use_backup_config (config_default_dir); + if (confp) + { + fprintf (stderr, "WARNING: using backup configuration file!\n"); + fullpath = config_default_dir; + } + else + { + fprintf (stderr, "can't open configuration file [%s]\n", + config_default_dir); + exit (1); + } + } + else + fullpath = config_default_dir; + } + else + { + /* Rleative path configuration file. */ + cwd = getcwd (NULL, MAXPATHLEN); + fullpath = XMALLOC (MTYPE_TMP, + strlen (cwd) + strlen (config_current_dir) + 2); + sprintf (fullpath, "%s/%s", cwd, config_current_dir); + } + } + vty_read_file (confp); + + fclose (confp); + + host_config_set (fullpath); +} + +/* Small utility function which output log to the VTY. */ +void +vty_log (const char *proto_str, const char *format, va_list va) +{ + int i; + struct vty *vty; + + for (i = 0; i < vector_max (vtyvec); i++) + if ((vty = vector_slot (vtyvec, i)) != NULL) + if (vty->monitor) + vty_log_out (vty, proto_str, format, va); +} + +int +vty_config_lock (struct vty *vty) +{ + if (vty_config == 0) + { + vty->config = 1; + vty_config = 1; + } + return vty->config; +} + +int +vty_config_unlock (struct vty *vty) +{ + if (vty_config == 1 && vty->config == 1) + { + vty->config = 0; + vty_config = 0; + } + return vty->config; +} + +/* Master of the threads. */ +extern struct thread_master *master; +/* struct thread_master *master; */ + +static void +vty_event (enum event event, int sock, struct vty *vty) +{ + struct thread *vty_serv_thread; + + switch (event) + { + case VTY_SERV: + vty_serv_thread = thread_add_read (master, vty_accept, vty, sock); + vector_set_index (Vvty_serv_thread, sock, vty_serv_thread); + break; +#ifdef VTYSH + case VTYSH_SERV: + thread_add_read (master, vtysh_accept, vty, sock); + break; + case VTYSH_READ: + thread_add_read (master, vtysh_read, vty, sock); + break; +#endif /* VTYSH */ + case VTY_READ: + vty->t_read = thread_add_read (master, vty_read, vty, sock); + + /* Time out treatment. */ + if (vty->v_timeout) + { + if (vty->t_timeout) + thread_cancel (vty->t_timeout); + vty->t_timeout = + thread_add_timer (master, vty_timeout, vty, vty->v_timeout); + } + break; + case VTY_WRITE: + if (! vty->t_write) + vty->t_write = thread_add_write (master, vty_flush, vty, sock); + break; + case VTY_TIMEOUT_RESET: + if (vty->t_timeout) + { + thread_cancel (vty->t_timeout); + vty->t_timeout = NULL; + } + if (vty->v_timeout) + { + vty->t_timeout = + thread_add_timer (master, vty_timeout, vty, vty->v_timeout); + } + break; + } +} + +DEFUN (config_who, + config_who_cmd, + "who", + "Display who is on vty\n") +{ + int i; + struct vty *v; + + for (i = 0; i < vector_max (vtyvec); i++) + if ((v = vector_slot (vtyvec, i)) != NULL) + vty_out (vty, "%svty[%d] connected from %s.%s", + v->config ? "*" : " ", + i, v->address, VTY_NEWLINE); + return CMD_SUCCESS; +} + +/* Move to vty configuration mode. */ +DEFUN (line_vty, + line_vty_cmd, + "line vty", + "Configure a terminal line\n" + "Virtual terminal\n") +{ + vty->node = VTY_NODE; + return CMD_SUCCESS; +} + +/* Set time out value. */ +int +exec_timeout (struct vty *vty, char *min_str, char *sec_str) +{ + unsigned long timeout = 0; + + /* min_str and sec_str are already checked by parser. So it must be + all digit string. */ + if (min_str) + { + timeout = strtol (min_str, NULL, 10); + timeout *= 60; + } + if (sec_str) + timeout += strtol (sec_str, NULL, 10); + + vty_timeout_val = timeout; + vty->v_timeout = timeout; + vty_event (VTY_TIMEOUT_RESET, 0, vty); + + + return CMD_SUCCESS; +} + +DEFUN (exec_timeout_min, + exec_timeout_min_cmd, + "exec-timeout <0-35791>", + "Set timeout value\n" + "Timeout value in minutes\n") +{ + return exec_timeout (vty, argv[0], NULL); +} + +DEFUN (exec_timeout_sec, + exec_timeout_sec_cmd, + "exec-timeout <0-35791> <0-2147483>", + "Set the EXEC timeout\n" + "Timeout in minutes\n" + "Timeout in seconds\n") +{ + return exec_timeout (vty, argv[0], argv[1]); +} + +DEFUN (no_exec_timeout, + no_exec_timeout_cmd, + "no exec-timeout", + NO_STR + "Set the EXEC timeout\n") +{ + return exec_timeout (vty, NULL, NULL); +} + +/* Set vty access class. */ +DEFUN (vty_access_class, + vty_access_class_cmd, + "access-class WORD", + "Filter connections based on an IP access list\n" + "IP access list\n") +{ + if (vty_accesslist_name) + XFREE(MTYPE_VTY, vty_accesslist_name); + + vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]); + + return CMD_SUCCESS; +} + +/* Clear vty access class. */ +DEFUN (no_vty_access_class, + no_vty_access_class_cmd, + "no access-class [WORD]", + NO_STR + "Filter connections based on an IP access list\n" + "IP access list\n") +{ + if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0]))) + { + vty_out (vty, "Access-class is not currently applied to vty%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + XFREE(MTYPE_VTY, vty_accesslist_name); + + vty_accesslist_name = NULL; + + return CMD_SUCCESS; +} + +#ifdef HAVE_IPV6 +/* Set vty access class. */ +DEFUN (vty_ipv6_access_class, + vty_ipv6_access_class_cmd, + "ipv6 access-class WORD", + IPV6_STR + "Filter connections based on an IP access list\n" + "IPv6 access list\n") +{ + if (vty_ipv6_accesslist_name) + XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); + + vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]); + + return CMD_SUCCESS; +} + +/* Clear vty access class. */ +DEFUN (no_vty_ipv6_access_class, + no_vty_ipv6_access_class_cmd, + "no ipv6 access-class [WORD]", + NO_STR + IPV6_STR + "Filter connections based on an IP access list\n" + "IPv6 access list\n") +{ + if (! vty_ipv6_accesslist_name || + (argc && strcmp(vty_ipv6_accesslist_name, argv[0]))) + { + vty_out (vty, "IPv6 access-class is not currently applied to vty%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); + + vty_ipv6_accesslist_name = NULL; + + return CMD_SUCCESS; +} +#endif /* HAVE_IPV6 */ + +/* vty login. */ +DEFUN (vty_login, + vty_login_cmd, + "login", + "Enable password checking\n") +{ + no_password_check = 0; + return CMD_SUCCESS; +} + +DEFUN (no_vty_login, + no_vty_login_cmd, + "no login", + NO_STR + "Enable password checking\n") +{ + no_password_check = 1; + return CMD_SUCCESS; +} + +DEFUN (service_advanced_vty, + service_advanced_vty_cmd, + "service advanced-vty", + "Set up miscellaneous service\n" + "Enable advanced mode vty interface\n") +{ + host.advanced = 1; + return CMD_SUCCESS; +} + +DEFUN (no_service_advanced_vty, + no_service_advanced_vty_cmd, + "no service advanced-vty", + NO_STR + "Set up miscellaneous service\n" + "Enable advanced mode vty interface\n") +{ + host.advanced = 0; + return CMD_SUCCESS; +} + +DEFUN (terminal_monitor, + terminal_monitor_cmd, + "terminal monitor", + "Set terminal line parameters\n" + "Copy debug output to the current terminal line\n") +{ + vty->monitor = 1; + return CMD_SUCCESS; +} + +DEFUN (terminal_no_monitor, + terminal_no_monitor_cmd, + "terminal no monitor", + "Set terminal line parameters\n" + NO_STR + "Copy debug output to the current terminal line\n") +{ + vty->monitor = 0; + return CMD_SUCCESS; +} + +DEFUN (show_history, + show_history_cmd, + "show history", + SHOW_STR + "Display the session command history\n") +{ + int index; + + for (index = vty->hindex + 1; index != vty->hindex;) + { + if (index == VTY_MAXHIST) + { + index = 0; + continue; + } + + if (vty->hist[index] != NULL) + vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE); + + index++; + } + + return CMD_SUCCESS; +} + +/* Display current configuration. */ +int +vty_config_write (struct vty *vty) +{ + vty_out (vty, "line vty%s", VTY_NEWLINE); + + if (vty_accesslist_name) + vty_out (vty, " access-class %s%s", + vty_accesslist_name, VTY_NEWLINE); + + if (vty_ipv6_accesslist_name) + vty_out (vty, " ipv6 access-class %s%s", + vty_ipv6_accesslist_name, VTY_NEWLINE); + + /* exec-timeout */ + if (vty_timeout_val != VTY_TIMEOUT_DEFAULT) + vty_out (vty, " exec-timeout %ld %ld%s", + vty_timeout_val / 60, + vty_timeout_val % 60, VTY_NEWLINE); + + /* login */ + if (no_password_check) + vty_out (vty, " no login%s", VTY_NEWLINE); + + vty_out (vty, "!%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +struct cmd_node vty_node = + { + VTY_NODE, + "%s(config-line)# ", + }; + +/* Reset all VTY status. */ +void +vty_reset () +{ + int i; + struct vty *vty; + struct thread *vty_serv_thread; + + for (i = 0; i < vector_max (vtyvec); i++) + if ((vty = vector_slot (vtyvec, i)) != NULL) + { + buffer_reset (vty->obuf); + vty->status = VTY_CLOSE; + vty_close (vty); + } + + for (i = 0; i < vector_max (Vvty_serv_thread); i++) + if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL) + { + thread_cancel (vty_serv_thread); + vector_slot (Vvty_serv_thread, i) = NULL; + close (i); + } + + vty_timeout_val = VTY_TIMEOUT_DEFAULT; + + if (vty_accesslist_name) + { + XFREE(MTYPE_VTY, vty_accesslist_name); + vty_accesslist_name = NULL; + } + + if (vty_ipv6_accesslist_name) + { + XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); + vty_ipv6_accesslist_name = NULL; + } +} + +/* for ospf6d easy temprary reload function */ +/* vty_reset + close accept socket */ +void +vty_finish () +{ + int i; + struct vty *vty; + struct thread *vty_serv_thread; + + for (i = 0; i < vector_max (vtyvec); i++) + if ((vty = vector_slot (vtyvec, i)) != NULL) + { + buffer_reset (vty->obuf); + vty->status = VTY_CLOSE; + vty_close (vty); + } + + for (i = 0; i < vector_max (Vvty_serv_thread); i++) + if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL) + { + thread_cancel (vty_serv_thread); + vector_slot (Vvty_serv_thread, i) = NULL; + close (i); + } + + vty_timeout_val = VTY_TIMEOUT_DEFAULT; + + if (vty_accesslist_name) + { + XFREE(MTYPE_VTY, vty_accesslist_name); + vty_accesslist_name = NULL; + } + + if (vty_ipv6_accesslist_name) + { + XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); + vty_ipv6_accesslist_name = NULL; + } +} + +void +vty_save_cwd () +{ + char *cwd; + + cwd = getcwd (NULL, MAXPATHLEN); + + vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1); + strcpy (vty_cwd, cwd); +} + +char * +vty_get_cwd () +{ + return vty_cwd; +} + +int +vty_shell (struct vty *vty) +{ + return vty->type == VTY_SHELL ? 1 : 0; +} + +int +vty_shell_serv (struct vty *vty) +{ + return vty->type == VTY_SHELL_SERV ? 1 : 0; +} + +void +vty_init_vtysh () +{ + vtyvec = vector_init (VECTOR_MIN_SIZE); +} + +/* Install vty's own commands like `who' command. */ +void +vty_init () +{ + /* For further configuration read, preserve current directory. */ + vty_save_cwd (); + + vtyvec = vector_init (VECTOR_MIN_SIZE); + + /* Initilize server thread vector. */ + Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE); + + /* Install bgp top node. */ + install_node (&vty_node, vty_config_write); + + install_element (VIEW_NODE, &config_who_cmd); + install_element (VIEW_NODE, &show_history_cmd); + install_element (ENABLE_NODE, &config_who_cmd); + install_element (CONFIG_NODE, &line_vty_cmd); + install_element (CONFIG_NODE, &service_advanced_vty_cmd); + install_element (CONFIG_NODE, &no_service_advanced_vty_cmd); + install_element (CONFIG_NODE, &show_history_cmd); + install_element (ENABLE_NODE, &terminal_monitor_cmd); + install_element (ENABLE_NODE, &terminal_no_monitor_cmd); + install_element (ENABLE_NODE, &show_history_cmd); + + install_default (VTY_NODE); + install_element (VTY_NODE, &exec_timeout_min_cmd); + install_element (VTY_NODE, &exec_timeout_sec_cmd); + install_element (VTY_NODE, &no_exec_timeout_cmd); + install_element (VTY_NODE, &vty_access_class_cmd); + install_element (VTY_NODE, &no_vty_access_class_cmd); + install_element (VTY_NODE, &vty_login_cmd); + install_element (VTY_NODE, &no_vty_login_cmd); +#ifdef HAVE_IPV6 + install_element (VTY_NODE, &vty_ipv6_access_class_cmd); + install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd); +#endif /* HAVE_IPV6 */ +} diff --git a/lib/vty.h b/lib/vty.h new file mode 100644 index 0000000..4d2a6a0 --- /dev/null +++ b/lib/vty.h @@ -0,0 +1,205 @@ +/* Virtual terminal [aka TeletYpe] interface routine + Copyright (C) 1997 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _ZEBRA_VTY_H +#define _ZEBRA_VTY_H + +#define VTY_BUFSIZ 512 +#define VTY_MAXHIST 20 + +/* VTY struct. */ +struct vty +{ + /* File descripter of this vty. */ + int fd; + + /* Is this vty connect to file or not */ + enum {VTY_TERM, VTY_FILE, VTY_SHELL, VTY_SHELL_SERV} type; + + /* Node status of this vty */ + int node; + + /* What address is this vty comming from. */ + char *address; + + /* Privilege level of this vty. */ + int privilege; + + /* Failure count */ + int fail; + + /* Output buffer. */ + struct buffer *obuf; + + /* Command input buffer */ + char *buf; + + /* Command cursor point */ + int cp; + + /* Command length */ + int length; + + /* Command max length. */ + int max; + + /* Histry of command */ + char *hist[VTY_MAXHIST]; + + /* History lookup current point */ + int hp; + + /* History insert end point */ + int hindex; + + /* For current referencing point of interface, route-map, + access-list etc... */ + void *index; + + /* For multiple level index treatment such as key chain and key. */ + void *index_sub; + + /* For escape character. */ + unsigned char escape; + + /* Current vty status. */ + enum {VTY_NORMAL, VTY_CLOSE, VTY_MORE, VTY_MORELINE, + VTY_START, VTY_CONTINUE} status; + + /* IAC handling */ + unsigned char iac; + + /* IAC SB handling */ + unsigned char iac_sb_in_progress; + struct buffer *sb_buffer; + + /* Window width/height. */ + int width; + int height; + + int scroll_one; + + /* Configure lines. */ + int lines; + + /* Current executing function pointer. */ + int (*func) (struct vty *, void *arg); + + /* Terminal monitor. */ + int monitor; + + /* In configure mode. */ + int config; + + /* Read and write thread. */ + struct thread *t_read; + struct thread *t_write; + + /* Timeout seconds and thread. */ + unsigned long v_timeout; + struct thread *t_timeout; + + /* Thread output function. */ + struct thread *t_output; + + /* Output data pointer. */ + int (*output_func) (struct vty *, int); + void (*output_clean) (struct vty *); + void *output_rn; + unsigned long output_count; + int output_type; + void *output_arg; +}; + +/* Integrated configuration file. */ +#define INTEGRATE_DEFAULT_CONFIG "Zebra.conf" + +/* Small macro to determine newline is newline only or linefeed needed. */ +#define VTY_NEWLINE ((vty->type == VTY_TERM) ? "\r\n" : "\n") + +/* Default time out value */ +#define VTY_TIMEOUT_DEFAULT 600 + +/* Vty read buffer size. */ +#define VTY_READ_BUFSIZ 512 + +/* Directory separator. */ +#ifndef DIRECTORY_SEP +#define DIRECTORY_SEP '/' +#endif /* DIRECTORY_SEP */ + +#ifndef IS_DIRECTORY_SEP +#define IS_DIRECTORY_SEP(c) ((c) == DIRECTORY_SEP) +#endif + +/* GCC have printf type attribute check. */ +#ifdef __GNUC__ +#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) +#else +#define PRINTF_ATTRIBUTE(a,b) +#endif /* __GNUC__ */ + +/* Utility macro to convert VTY argument to unsigned integer. */ +#define VTY_GET_INTEGER(NAME,V,STR) \ +{ \ + char *endptr = NULL; \ + (V) = strtoul ((STR), &endptr, 10); \ + if ((V) == ULONG_MAX || *endptr != '\0') \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_INTEGER_RANGE(NAME,V,STR,MIN,MAX) \ +{ \ + char *endptr = NULL; \ + (V) = strtoul ((STR), &endptr, 10); \ + if ((V) == ULONG_MAX || *endptr != '\0' \ + || (V) < (MIN) || (V) > (MAX)) \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +/* Exported variables */ +extern char integrate_default[]; + +/* Prototypes. */ +void vty_init (void); +void vty_init_vtysh (void); +void vty_reset (void); +void vty_finish (void); +struct vty *vty_new (void); +int vty_out (struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); +void vty_read_config (char *, char *, char *); +void vty_time_print (struct vty *, int); +void vty_serv_sock (const char *, unsigned short, char *); +void vty_close (struct vty *); +char *vty_get_cwd (void); +void vty_log (const char *, const char *, va_list); +int vty_config_lock (struct vty *); +int vty_config_unlock (struct vty *); +int vty_shell (struct vty *); +int vty_shell_serv (struct vty *); +void vty_hello (struct vty *); + +#endif /* _ZEBRA_VTY_H */ diff --git a/lib/zclient.c b/lib/zclient.c new file mode 100644 index 0000000..5e37154 --- /dev/null +++ b/lib/zclient.c @@ -0,0 +1,901 @@ +/* Zebra's client library. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "stream.h" +#include "network.h" +#include "if.h" +#include "log.h" +#include "thread.h" +#include "zclient.h" +#include "memory.h" +#include "table.h" + +#include "zebra/rib.h" +#include "zebra/zserv.h" + +/* Zebra client events. */ +enum event {ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT}; + +/* Prototype for event manager. */ +static void zclient_event (enum event, struct zclient *); + +/* This file local debug flag. */ +int zclient_debug = 0; + +/* Allocate zclient structure. */ +struct zclient * +zclient_new () +{ + struct zclient *zclient; + zclient = XMALLOC (MTYPE_ZCLIENT, sizeof (struct zclient)); + memset (zclient, 0, sizeof (struct zclient)); + + zclient->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); + zclient->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); + + return zclient; +} + +/* Free zclient structure. */ +void +zclient_free (struct zclient *zclient) +{ + XFREE (MTYPE_ZCLIENT, zclient); +} + +/* Initialize zebra client. Argument redist_default is unwanted + redistribute route type. */ +void +zclient_init (struct zclient *zclient, int redist_default) +{ + int i; + + /* Enable zebra client connection by default. */ + zclient->enable = 1; + + /* Set -1 to the default socket value. */ + zclient->sock = -1; + + /* Clear redistribution flags. */ + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + zclient->redist[i] = 0; + + /* Set unwanted redistribute route. bgpd does not need BGP route + redistribution. */ + zclient->redist_default = redist_default; + zclient->redist[redist_default] = 1; + + /* Set default-information redistribute to zero. */ + zclient->default_information = 0; + + /* Schedule first zclient connection. */ + if (zclient_debug) + zlog_info ("zclient start scheduled"); + + zclient_event (ZCLIENT_SCHEDULE, zclient); +} + +/* Stop zebra client services. */ +void +zclient_stop (struct zclient *zclient) +{ + if (zclient_debug) + zlog_info ("zclient stopped"); + + /* Stop threads. */ + if (zclient->t_read) + { + thread_cancel (zclient->t_read); + zclient->t_read = NULL; + } + if (zclient->t_connect) + { + thread_cancel (zclient->t_connect); + zclient->t_connect = NULL; + } + + /* Close socket. */ + if (zclient->sock >= 0) + { + close (zclient->sock); + zclient->sock = -1; + } + zclient->fail = 0; +} + +void +zclient_reset (struct zclient *zclient) +{ + zclient_stop (zclient); + zclient_init (zclient, zclient->redist_default); +} + +/* Make socket to zebra daemon. Return zebra socket. */ +int +zclient_socket () +{ + int sock; + int ret; + struct sockaddr_in serv; + + /* We should think about IPv6 connection. */ + sock = socket (AF_INET, SOCK_STREAM, 0); + if (sock < 0) + return -1; + + /* Make server socket. */ + memset (&serv, 0, sizeof (struct sockaddr_in)); + serv.sin_family = AF_INET; + serv.sin_port = htons (ZEBRA_PORT); +#ifdef HAVE_SIN_LEN + serv.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + /* Connect to zebra. */ + ret = connect (sock, (struct sockaddr *) &serv, sizeof (serv)); + if (ret < 0) + { + close (sock); + return -1; + } + return sock; +} + +/* For sockaddr_un. */ +#include + +int +zclient_socket_un (char *path) +{ + int ret; + int sock, len; + struct sockaddr_un addr; + + sock = socket (AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + return -1; + + /* Make server socket. */ + memset (&addr, 0, sizeof (struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy (addr.sun_path, path, strlen (path)); +#ifdef HAVE_SUN_LEN + len = addr.sun_len = SUN_LEN(&addr); +#else + len = sizeof (addr.sun_family) + strlen (addr.sun_path); +#endif /* HAVE_SUN_LEN */ + + ret = connect (sock, (struct sockaddr *) &addr, len); + if (ret < 0) + { + close (sock); + return -1; + } + return sock; +} + +/* Send simple Zebra message. */ +int +zebra_message_send (struct zclient *zclient, int command) +{ + struct stream *s; + + /* Get zclient output buffer. */ + s = zclient->obuf; + stream_reset (s); + + /* Send very simple command only Zebra message. */ + stream_putw (s, 3); + stream_putc (s, command); + + return writen (zclient->sock, s->data, 3); +} + +/* Make connection to zebra daemon. */ +int +zclient_start (struct zclient *zclient) +{ + int i; + + if (zclient_debug) + zlog_info ("zclient_start is called"); + + /* zclient is disabled. */ + if (! zclient->enable) + return 0; + + /* If already connected to the zebra. */ + if (zclient->sock >= 0) + return 0; + + /* Check connect thread. */ + if (zclient->t_connect) + return 0; + + /* Make socket. */ +#ifdef HAVE_TCP_ZEBRA + zclient->sock = zclient_socket (); +#else + zclient->sock = zclient_socket_un (ZEBRA_SERV_PATH); +#endif /* HAVE_TCP_ZEBRA */ + if (zclient->sock < 0) + { + if (zclient_debug) + zlog_info ("zclient connection fail"); + zclient->fail++; + zclient_event (ZCLIENT_CONNECT, zclient); + return -1; + } + + /* Clear fail count. */ + zclient->fail = 0; + if (zclient_debug) + zlog_info ("zclient connect success with socket [%d]", zclient->sock); + + /* Create read thread. */ + zclient_event (ZCLIENT_READ, zclient); + + /* We need interface information. */ + zebra_message_send (zclient, ZEBRA_INTERFACE_ADD); + + /* Flush all redistribute request. */ + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (i != zclient->redist_default && zclient->redist[i]) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, i); + + /* If default information is needed. */ + if (zclient->default_information) + zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD); + + return 0; +} + +/* This function is a wrapper function for calling zclient_start from + timer or event thread. */ +int +zclient_connect (struct thread *t) +{ + struct zclient *zclient; + + zclient = THREAD_ARG (t); + zclient->t_connect = NULL; + + if (zclient_debug) + zlog_info ("zclient_connect is called"); + + return zclient_start (zclient); +} + +int +zapi_ipv4_add (struct zclient *zclient, struct prefix_ipv4 *p, + struct zapi_ipv4 *api) +{ + int i; + int psize; + struct stream *s; + + /* Reset stream. */ + s = zclient->obuf; + stream_reset (s); + + /* Length place holder. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV4_ROUTE_ADD); + stream_putc (s, api->type); + stream_putc (s, api->flags); + stream_putc (s, api->message); + + /* Put prefix information. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop, ifindex, distance and metric information. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE)) + { + stream_putc (s, 1); + stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE); + } + else + stream_putc (s, api->nexthop_num + api->ifindex_num); + + for (i = 0; i < api->nexthop_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IPV4); + stream_put_in_addr (s, api->nexthop[i]); + } + for (i = 0; i < api->ifindex_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putl (s, api->ifindex[i]); + } + } + + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE)) + stream_putc (s, api->distance); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) + stream_putl (s, api->metric); + + /* Put length at the first point of the stream. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + return writen (zclient->sock, s->data, stream_get_endp (s)); +} + +int +zapi_ipv4_delete (struct zclient *zclient, struct prefix_ipv4 *p, + struct zapi_ipv4 *api) +{ + int i; + int psize; + struct stream *s; + + /* Reset stream. */ + s = zclient->obuf; + stream_reset (s); + + /* Length place holder. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV4_ROUTE_DELETE); + stream_putc (s, api->type); + stream_putc (s, api->flags); + stream_putc (s, api->message); + + /* Put prefix information. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop, ifindex, distance and metric information. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE)) + { + stream_putc (s, 1); + stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE); + } + else + stream_putc (s, api->nexthop_num + api->ifindex_num); + + for (i = 0; i < api->nexthop_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IPV4); + stream_put_in_addr (s, api->nexthop[i]); + } + for (i = 0; i < api->ifindex_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putl (s, api->ifindex[i]); + } + } + + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE)) + stream_putc (s, api->distance); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) + stream_putl (s, api->metric); + + /* Put length at the first point of the stream. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + return writen (zclient->sock, s->data, stream_get_endp (s)); +} + +#ifdef HAVE_IPV6 +int +zapi_ipv6_add (struct zclient *zclient, struct prefix_ipv6 *p, + struct zapi_ipv6 *api) +{ + int i; + int psize; + struct stream *s; + + /* Reset stream. */ + s = zclient->obuf; + stream_reset (s); + + /* Length place holder. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV6_ROUTE_ADD); + stream_putc (s, api->type); + stream_putc (s, api->flags); + stream_putc (s, api->message); + + /* Put prefix information. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop, ifindex, distance and metric information. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + stream_putc (s, api->nexthop_num + api->ifindex_num); + + for (i = 0; i < api->nexthop_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IPV6); + stream_write (s, (u_char *)api->nexthop[i], 16); + } + for (i = 0; i < api->ifindex_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putl (s, api->ifindex[i]); + } + } + + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE)) + stream_putc (s, api->distance); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) + stream_putl (s, api->metric); + + /* Put length at the first point of the stream. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + return writen (zclient->sock, s->data, stream_get_endp (s)); +} + +int +zapi_ipv6_delete (struct zclient *zclient, struct prefix_ipv6 *p, + struct zapi_ipv6 *api) +{ + int i; + int psize; + struct stream *s; + + /* Reset stream. */ + s = zclient->obuf; + stream_reset (s); + + /* Length place holder. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV6_ROUTE_DELETE); + stream_putc (s, api->type); + stream_putc (s, api->flags); + stream_putc (s, api->message); + + /* Put prefix information. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop, ifindex, distance and metric information. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + stream_putc (s, api->nexthop_num + api->ifindex_num); + + for (i = 0; i < api->nexthop_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IPV6); + stream_write (s, (u_char *)api->nexthop[i], 16); + } + for (i = 0; i < api->ifindex_num; i++) + { + stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + stream_putl (s, api->ifindex[i]); + } + } + + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE)) + stream_putc (s, api->distance); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) + stream_putl (s, api->metric); + + /* Put length at the first point of the stream. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + return writen (zclient->sock, s->data, stream_get_endp (s)); +} + +#endif /* HAVE_IPV6 */ + +int +zebra_redistribute_send (int command, int sock, int type) +{ + int ret; + struct stream *s; + + s = stream_new (ZEBRA_MAX_PACKET_SIZ); + + /* Total length of the messages. */ + stream_putw (s, 4); + + stream_putc (s, command); + stream_putc (s, type); + + ret = writen (sock, s->data, 4); + + stream_free (s); + + return ret; +} + +/* Interface addition from zebra daemon. */ +struct interface * +zebra_interface_add_read (struct stream *s) +{ + struct interface *ifp; + u_char ifname_tmp[INTERFACE_NAMSIZ]; + + /* Read interface name. */ + stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); + + /* Lookup this by interface name. */ + ifp = if_lookup_by_name (ifname_tmp); + + /* If such interface does not exist, make new one. */ + if (! ifp) + { + ifp = if_create (); + strncpy (ifp->name, ifname_tmp, IFNAMSIZ); + } + + /* Read interface's index. */ + ifp->ifindex = stream_getl (s); + + /* Read interface's value. */ + ifp->flags = stream_getl (s); + ifp->metric = stream_getl (s); + ifp->mtu = stream_getl (s); + ifp->bandwidth = stream_getl (s); +#ifdef HAVE_SOCKADDR_DL + stream_get (&ifp->sdl, s, sizeof (ifp->sdl)); +#else + ifp->hw_addr_len = stream_getl (s); + if (ifp->hw_addr_len) + stream_get (ifp->hw_addr, s, ifp->hw_addr_len); +#endif /* HAVE_SOCKADDR_DL */ + + return ifp; +} + +/* Read interface up/down msg from zebra daemon. */ +struct interface * +zebra_interface_state_read (struct stream *s) +{ + struct interface *ifp; + u_char ifname_tmp[INTERFACE_NAMSIZ]; + + /* Read interface name. */ + stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); + + /* Lookup this by interface index. */ + ifp = if_lookup_by_name (ifname_tmp); + + /* If such interface does not exist, indicate an error */ + if (! ifp) + return NULL; + + /* Read interface's index. */ + ifp->ifindex = stream_getl (s); + + /* Read interface's value. */ + ifp->flags = stream_getl (s); + ifp->metric = stream_getl (s); + ifp->mtu = stream_getl (s); + ifp->bandwidth = stream_getl (s); + + return ifp; +} + +struct connected * +zebra_interface_address_add_read (struct stream *s) +{ + unsigned int ifindex; + struct interface *ifp; + struct connected *ifc; + struct prefix *p; + int family; + int plen; + + /* Get interface index. */ + ifindex = stream_getl (s); + + /* Lookup index. */ + ifp = if_lookup_by_index (ifindex); + if (ifp == NULL) + { + zlog_warn ("zebra_interface_address_add_read: Can't find interface by ifindex: %d ", ifindex); + return NULL; + } + + /* Allocate new connected address. */ + ifc = connected_new (); + ifc->ifp = ifp; + + /* Fetch flag. */ + ifc->flags = stream_getc (s); + + /* Fetch interface address. */ + p = prefix_new (); + family = p->family = stream_getc (s); + + plen = prefix_blen (p); + stream_get (&p->u.prefix, s, plen); + p->prefixlen = stream_getc (s); + ifc->address = p; + + /* Fetch destination address. */ + p = prefix_new (); + stream_get (&p->u.prefix, s, plen); + p->family = family; + + ifc->destination = p; + + p = ifc->address; + + /* Add connected address to the interface. */ + listnode_add (ifp->connected, ifc); + + return ifc; +} + +struct connected * +zebra_interface_address_delete_read (struct stream *s) +{ + unsigned int ifindex; + struct interface *ifp; + struct connected *ifc; + struct prefix p; + struct prefix d; + int family; + int len; + u_char flags; + + /* Get interface index. */ + ifindex = stream_getl (s); + + /* Lookup index. */ + ifp = if_lookup_by_index (ifindex); + if (ifp == NULL) + { + zlog_warn ("zebra_interface_address_delete_read: Can't find interface by ifindex: %d ", ifindex); + return NULL; + } + + /* Fetch flag. */ + flags = stream_getc (s); + + /* Fetch interface address. */ + family = p.family = stream_getc (s); + + len = prefix_blen (&p); + stream_get (&p.u.prefix, s, len); + p.prefixlen = stream_getc (s); + + /* Fetch destination address. */ + stream_get (&d.u.prefix, s, len); + d.family = family; + + ifc = connected_delete_by_prefix (ifp, &p); + + return ifc; +} + +/* Zebra client message read function. */ +int +zclient_read (struct thread *thread) +{ + int ret; + int nbytes; + int sock; + zebra_size_t length; + zebra_command_t command; + struct zclient *zclient; + + /* Get socket to zebra. */ + sock = THREAD_FD (thread); + zclient = THREAD_ARG (thread); + zclient->t_read = NULL; + + /* Clear input buffer. */ + stream_reset (zclient->ibuf); + + /* Read zebra header. */ + nbytes = stream_read (zclient->ibuf, sock, ZEBRA_HEADER_SIZE); + + /* zebra socket is closed. */ + if (nbytes == 0) + { + if (zclient_debug) + zlog_info ("zclient connection closed socket [%d].", sock); + zclient->fail++; + zclient_stop (zclient); + zclient_event (ZCLIENT_CONNECT, zclient); + return -1; + } + + /* zebra read error. */ + if (nbytes < 0 || nbytes != ZEBRA_HEADER_SIZE) + { + if (zclient_debug) + zlog_info ("Can't read all packet (length %d).", nbytes); + zclient->fail++; + zclient_stop (zclient); + zclient_event (ZCLIENT_CONNECT, zclient); + return -1; + } + + /* Fetch length and command. */ + length = stream_getw (zclient->ibuf); + command = stream_getc (zclient->ibuf); + + /* Length check. */ + if (length >= zclient->ibuf->size) + { + stream_free (zclient->ibuf); + zclient->ibuf = stream_new (length + 1); + } + length -= ZEBRA_HEADER_SIZE; + + /* Read rest of zebra packet. */ + nbytes = stream_read (zclient->ibuf, sock, length); + if (nbytes != length) + { + if (zclient_debug) + zlog_info ("zclient connection closed socket [%d].", sock); + zclient->fail++; + zclient_stop (zclient); + zclient_event (ZCLIENT_CONNECT, zclient); + return -1; + } + + switch (command) + { + case ZEBRA_INTERFACE_ADD: + if (zclient->interface_add) + ret = (*zclient->interface_add) (command, zclient, length); + break; + case ZEBRA_INTERFACE_DELETE: + if (zclient->interface_delete) + ret = (*zclient->interface_delete) (command, zclient, length); + break; + case ZEBRA_INTERFACE_ADDRESS_ADD: + if (zclient->interface_address_add) + ret = (*zclient->interface_address_add) (command, zclient, length); + break; + case ZEBRA_INTERFACE_ADDRESS_DELETE: + if (zclient->interface_address_delete) + ret = (*zclient->interface_address_delete) (command, zclient, length); + break; + case ZEBRA_INTERFACE_UP: + if (zclient->interface_up) + ret = (*zclient->interface_up) (command, zclient, length); + break; + case ZEBRA_INTERFACE_DOWN: + if (zclient->interface_down) + ret = (*zclient->interface_down) (command, zclient, length); + break; + case ZEBRA_IPV4_ROUTE_ADD: + if (zclient->ipv4_route_add) + ret = (*zclient->ipv4_route_add) (command, zclient, length); + break; + case ZEBRA_IPV4_ROUTE_DELETE: + if (zclient->ipv4_route_delete) + ret = (*zclient->ipv4_route_delete) (command, zclient, length); + break; + case ZEBRA_IPV6_ROUTE_ADD: + if (zclient->ipv6_route_add) + ret = (*zclient->ipv6_route_add) (command, zclient, length); + break; + case ZEBRA_IPV6_ROUTE_DELETE: + if (zclient->ipv6_route_delete) + ret = (*zclient->ipv6_route_delete) (command, zclient, length); + break; + default: + break; + } + + /* Register read thread. */ + zclient_event (ZCLIENT_READ, zclient); + + return 0; +} + +void +zclient_redistribute_set (struct zclient *zclient, int type) +{ + if (zclient->redist[type]) + return; + + zclient->redist[type] = 1; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type); +} + +void +zclient_redistribute_unset (struct zclient *zclient, int type) +{ + if (! zclient->redist[type]) + return; + + zclient->redist[type] = 0; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type); +} + +void +zclient_redistribute_default_set (struct zclient *zclient) +{ + if (zclient->default_information) + return; + + zclient->default_information = 1; + + if (zclient->sock > 0) + zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD); +} + +void +zclient_redistribute_default_unset (struct zclient *zclient) +{ + if (! zclient->default_information) + return; + + zclient->default_information = 0; + + if (zclient->sock > 0) + zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_DELETE); +} + +extern struct thread_master *master; + +static void +zclient_event (enum event event, struct zclient *zclient) +{ + switch (event) + { + case ZCLIENT_SCHEDULE: + if (! zclient->t_connect) + zclient->t_connect = + thread_add_event (master, zclient_connect, zclient, 0); + break; + case ZCLIENT_CONNECT: + if (zclient->fail >= 10) + return; + if (zclient_debug) + zlog_info ("zclient connect schedule interval is %d", + zclient->fail < 3 ? 10 : 60); + if (! zclient->t_connect) + zclient->t_connect = + thread_add_timer (master, zclient_connect, zclient, + zclient->fail < 3 ? 10 : 60); + break; + case ZCLIENT_READ: + zclient->t_read = + thread_add_read (master, zclient_read, zclient, zclient->sock); + break; + } +} diff --git a/lib/zclient.h b/lib/zclient.h new file mode 100644 index 0000000..66307c9 --- /dev/null +++ b/lib/zclient.h @@ -0,0 +1,164 @@ +/* Zebra's client header. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) + * any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_ZCLIENT_H +#define _ZEBRA_ZCLIENT_H + +/* For struct interface and struct connected. */ +#include "if.h" + +/* For input/output buffer to zebra. */ +#define ZEBRA_MAX_PACKET_SIZ 4096 + +/* Zebra header size. */ +#define ZEBRA_HEADER_SIZE 3 + +/* Structure for the zebra client. */ +struct zclient +{ + /* Socket to zebra daemon. */ + int sock; + + /* Flag of communication to zebra is enabled or not. Default is on. + This flag is disabled by `no router zebra' statement. */ + int enable; + + /* Connection failure count. */ + int fail; + + /* Input buffer for zebra message. */ + struct stream *ibuf; + + /* Output buffer for zebra message. */ + struct stream *obuf; + + /* Read and connect thread. */ + struct thread *t_read; + struct thread *t_connect; + + /* Redistribute information. */ + u_char redist_default; + u_char redist[ZEBRA_ROUTE_MAX]; + + /* Redistribute defauilt. */ + u_char default_information; + + /* Pointer to the callback functions. */ + int (*interface_add) (int, struct zclient *, zebra_size_t); + int (*interface_delete) (int, struct zclient *, zebra_size_t); + int (*interface_up) (int, struct zclient *, zebra_size_t); + int (*interface_down) (int, struct zclient *, zebra_size_t); + int (*interface_address_add) (int, struct zclient *, zebra_size_t); + int (*interface_address_delete) (int, struct zclient *, zebra_size_t); + int (*ipv4_route_add) (int, struct zclient *, zebra_size_t); + int (*ipv4_route_delete) (int, struct zclient *, zebra_size_t); + int (*ipv6_route_add) (int, struct zclient *, zebra_size_t); + int (*ipv6_route_delete) (int, struct zclient *, zebra_size_t); +}; + +/* Zebra API message flag. */ +#define ZAPI_MESSAGE_NEXTHOP 0x01 +#define ZAPI_MESSAGE_IFINDEX 0x02 +#define ZAPI_MESSAGE_DISTANCE 0x04 +#define ZAPI_MESSAGE_METRIC 0x08 + +/* Zebra IPv4 route message API. */ +struct zapi_ipv4 +{ + u_char type; + + u_char flags; + + u_char message; + + u_char nexthop_num; + struct in_addr **nexthop; + + u_char ifindex_num; + unsigned int *ifindex; + + u_char distance; + + u_int32_t metric; +}; + +int +zapi_ipv4_add (struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *); + +int +zapi_ipv4_delete (struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *); + +/* Prototypes of zebra client service functions. */ +struct zclient *zclient_new (void); +void zclient_free (struct zclient *); +void zclient_init (struct zclient *, int); +int zclient_start (struct zclient *); +void zclient_stop (struct zclient *); +void zclient_reset (struct zclient *); +int zclient_socket (); +int zclient_socket_un (char *); + +void zclient_redistribute_set (struct zclient *, int); +void zclient_redistribute_unset (struct zclient *, int); + +void zclient_redistribute_default_set (struct zclient *); +void zclient_redistribute_default_unset (struct zclient *); + +/* struct zebra *zebra_new (); */ +int zebra_redistribute_send (int, int, int); + +struct interface *zebra_interface_add_read (struct stream *); +struct interface *zebra_interface_state_read (struct stream *s); +struct connected *zebra_interface_address_add_read (struct stream *); +struct connected *zebra_interface_address_delete_read (struct stream *); + +#ifdef HAVE_IPV6 +/* IPv6 prefix add and delete function prototype. */ + +struct zapi_ipv6 +{ + u_char type; + + u_char flags; + + u_char message; + + u_char nexthop_num; + struct in6_addr **nexthop; + + u_char ifindex_num; + unsigned int *ifindex; + + u_char distance; + + u_int32_t metric; +}; + +int +zapi_ipv6_add (struct zclient *zclient, struct prefix_ipv6 *p, + struct zapi_ipv6 *api); +int +zapi_ipv6_delete (struct zclient *zclient, struct prefix_ipv6 *p, + struct zapi_ipv6 *api); + +#endif /* HAVE_IPV6 */ + +#endif /* _ZEBRA_ZCLIENT_H */ diff --git a/lib/zebra.h b/lib/zebra.h new file mode 100644 index 0000000..a2ea545 --- /dev/null +++ b/lib/zebra.h @@ -0,0 +1,365 @@ +/* Zebra common header. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _ZEBRA_H +#define _ZEBRA_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#ifdef SUNOS_5 +#define _XPG4_2 +#define __EXTENSIONS__ +typedef unsigned int u_int32_t; +typedef unsigned short u_int16_t; +typedef unsigned short u_int8_t; +#endif /* SUNOS_5 */ + +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif /* HAVE_SOCKLEN_T */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_STROPTS_H +#include +#endif /* HAVE_STROPTS_H */ +#include +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* HAVE_SYS_SELECT_H */ +#include +#include +#include +#include +#ifdef HAVE_SYS_SYSCTL_H +#include +#endif /* HAVE_SYS_SYSCTL_H */ +#include +#ifdef HAVE_SYS_CONF_H +#include +#endif /* HAVE_SYS_CONF_H */ +#ifdef HAVE_SYS_KSYM_H +#include +#endif /* HAVE_SYS_KSYM_H */ +#include +#include +#include +#include +#ifdef HAVE_RUSAGE +#include +#endif /* HAVE_RUSAGE */ + +/* machine dependent includes */ +#ifdef SUNOS_5 +#include +#include +#endif /* SUNOS_5 */ + +/* machine dependent includes */ +#ifdef HAVE_LINUX_VERSION_H +#include +#endif /* HAVE_LINUX_VERSION_H */ + +#ifdef HAVE_ASM_TYPES_H +#include +#endif /* HAVE_ASM_TYPES_H */ + +/* misc include group */ +#include +#include + +/* network include group */ + +#include + +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif /* HAVE_SYS_SOCKIO_H */ + +#ifdef HAVE_NETINET_IN_H +#include +#endif /* HAVE_NETINET_IN_H */ +#include +#include +#include + +#ifdef HAVE_NET_NETOPT_H +#include +#endif /* HAVE_NET_NETOPT_H */ + +#include + +#ifdef HAVE_NET_IF_DL_H +#include +#endif /* HAVE_NET_IF_DL_H */ + +#ifdef HAVE_NET_IF_VAR_H +#include +#endif /* HAVE_NET_IF_VAR_H */ + +#include + +#ifdef HAVE_NETLINK +#include +#include +#else +#define RT_TABLE_MAIN 0 +#endif /* HAVE_NETLINK */ + +#ifdef HAVE_NETDB_H +#include +#endif /* HAVE_NETDB_H */ + +#include +#include + +#ifdef HAVE_INET_ND_H +#include +#endif /* HAVE_INET_ND_H */ + +#ifdef HAVE_NETINET_IN_VAR_H +#include +#endif /* HAVE_NETINET_IN_VAR_H */ + +#ifdef HAVE_NETINET_IN6_VAR_H +#include +#endif /* HAVE_NETINET_IN6_VAR_H */ + +#ifdef HAVE_NETINET6_IN_H +#include +#endif /* HAVE_NETINET6_IN_H */ + + +#ifdef HAVE_NETINET6_IP6_H +#include +#endif /* HAVE_NETINET6_IP6_H */ + +#ifdef HAVE_NETINET_ICMP6_H +#include +#endif /* HAVE_NETINET_ICMP6_H */ + +#ifdef HAVE_NETINET6_ND6_H +#include +#endif /* HAVE_NETINET6_ND6_H */ + +#ifdef HAVE_LIBUTIL_H +#include +#endif /* HAVE_LIBUTIL_H */ + +#ifdef BSDI_NRL + +#ifdef HAVE_NETINET6_IN6_H +#include +#endif /* HAVE_NETINET6_IN6_H */ + +#ifdef NRL +#include +#endif /* NRL */ + +#define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL + +/* BSD/OS 4.0 has lost belows defines, it should appear at + /usr/include/sys/socket.h. */ +#define CMSG_ALIGN(n) (((n) + 3) & ~3) +#define CMSG_SPACE(l) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(l)) +#define CMSG_LEN(l) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (l)) + +#endif /* BSDI_NRL */ + +/* The definition of struct in_pktinfo is missing in old version of + GLIBC 2.1 (Redhat 6.1). */ +#if defined (GNU_LINUX) && ! defined (HAVE_INPKTINFO) +struct in_pktinfo +{ + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; +#endif + +/* OpenBSD release month check. */ +#ifdef __OpenBSD__ +#if OpenBSD < 200311 +#define OpenBSD_IP_LEN +#endif /* OpenBSD */ +#endif /* __OpenBSD__ */ + +/* For old definition. */ +#ifndef IN6_ARE_ADDR_EQUAL +#define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL +#endif /* IN6_ARE_ADDR_EQUAL */ + +/* Zebra message types. */ +#define ZEBRA_INTERFACE_ADD 1 +#define ZEBRA_INTERFACE_DELETE 2 +#define ZEBRA_INTERFACE_ADDRESS_ADD 3 +#define ZEBRA_INTERFACE_ADDRESS_DELETE 4 +#define ZEBRA_INTERFACE_UP 5 +#define ZEBRA_INTERFACE_DOWN 6 +#define ZEBRA_IPV4_ROUTE_ADD 7 +#define ZEBRA_IPV4_ROUTE_DELETE 8 +#define ZEBRA_IPV6_ROUTE_ADD 9 +#define ZEBRA_IPV6_ROUTE_DELETE 10 +#define ZEBRA_REDISTRIBUTE_ADD 11 +#define ZEBRA_REDISTRIBUTE_DELETE 12 +#define ZEBRA_REDISTRIBUTE_DEFAULT_ADD 13 +#define ZEBRA_REDISTRIBUTE_DEFAULT_DELETE 14 +#define ZEBRA_IPV4_NEXTHOP_LOOKUP 15 +#define ZEBRA_IPV6_NEXTHOP_LOOKUP 16 +#define ZEBRA_IPV4_IMPORT_LOOKUP 17 +#define ZEBRA_IPV6_IMPORT_LOOKUP 18 +#define ZEBRA_MESSAGE_MAX 19 + +/* Zebra route's types. */ +#define ZEBRA_ROUTE_SYSTEM 0 +#define ZEBRA_ROUTE_KERNEL 1 +#define ZEBRA_ROUTE_CONNECT 2 +#define ZEBRA_ROUTE_STATIC 3 +#define ZEBRA_ROUTE_RIP 4 +#define ZEBRA_ROUTE_RIPNG 5 +#define ZEBRA_ROUTE_OSPF 6 +#define ZEBRA_ROUTE_OSPF6 7 +#define ZEBRA_ROUTE_BGP 8 +#define ZEBRA_ROUTE_MAX 9 + +/* Zebra's family types. */ +#define ZEBRA_FAMILY_IPV4 1 +#define ZEBRA_FAMILY_IPV6 2 +#define ZEBRA_FAMILY_MAX 3 + +/* Error codes of zebra. */ +#define ZEBRA_ERR_RTEXIST -1 +#define ZEBRA_ERR_RTUNREACH -2 +#define ZEBRA_ERR_EPERM -3 +#define ZEBRA_ERR_RTNOEXIST -4 + +/* Zebra message flags */ +#define ZEBRA_FLAG_INTERNAL 0x01 +#define ZEBRA_FLAG_SELFROUTE 0x02 +#define ZEBRA_FLAG_BLACKHOLE 0x04 +#define ZEBRA_FLAG_IBGP 0x08 +#define ZEBRA_FLAG_SELECTED 0x10 +#define ZEBRA_FLAG_CHANGED 0x20 +#define ZEBRA_FLAG_STATIC 0x40 + +/* Zebra nexthop flags. */ +#define ZEBRA_NEXTHOP_IFINDEX 1 +#define ZEBRA_NEXTHOP_IFNAME 2 +#define ZEBRA_NEXTHOP_IPV4 3 +#define ZEBRA_NEXTHOP_IPV4_IFINDEX 4 +#define ZEBRA_NEXTHOP_IPV4_IFNAME 5 +#define ZEBRA_NEXTHOP_IPV6 6 +#define ZEBRA_NEXTHOP_IPV6_IFINDEX 7 +#define ZEBRA_NEXTHOP_IPV6_IFNAME 8 +#define ZEBRA_NEXTHOP_BLACKHOLE 9 + +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */ +#endif + +/* Address family numbers from RFC1700. */ +#define AFI_IP 1 +#define AFI_IP6 2 +#define AFI_MAX 3 + +/* Subsequent Address Family Identifier. */ +#define SAFI_UNICAST 1 +#define SAFI_MULTICAST 2 +#define SAFI_UNICAST_MULTICAST 3 +#define SAFI_MPLS_VPN 4 +#define SAFI_MAX 5 + +/* Filter direction. */ +#define FILTER_IN 0 +#define FILTER_OUT 1 +#define FILTER_MAX 2 + +/* Default Administrative Distance of each protocol. */ +#define ZEBRA_KERNEL_DISTANCE_DEFAULT 0 +#define ZEBRA_CONNECT_DISTANCE_DEFAULT 0 +#define ZEBRA_STATIC_DISTANCE_DEFAULT 1 +#define ZEBRA_RIP_DISTANCE_DEFAULT 120 +#define ZEBRA_RIPNG_DISTANCE_DEFAULT 120 +#define ZEBRA_OSPF_DISTANCE_DEFAULT 110 +#define ZEBRA_OSPF6_DISTANCE_DEFAULT 110 +#define ZEBRA_IBGP_DISTANCE_DEFAULT 200 +#define ZEBRA_EBGP_DISTANCE_DEFAULT 20 + +/* Flag manipulation macros. */ +#define CHECK_FLAG(V,F) ((V) & (F)) +#define SET_FLAG(V,F) (V) = (V) | (F) +#define UNSET_FLAG(V,F) (V) = (V) & ~(F) + +/* AFI and SAFI type. */ +typedef u_int16_t afi_t; +typedef u_char safi_t; + +/* Zebra types. */ +typedef u_int16_t zebra_size_t; +typedef u_int8_t zebra_command_t; + +/* FIFO -- first in first out structure and macros. */ +struct fifo +{ + struct fifo *next; + struct fifo *prev; +}; + +#define FIFO_INIT(F) \ + do { \ + struct fifo *Xfifo = (struct fifo *)(F); \ + Xfifo->next = Xfifo->prev = Xfifo; \ + } while (0) + +#define FIFO_ADD(F,N) \ + do { \ + struct fifo *Xfifo = (struct fifo *)(F); \ + struct fifo *Xnode = (struct fifo *)(N); \ + Xnode->next = Xfifo; \ + Xnode->prev = Xfifo->prev; \ + Xfifo->prev = Xfifo->prev->next = Xnode; \ + } while (0) + +#define FIFO_DEL(N) \ + do { \ + struct fifo *Xnode = (struct fifo *)(N); \ + Xnode->prev->next = Xnode->next; \ + Xnode->next->prev = Xnode->prev; \ + } while (0) + +#define FIFO_HEAD(F) \ + ((((struct fifo *)(F))->next == (struct fifo *)(F)) \ + ? NULL : (F)->next) + +#define FIFO_EMPTY(F) \ + (((struct fifo *)(F))->next == (struct fifo *)(F)) + +#define FIFO_TOP(F) \ + (FIFO_EMPTY(F) ? NULL : ((struct fifo *)(F))->next) + +#endif /* _ZEBRA_H */ diff --git a/missing b/missing new file mode 100755 index 0000000..dd58370 --- /dev/null +++ b/missing @@ -0,0 +1,336 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright 1996, 1997, 1999, 2000 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing 0.4 - GNU automake" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. + You can get \`$1Help2man' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then + # We have makeinfo, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + tar) + shift + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + fi + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar ${1+"$@"} && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar ${1+"$@"} && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" ${1+"$@"} && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" ${1+"$@"} && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..f565332 --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,101 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs,v 1.3 2002/03/08 12:44:47 akim Exp $ + +errstatus=0 +dirmode="" + +usage="\ +Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..." + +# process command line arguments +while test $# -gt 0 ; do + case "${1}" in + -h | --help | --h* ) # -h for help + echo "${usage}" 1>&2; exit 0 ;; + -m ) # -m PERM arg + shift + test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; } + dirmode="${1}" + shift ;; + -- ) shift; break ;; # stop option processing + -* ) echo "${usage}" 1>&2; exit 1 ;; # unknown option + * ) break ;; # first non-opt arg + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in +0) exit 0 ;; +esac + +case $dirmode in +'') + if mkdir -p -- . 2>/dev/null; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + fi ;; +*) + if mkdir -m "$dirmode" -p -- . 2>/dev/null; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + fi ;; +esac + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + + lasterr="" + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 3 +# End: +# mkinstalldirs ends here diff --git a/ospf6d/ChangeLog b/ospf6d/ChangeLog new file mode 100644 index 0000000..7f489b5 --- /dev/null +++ b/ospf6d/ChangeLog @@ -0,0 +1,969 @@ +2005-06-25 Harald Welte + + * ospf6_abr.c, ospf6_area.[ch]: Add area filter-list (in|out) + support and area import and export lists support + +2005-06-24 Yasuhiro Ohara + + * ospf6_message.c: Changed to be insensitive to changes of + neighbors' IP source address in the OSPF packets. It was + sometimes problematic in actual operation (needed some operational + cost: restarting all-neighbor routers when I/F NIC was changed). + Due to this change, a previously safe case, attaching multiple + interface to the same link will now be dengerous and will not work. + Remedy to that should be applied later. + +2005-06-07 Yasuhiro Ohara + + * ospf6_interface.c, ospf6_neighbor.c: fix the way + inactivity_timer is called. Because inactivity_timer() deletes + the neighbor from the neighbor_list, it cannot be called + by thread_execute() from inner side of the neighbor_list for-loop. + +2004-12-08 Yasuhiro Ohara + + * ospf6_test.c: code for simulation test. + +2004-10-06 Yasuhiro Ohara + + * ospf6_snmp.c: add partial support for SNMP + (i.e. ospfv3AreaLsdbTable). + * OSPFv3-MIB.txt: Net-SNMP translate Unsigned32 range + (0..'FFFFFFFF'h) incorrectly to (0..-1). Those parts for + Unsigned32 range are changed to (0..4294967295). + Also, doubtful 'not-accessible's are changed to read-only. + +2004-10-06 Yasuhiro Ohara + + * ospf6_snmp.[ch], OSPFV3-MIB.txt: start supporting SNMP. + it follows draft-ietf-ospf-ospfv3-mib-08.txt, but change + OSPFv3 tree to {experimental 102} based on + http://www.iana.org/assignments/smi-numbers: + Prefix: iso.org.dod.internet.experimental (1.3.6.1.3.) + 102 OSPFv3 OSPF for IPv6 [Joyal] + +2004-09-25 Hasso Tepper + + * ospf6_asbr.c, ospf6_lsa.c, ospf6_proto.c, ospf6_proto.h: Fix + compiler warnings. + +2004-09-13 Yasuhiro Ohara + + * ospf6_intra.c, ospf6_route.[ch]: try to fix assertion failure + in brouter's route_remove + * ospf6d.h: version 0.9.7o + +2004-09-12 Yasuhiro Ohara + + * ospf6_route.c: route_count_assert bug fix + * ospf6d.h: version 0.9.7n + +2004-09-03 Yasuhiro Ohara + + * ospf6_area.c, ospf6_route.c, ospf6_top.c, ospf6d.c: + "show intra-route" function and "show SPF result" function is + changed. + * ospf6_neighbor.c: Changed to update stub intra-prefix origination + when it is not DR. + * ospf6_route.h: resolv conflict between best flag and + active-summary flag. + * ospf6d.h: version 0.9.7m + +2004-09-02 Yasuhiro Ohara + + * ospf6_asbr.c: E-bit check in examining AS-External-LSA + * ospf6_abr.c: E-bit set in receiving Inter-Area-Router-LSA + +2004-09-02 Yasuhiro Ohara + + * *.[ch]: Logging LSAs of particular type is added. + lsa_handler is now using vector in order to adjust + existing LSA modules. + * ospf6d.h: version 0.9.7l + +2004-08-26 Hasso Tepper + + * ospf6_interface.c, ospf6_top.c, ospf6d.c: for vtysh. + +2004-08-19 Yasuhiro Ohara + + * ospf6_asbr.c: Bug in ASBR check fixed. + * ospf6d.h: version 0.9.7k + +2004-08-19 Yasuhiro Ohara + + * ospf6_asbr.c: Bug in AS-External Origination fixed. + * ospf6d.h: version 0.9.7j + +2004-08-15 Yasuhiro Ohara + + * *.c: Area support almost done. (almost ! ;p) + * ospf6d.h: version 0.9.7i + +2004-08-15 Yasuhiro Ohara + + * ospf6_message.c: Bug cause BadLSReq is fixed. + * ospf6_abr.c: Border Router check. + * ospf6d.h: version 0.9.7h + +2004-08-14 Yasuhiro Ohara + + * ospf6_area.[ch], ospf6_abr.[ch]: area range, + border-routers, Inter-Area-Router-LSA origination + * ospf6d.h: version 0.9.7g + +2004-08-12 Yasuhiro Ohara + + * *.[c,h]: LSA refreshing is changed and cleaned up. + * ospf6d.h: version 0.9.7f + +2004-08-01 Yasuhiro Ohara + + * ospf6_abr.[ch]: add files for abr function. + * *.c: VTY_NEWLINE -> VNL + * ospf6d.h: version 0.9.7e + show database functions are rewritten. + +2004-07-06 Yasuhiro Ohara + + * ospf6_message.c, ospf6_interface.c: add a command to configure + ospf6 ifmtu on a interface. + * ospf6d.h: version 0.9.7d + +2004-05-17 Yasuhiro Ohara + + * ospf6_flood.[ch], ospf6_lsa.[ch], ospf6_lsdb.h, ospf6_message.c + ospf6_neighbor.c: Fix crash bug and change the way to count + how many neighbors include paticular LSA on its retrans-list. + * ospf6d.h: version 0.9.7c + +2004-05-03 Yasuhiro Ohara + + * ospf6_message.[ch], ospf6_interface.c: adjust send/recv buffer + size to interface MTUs. + * ospf6d.h: version 0.9.7b + +2003-08-18 Yasuhiro Ohara + + * *.[ch]: rewrite all source code from scratch + * ospf6d.h: version 0.9.7 + +2003-08-11 Taisuke Sasaki + + * ospf6_ism.c: DR Election bug fix. + +2003-04-25 Yasuhiro Ohara + + * ospf6_asbr.c: AS-External LSA refresh was based on the + prefix of the obsolete LSA. It was wrong so fixed. + * version: 0.9.6p + +2002-11-09 Vincent Jardin + + * ospf6_interface.c: update link-local address on interface creation. + +2002-11-09 Yasuhiro Ohara + + * ospf6_asbr.c: apply MinLSInterval to AS-External-LSA origination. + * ospf6_lsa.c: change not to issue flooding caused by expire event + when the received LSA is (already) MaxAge. + * ospf6_spf.c: fix a bug which is that ospf6d calculates + wrong nexthop when failed to find Link-LSA for the neighbor. + * ospf6_damp.c ospf6_dbex.c ospf6_neighbor.c ospf6_spf.c: + some clean up + * version: 0.9.6o + +2002-10-04 Yasuhiro Ohara + + * ospf6_asbr.c: bug of failing ASE lsa refresh fixed. + * version: 0.9.6n + +2002-10-01 Yasuhiro Ohara + + * ospf6_asbr.c: AS-External-LSA origination function + is re-written. + * ospf6_damp.[ch]: New feature that damps flaps is added. + * version: 0.9.6m + +2002-07-14 Yasuhiro Ohara + + * ospf6_spf.c: unwanted assert() in ospf6_spf_nexthop_calculation() + is deleted. + * version: 0.9.6l + +2002-07-14 Yasuhiro Ohara + + * ospf6_dbex.c: bug that ospf6d fails to refresh self-originated + LSA if he have not the LSA before has been fixed. + * ospf6_asbr.c: bug of failing removing ASE LSA when remove + message arrived from zebra has been fixed. + * version: 0.9.6k + +2002-07-13 Yasuhiro Ohara + + * ospf6_zebra.c: bug reported [zebra 14642] fixed. + The bug was related to the synchronization between zebra + and ospf6d. Now synchronization will be correctly done. + * version: 0.9.6j + +2002-07-07 Yasuhiro Ohara + + * ospf6_lsdb.c: bug fixed in ospf6_lsdb_type_router (). + * ospf6_dbex.c: because of retrans list structure changed + due to LSDB change, removal of old instance from retrans-list + is not necessary anymore. this caused crash but now fixed. + * version: 0.9.6i + +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2002-07-07 Yasuhiro Ohara + + * ospf6_lsdb.c: entirely rewritten. now ospf6d uses + radix tree by using lib/table.[ch] for LSDB lookup. + * ospf6_abr.c, ospf6_asbr.c, ospf6_intra.c: hook changed + due to rewriting of lsdb module. + * ospf6_neighbor.c: lack of check existence and find correct + instance of the LSA which is going to be removed from neighbor's + retransmission was filled. + * version: 0.9.6h + +2002-07-07 Yasuhiro Ohara + + * ospf6_intra.c: bug fix for Intra-route deletion. + * ospf6_route.c: bug fix for path comparison. + * version: 0.9.6g + +2002-06-28 Yasuhiro Ohara + + * ospf6_route.c: some logs trying to find the situation + when assert occur are added. route duration statistics + added. + * ospf6_zebra.c: trying to fix the problem reported by + [zebra 14318] but not yet sure. + * version: 0.9.6f + +2002-06-25 Yasuhiro Ohara + + * ospf6_intra.c: new file for management of intra-prefix LSA. + * ospf6_abr.c: inter area route calculation code added. + * version: 0.9.6e + +2002-06-22 Yasuhiro Ohara + + * ospf6_asbr.c: All AS-External route was removed when + one of the ASBR path was gone, but the route from other ASBR + path should stay remained. this bug is fixed. + * version: 0.9.6d + +2002-06-22 Yasuhiro Ohara + + * ospf6_route.c: route table calculation bug fixed. [zebra 14105] + * ospf6_spf.c, ospf6_route.c, etc.: log message cleaned up. + * version: 0.9.6c + +2002-04-27 Yasuhiro Ohara + + * ospf6_route.c: [zebra 13514] bug fix. + thanks to Harald Koch. + * version: 0.9.6b + +2002-04-22 Yasuhiro Ohara + + * ospf6_dump.c: fix bug of log function + * ospf6_area.c: fix bug of intra route deletion + * version: 0.9.6a + +2002-04-20 Yasuhiro Ohara + + * merged with "current" version. + * version: 0.9.6 + +2001-03-11 Yasuhiro Ohara + + * ospf6_lsdb.c ospf6_spf.c: log message changed for debug. + +2001-02-20 Yasuhiro Ohara + + * version: 0.9.5i + + * ospf6_asbr.c: Added code that finds alternative + AS-External route when remove AS-External route. + This is temporary fix ... + + * ospf6_redistribute.c: remove redistributed routes + immediately when 'no redistribute ...' + +2001-02-20 Yasuhiro Ohara + + * version: 0.9.5h + + * ospf6_spf.c, ospf6_lsa.c: Change to originate Link-LSA on + point-to-point links. + + * ospf6_message.c: Bug of log messages of self-originated + Hello packet fixed. + +2001-02-09 Yasuhiro Ohara + + * version: 0.9.5g + * ospf6_asbr.c: fix for the bug that AS-External route + is not get removed. + +2001-02-09 Yasuhiro Ohara + + * ospf6_lsdb.c: crash bug while receiving wrong LSA scope bit + has been temporarily fixed + +2001-12-20 Yasuhiro Ohara + + * ospf6_asbr.[ch]: The byte order bug in encoding/decoding + the bits/metric field in AS-External-LSA fixed. + Fixed to update E-bit in Router-LSA of itself. + Reported by Taisuke Sasaki ([zebra 11548]). + + * README: updated. + + * version: 0.9.5f + +2001-11-21 Yasuhiro Ohara + + * ospf6_prefix.c: Intra-prefix-LSA bug fixed. + * ospf6_abr.[ch]: added (only just placeholder yet) + +2001-11-20 Yasuhiro Ohara + + * ospf6_route.c: fix to overwrite a prefix when another + addition to the prefix is given. freeze function changed + not to remove routes by default. + + * version: 0.9.5e + +2001-11-19 Yasuhiro Ohara + + * version: 0.9.5d + + * ospf6_lsa.c ospf6_spf.c: SPF Calculations are now + scheduled by hook. + + * ospf6_route.c: ospf6_route_add bug fix, + ospf6_route_remove_all corrected. + +2001-11-15 Yasuhiro Ohara + + * ospf6_hook.[ch]: added. + * Almost half of the code has been rewritten. + especially, ospf6_route.[ch]. Hook call has been injected + much. + * ospf6_asbr.[ch]: added. + +2001-10-17 Yasuhiro Ohara + + * ospf6_dbex.c: ospf6d was wrong to omit reoriginating + of LSA when the self-originated LSA was received from others. + fixed. + * ospf6d.h: version: 0.9.5c + +2001-10-16 Yasuhiro Ohara + + * ospf6_lsa.c: 'force-prefix' was not executed. fixed. + * ospf6d.h: version: 0.9.5b + +2001-10-13 Yasuhiro Ohara + + * ospf6_interface.c: 'passive-interface' is now moved to + 'ipv6 ospf6 passive' in INTERFACE NODE. 'prefix-list' which + specifies the filter prefix for connected address prefix also + moved to INTERFACE NODE as 'ipv6 ospf6 advertise prefix-list WORD'. + The old obsoleted commands are still acceptable though. New command + 'ipv6 ospf6 advertise force-prefix' added, which which tells ospf6d + to advertise rather prefix than stub local-address even on loopback + or pointopoint interfaces. + + * ospf6_dump.c: 'ospf6 debug hello' -> 'ospf6 debug message hello'. + same for other message type. The older is still acceptable. + + * ospf6_lsa.c: Changed AS-External generation to new one which uses + LSA hooks. Delete old garbage. + +2001-10-02 Yasuhiro Ohara + + * ospf6d.c: turn off and turn on sequence with + 'no interface' 'interface' cmds was not work. fixed. + + * ospf6_lsa.c: generating Intra-Area-Prefix-LSA for stub + did not care duplicate prefixes. fixed. + +2001-09-07 Yasuhiro Ohara + + * ospf6_message.c: There was a bug that prevent LSDB + to syncronize. It was a DbDesc packet bug that Slave + sends two different DbDesc packet on the same sequence + number. This cause many LSAs are dropped when Exchanging + LSDB, because the latter DbDesc packet that have the same + sequence number will be ignored as duplicate packet. + This seems to be exist at least before 0.9.4 version. + Now this is the most stable candidate. + + * ospf6d.h: version 0.9.5a + +2001-09-06 Yasuhiro Ohara + + * ospf6_zebra.c ospf6_spf.c ospf6_lsa.c : + delete nexthop check to certify the nexthop is Link-local address. + Suppress Link-LSA origination on links other than Broadcast. + SPF's nexthop calculation first checks linklocal address + in Link-LSA, then checks source address of neighbor's packets. + + * ospf6_interface.c ospf6_ism.c ospf6_lsa.c ospf6_nsm.c: + intra-area-prefix-lsa origination func moved to new one. + + * ospf6_interface.h ospf6d.[ch] ospf6_lsa.c: + interface_area_cmd now changed to have 'passive' + and 'prefix-list' option. + + * ospf6_prefix.c: + clean up. + +2001-09-04 Yasuhiro Ohara + + * ospf6_dbex.c ospf6_interface.c ospf6_ism.c ospf6_lsa.[ch]: + clean up and new LSA origination functions added. + + * ospf6_route.c ospf6_lsdb.c: make vty function more + clean/understandable. + + * ospf6d.h: version 0.9.5 + +2001-08-24 Kunihiro Ishiguro + + * ospf6_lsdb.c: Use IS_LSA_MAXAGE macro instead of + ospf6_lsa_is_maxage. + + * ospf6_lsa.h (IS_LSA_MAXAGE): Add new macro to check MaxAge. + +2001-08-21 Yasuhiro Ohara + + * ospf6_lsdb.c: if There's no previous prefix + ospf6d was wrongly not calculate the prefix. + this reported by (v6 16029) is fixed. + + * ospf6_neighbor.c: Instance of LSA Summary included + in DbDesc packet was wrongly freed. The bug cause + malformed DbDesc, ExChange <-> ExStart flapping, + and then crash. + + * ospf6d.h: version 0.9.4 + +2001-08-21 Yasuhiro Ohara + + * ospf6_route.[ch]: Showing format is changed. + 'show ipv6 route ospf6' -> 'show ipv6 ospf6 route' + 'show ipv6 route ospf6 external' -> + 'show ipv6 ospf6 route redistribute' + + * ospf6_lsdb.c ospf6_lsa.c ospf6_neighbor.c ospf6_interface.c: + memory leak in LS list fixed. + + * all: clean up + + * ospf6d.h: version 0.9.3 + +2001-08-20 Kunihiro Ishiguro + + * ospf6d.c (ospf6_timeval_sub_equal): Remove function. + + * ospf6_spf.c (ospf6_timeval_cmp): Rewrite ospf6_timeval_cmp(). + (ospf6_timeval_add_equal): Function moved from ospf6d.c + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-09 Yasuhiro Ohara + + * ospf6_lsdb.c ospf6_neighbor.c: + LSDB function/structure and LS list function has been rewritten. + memory leak has been decreased. + + * ospf6_lsa.[ch] ospf6_dbex.c: garbage code has been deleted. + + * ospf6d.h: version 0.9.2 + +2001-08-07 Yasuhiro Ohara + + * ospf6_dbex.c ospf6_lsdb.c: + Retransmition list had a critical bug that breaks LSDB + synchronization. When new LSA be added to retrans-list, + old must be removed, but it was not. So new LSA dropped, + and LSA Acknowledgement did not work. The bug was fixed. + + * ospf6d.h: version 0.9.1 + +2001-06-20 Yasuhiro Ohara + + * ospf6_spf.c: crash bug fix in temporary treat code for + Router-LSA whose LS-ID != 0 + + * ospf6_dbex.c: RFC2328 13.(4) was wrongly coded. + (4) Else if the LSA's LS age is equal to MaxAge, and there is + currently *NO* instance of the LSA in the router's link state + ... + + * ospf6_lsa.c: RFC2328 13.1 checksum tie breaker + had been neglected, and has just added now. + + * ospf6d.h: version 0.9.0 + ospf6d expected to work with hitachi gr2000 from these fixes. + +2001-06-12 Yasuhiro Ohara + + * ospf6_lsa.c: Fix bug in creating Intra-Area-Prefix-LSA. + DR was mis-include others prefixes advertised by their Link-LSA. + + * ospf6_route.c: Fix bug in calculating intra area routes. + Not all prefixes in Intra-Area-Prefix-LSA was calculated. + + * ospf6_spf.c: + Changed to quit when a error occured in calculating SPF tree. + Very messy hack for the bug reported by [zebra 8807]. This + is not tested yet. + Changed to quit SPF calculation when a nexthop calculation + errors. + + * ospf6_zebra.c: + Support for interface address deletion. + + * ospf6d.h: + version: 0.8.y + +2001-04-18 Yasuhiro Ohara + + * ospf6d.h + Due to previous change (DR Election algorithm changed), + backward compatibility will be lost from this version. + version: 0.8.x + +2001-04-18 Yasuhiro Ohara + + * ospf6_message.c ospf6_ism.c: + Bug of router_id comparison + +2001-04-17 Yasuhiro Ohara + + * ospf6_dbex.c: ospf6_dbex_is_maxage_to_be_dropped() had + some bug causing Loading state lasts long. + version: 0.8.v + +2001-04-08 Yasuhiro Ohara + + * ospf6_route.c: BUG in AS-External route calculation fixed. + It was using OLD LSDB... + Version: 0.8.u- + +2001-04-08 Yasuhiro Ohara + + * ospf6_area.c, ospf6_dbex.c, ospf6_interface.c, + ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h, ospf6_message.c, + ospf6_neighbor.c, ospf6_neighbor.h, ospf6_nsm.c, + ospf6_redistribute.c, ospf6_route.c, ospf6_spf.c: + Delete old LSDB function. + + * ospf6d.h: + Version: 0.8.u + +2001-04-05 Yasuhiro Ohara + + * ospf6_area.c, ospf6_area.h, ospf6_dbex.c, ospf6_interface.c, + ospf6_interface.h, ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h, + ospf6_message.c, ospf6_nsm.c, ospf6_redistribute.c, ospf6_route.c, + ospf6_spf.c, ospf6_top.c, ospf6_top.h, ospf6d.h: + Changed to use New LSDB. + Version: 0.8.t + +2001-04-02 Yasuhiro Ohara + + * ospf6_lsa.c: + Interface stub check in Intra-Area-Prefix-LSA origination + was wrong. - fixed. + + * ospf6_area.h, ospf6_dbex.c, ospf6_interface.c, + ospf6_interface.h, ospf6_lsa.c, ospf6_lsa.h, ospf6_lsdb.c, + ospf6_message.c, ospf6_neighbor.c, ospf6_nsm.c, + ospf6_redistribute.c, ospf6_top.c, ospf6_top.h, ospf6d.c: + New LSDB functions, but not changed to be used. + + * ospf6d.h: + Version: 0.8.s + +2001-03-28 Yasuhiro Ohara + + * ospf6_area.c ospf6_area.h ospf6_dbex.c ospf6_dump.c + ospf6_interface.c ospf6_interface.h ospf6_lsa.c + ospf6_message.c ospf6_redistribute.c ospf6_spf.c ospf6_top.c + ospf6_top.h ospf6_zebra.c ospf6d.c ospf6d.h: cleaning. + +2001-03-24 Yasuhiro Ohara + + * ospf6d.h: + version: 0.8.r + + * ospf6_neighbor.[ch], ospf6_lsa.[ch]: + just clean up and log clearify. + + * ospf6_message.[ch]: + Packet receiving function and dumping OSPFv3 packet has been + changed simple and clean. + + * ospf6_dbex.[ch], ospf6_interface.[ch], ospf6_lsdb.[ch], + ospf6_neighbor.[ch], ospf6_nsm.[ch]: + LSList(i.e. summary list, request list, retrans list, etc) have + been rewritten based on new LSDB module. The main LSDB have not + yet shifted to this new module, but will shift eventually. + This change expected to resolve the problem that the ospf6d keeps + on sending redundant LSUpdate/LSAck. + + * ospf6_interface.c: changed default MTU from 1500 to 1280. + It was possible that the ospf6d could not send packet (e.g. + LSUpdate in response to LSReq in my case) when the packet + size accidentally reached near 1500 (I was forget about IP + header :p). It is a bit illegal to set MTU 1280 constantly, + but I failed once with I/F MTU from kernel (through zebra), + and thinks that 1280 is more stable than kernel variable. + Comments will be appriciated. + +2001-03-15 Yasuhiro Ohara + + * ospf6_dbex.c, ospf6_interface.c, ospf6_ism.c, ospf6_lsdb.[ch], + ospf6_neighbor.c, ospf6_spf.c, ospf6d.c: + Fix for crash. ospf6d has ever been crashing when + 'no interface' command executed, and when starting up with + the configuration which does not include 'router ospf6'. + these has been fixed. + +2001-02-24 Yasuhiro Ohara + + * ospf6_lsa.c, ospf6_message.c: + LSA summary (exchanged while Adjacency bring up) may expire + (may reach MaxAge). Handling this has been added but + it's a little bit quick hack. + + * ospf6_message.c: + Thread chain bug fixed. Read network thread chain has been cut + when receive packets on not-enabled interface. this was wrong + and fixed. + +2001-02-24 Yasuhiro Ohara + + * ospf6_message.c: + I/F MTU check part on sending packet had some bug, and it's fixed. + Ospf6d has believed a value from zebra as I/F MTU, but from now + I/F MTU is set to constant 1500. This is workaround for ATM. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-04 Yasuhiro Ohara + + * just code clean up of almost all module. + * ospf6_dump.c, ospf6_lsa.c: file dependency. + * ospf6_mesg.[ch]: changed filename to ospf6_message.[ch] + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + +2001-01-04 Yasuhiro Ohara + + * ospf6_mesg.c,ospf6_lsa.c: doubly cancel thread bug fixed. + version 0.8.k CRASHed for this. + * ospf6_lsa.c: bug of logging fixed. + version: 0.8.l + +2001-01-04 Yasuhiro Ohara + + * ospf6_neighbor.c: fix typo when trying to delete + MaxAge AS-External LSA. MaxAge LSA remaining bug is expected + to be fixed. + version: 0.8.k + +2001-01-04 Yasuhiro Ohara + + * ospf6_mesg.c: add I/F Mtu check for sending LS Update. + + * ospf6_dbex.c, ospf6_mesg.c, ospf6_neighbor.c, ospf6_neighbor.h, + ospf6_spf.c: Changed type of hisaddr field in ospf6_neighbor + structure, from sockaddr_in6 to in6_addr. No protocol/processing + changed. + +2001-01-04 Yasuhiro Ohara + + * ospf6_mesg.c, ospf6_neighbor.[ch]: Speed up of + Database Exchange. + version: 0.8.j + + Because the LS Request list was checked only when attempt + to send (retransmit) LS Request packet, Loading state lasted + long (for RxmtInterval) unexpectedly. This was fixed; LS Request + packet will be send as soon as one received a LS Update packet. + +2001-01-01 Kunihiro Ishiguro + + * ospf6d.h (OSPF6_VTYSH_PATH): Change "/tmp/ospf6d" to + /tmp/.ospf6d". + +2000-12-29 Yasuhiro Ohara + + * ospf6_dump.[ch]: simplified. + +2000-12-19 Yasuhiro Ohara + + * ospf6_route.c: Fix bug of using unavailable route. + version: 0.8.d + +2000-11-30 Yasuhiro Ohara + + * ospf6_spf.c: calculate statistics. version: 0.8.d + +2000-11-26 Yasuhiro Ohara + + * ospf6_mesg.c, ospf6_nsm.c: LSDB sync bug fixed. + version: 0.8.c + +2000-11-26 Yasuhiro Ohara + + * ospf6_dbex.c: Start debugging and cleaning. + + * ospf6_area.c, ospf6_dbex.c, ospf6_interface.c, ospf6_lsa.c, + ospf6_proto.c, ospf6_top.c: add some function to clarify codes. + +2000-11-26 Yasuhiro Ohara + + * ospf6_spf.c: Delete old garbage (which was enclosed by #if 0) + + * ospf6_redistribute.c: "redistribute ospf6" was generated in + "router ospf6" in config file. It is a bug, and fixed. + wrong warning message was deleted. + + * ospf6_main.c: If daemon mode, ospf6d was silent even if + the config file was wrong. It is a bug, and fixed. + + * ospf6_route.c, ospf6_zebra.c: Zebra syncronization method + has been changed. delete garbages. allow nexthop of :: in case + of connected route. + + * ospf6_dbex.c: Delete annoying log messages. + + * ospf6_lsa.c: Changed string for LSA log. + +2000-11-21 Yasuhiro Ohara + + * ospf6_spf.c: some careless bug fixed. + + * ospf6_route.c: changed not to send garbage route + whose nexthop is not linklocal address. + +2000-11-09 Yasuhiro Ohara + + * ospf6_rtable.c: renamed to ospf6_route.c + whole functionality has been rewritten as new code. + new functions not yet installs routes; the old + functions still remains. cleaning log messages. + + * ospf6_spf.c: whole functionality has been rewritten + as new code. new command "show ipv6 ospf6 spf node", + "show ipv6 ospf6 spf tree", "show ipv6 ospf6 spf table" + has been added. Memory leak was fixed. cleaning log messages. + + * ospf6d version: 0.7.c + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-09-10 Kunihiro Ishiguro + + * ospf6_lsdb.c (ospf6_lsdb_remove_maxage_lsa): Fix compile + warnings. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +2000-08-06 Kunihiro Ishiguro + + * ospf6_rtable.h (struct ospf6_nexthop): Change ifindex type from + unsigned long to unsigned int. + +2000-04-28 Kunihiro Ishiguro + + * ospf6d.h: Include some headers for avoid warning. + + * ospf6_routemap.h: Add newfile. + +1999-11-21 Kunihiro Ishiguro + + * ospf6_network.c: Respect IPV6_JOIN_GROUP and IPV6_LEAVE_GROUP + rather than RFC2133. + +1999-10-21 Jun-ichiro itojun Hagino + + * ospf6_network.c (ospf6_ipv6_decode_ipv4): Fix bug of conversion + from IPv4 Mapped Address to IPv4 address. + +1999-08-08 Kunihiro Ishiguro + + * ospf6_lsa.c (construct_link_lsa): Enclose KAME specific part by + #ifdef/#endif. + +1999-07-29 Yasuhiro Ohara + + * ospf6_mesg.c: add new message process function. + +1999-07-25 Kunihiro Ishiguro + + * ospf6_main.c (sighup): Call of log_rotate() removed. + +1999-07-24 Yasuhiro Ohara + + ospf6_dbex.{c,h}: variable "acknowledge" has been deleted. + +1999-07-22 Yasuhiro Ohara + + * *.{c,h}: lsa data structure has been drastically + changed. + +1999-07-16 Yasuhiro Ohara + + * *.{c,h}: bug of updating LSA's which is self + originated has been fixed. + +1999-07-14 Yasuhiro Ohara + + * *.{c,h} : log clean up. + +1999-07-05 Kunihiro Ishiguro + + * ospf6d.c (ospf6_init): Change to use install_default. + +1999-07-03 Yasuhiro Ohara + + * ospf6_rtable.c (nexthop_*): added some function that handles + new nexthop structure. + +1999-07-01 Rick Payne + + * ospf6_zebra.c (ospf6_zebra_init): Install standard commands to + ZEBRA_NODE. + +1999-06-09 Yasuhiro Ohara + + * ospf6_rtable.h: added for new routing table of ospf6d + +1999-05-14 Stephen R. van den Berg + + * ospf6_main.c (signal_init): SIGTERM call sigint. + (sigint): Loggging more better message. + +1999-05-13 Yasuhiro Ohara + + *ospf6_spf.c (get_prefix_lsa_of_vertex): bug fix about network vertex. + +1999-05-08 Kunihiro Ishiguro + + * ospf6_network.c (send_linkstate_ack): Check HAVE_SIN6_SCOPE_ID + is defined. + * ospf6_mesg.c (make_hello): Likewise. + * ospf6_lsa.c (lsa_flood): Likewise. + +1999-05-07 Yasuhiro Ohara + + * ospf6_spf.c, etc: Many bug fix. + intra-area-prefix-LSA treatment changed. + network byte order of neighbor ifid changed. + +1999-05-07 Kunihiro Ishiguro + + * ospf6_zebra.h (struct zebra): Add hitory entry to structure. + +1999-05-05 Kunihiro Ishiguro + + * ospf6_main.c (main): Add KAME check for binding vty socket. + (main): Delete old interface get routine garbage. + + * ospf6d.c: Change all `show ip6' statement to `show ipv6'. + (show_ipv6_ospf6_requestlist): Add description. + +1999-05-04 Yasuhiro Ohara + + * ospf6_lsa.c, etc: Many bug fix, now two routers + on the same segment can become FULL neighbor state + each other. + +1999-05-03 Kunihiro Ishiguro + + * Makefile.am: Add file dependency. + (depend): Add target. + +1999-05-02 Yasuhiro Ohara + + * Clean up and fix have been almost done. This code + now testing stage of Intra area routing. + + * Configuration Vty become more similar to Cisco. + +1999-04-22 Kunihiro Ishiguro + + * Trim training newline from zlog format arguemnt. + + * ospf6_dump.c (ospf6_err): Commented out ospf6_err and + ospf6_warn. Same kind of function should be implemented as + zlog_err or zlog_warn or someting. + + * ospf6d.c: Change OSPF_NODE to OSPF6_NODE. + Change OSPF_DEFAULT_CONFIG to OSPF6_DEFAULT_CONFIG. + + +1999-04-21 Kunihiro Ishiguro + + * ospf6_mesg.c (make_hello): Add check of SIN6_LEN + +1999-04-16 Kunihiro Ishiguro + + * ospf6_neighbor.c: Change list_clear_all to list_delete_all_node. + Remove list_delete_all fuction and use lib/linklist.c's one. + +1999-04-14 Kunihiro Ishiguro + + * mcast_join(),mcast_leave()'s argument socket length is removed. + +1999-04-08 + + * ospf6_zebra.h (ospf_zebra_read): Fix typo. + + * ospf6_interface.h: Tempolary add struct rt_addrinfo. + +1999-03-05 Kunihiro Ishiguro + + * Merge from ospfd-zebra-990303 codes. + +1999-02-23 Kunihiro Ishiguro + + * Makefile.in: add new file. + + * Makefile.am: @INCLUDES@ is added for OS/library specific IPv6 + directory search. + + * Import files from Yasuhiro Ohara 's ospfd. + Impterted files are: + Makefile.am, ospf_area.h, ospf_dump.c, ospf_interface.c, + ospf_interface.h, ospf_lsa.c, ospf_lsa.h, ospf_main.c, + ospf_mesg.c, ospf_mesg.h, ospf_neighbor.c, + ospf_neighbor.h,ospf_network.c, ospf_network.h, ospf_proto.h, + ospf_spf.c, ospf_spf.h, ospf_types.h, ospfd.c, ospfd.h diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am new file mode 100644 index 0000000..05968e2 --- /dev/null +++ b/ospf6d/Makefile.am @@ -0,0 +1,50 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +noinst_LIBRARIES = libospf6.a +sbin_PROGRAMS = ospf6d +noinst_PROGRAMS = ospf6test + +libospf6_a_SOURCES = \ + ospf6_network.c ospf6_message.c ospf6_lsa.c ospf6_lsdb.c \ + ospf6_top.c ospf6_area.c ospf6_interface.c ospf6_neighbor.c \ + ospf6_flood.c ospf6_route.c ospf6_intra.c ospf6_zebra.c \ + ospf6_spf.c ospf6_proto.c ospf6_asbr.c ospf6_abr.c ospf6_snmp.c \ + ospf6d.c + +noinst_HEADERS = \ + ospf6_network.h ospf6_message.h ospf6_lsa.h ospf6_lsdb.h \ + ospf6_top.h ospf6_area.h ospf6_interface.h ospf6_neighbor.h \ + ospf6_flood.h ospf6_route.h ospf6_intra.h ospf6_zebra.h \ + ospf6_spf.h ospf6_proto.h ospf6_asbr.h ospf6_abr.h ospf6_snmp.h \ + ospf6d.h + +ospf6d_SOURCES = \ + ospf6_main.c $(libospf6_a_SOURCES) + +ospf6d_LDADD = ../lib/libzebra.a + +ospf6test_SOURCES = \ + ospf6_test.c $(libospf6_a_SOURCES) + +ospf6test_LDADD = ../lib/libzebra.a + +sysconf_DATA = ospf6d.conf.sample + +EXTRA_DIST = $(sysconf_DATA) + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done diff --git a/ospf6d/Makefile.in b/ospf6d/Makefile.in new file mode 100644 index 0000000..fdd7a53 --- /dev/null +++ b/ospf6d/Makefile.in @@ -0,0 +1,474 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CPP = @CPP@ +CURSES = @CURSES@ +DEPDIR = @DEPDIR@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LIBPAM = @LIBPAM@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA = @INSTALL@ -m 600 + +noinst_LIBRARIES = libospf6.a +sbin_PROGRAMS = ospf6d +noinst_PROGRAMS = ospf6test + +libospf6_a_SOURCES = \ + ospf6_network.c ospf6_message.c ospf6_lsa.c ospf6_lsdb.c \ + ospf6_top.c ospf6_area.c ospf6_interface.c ospf6_neighbor.c \ + ospf6_flood.c ospf6_route.c ospf6_intra.c ospf6_zebra.c \ + ospf6_spf.c ospf6_proto.c ospf6_asbr.c ospf6_abr.c ospf6_snmp.c \ + ospf6d.c + + +noinst_HEADERS = \ + ospf6_network.h ospf6_message.h ospf6_lsa.h ospf6_lsdb.h \ + ospf6_top.h ospf6_area.h ospf6_interface.h ospf6_neighbor.h \ + ospf6_flood.h ospf6_route.h ospf6_intra.h ospf6_zebra.h \ + ospf6_spf.h ospf6_proto.h ospf6_asbr.h ospf6_abr.h ospf6_snmp.h \ + ospf6d.h + + +ospf6d_SOURCES = \ + ospf6_main.c $(libospf6_a_SOURCES) + + +ospf6d_LDADD = ../lib/libzebra.a + +ospf6test_SOURCES = \ + ospf6_test.c $(libospf6_a_SOURCES) + + +ospf6test_LDADD = ../lib/libzebra.a + +sysconf_DATA = ospf6d.conf.sample + +EXTRA_DIST = $(sysconf_DATA) +subdir = ospf6d +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libospf6_a_AR = $(AR) cru +libospf6_a_LIBADD = +am_libospf6_a_OBJECTS = ospf6_network.$(OBJEXT) ospf6_message.$(OBJEXT) \ + ospf6_lsa.$(OBJEXT) ospf6_lsdb.$(OBJEXT) ospf6_top.$(OBJEXT) \ + ospf6_area.$(OBJEXT) ospf6_interface.$(OBJEXT) \ + ospf6_neighbor.$(OBJEXT) ospf6_flood.$(OBJEXT) \ + ospf6_route.$(OBJEXT) ospf6_intra.$(OBJEXT) \ + ospf6_zebra.$(OBJEXT) ospf6_spf.$(OBJEXT) ospf6_proto.$(OBJEXT) \ + ospf6_asbr.$(OBJEXT) ospf6_abr.$(OBJEXT) ospf6_snmp.$(OBJEXT) \ + ospf6d.$(OBJEXT) +libospf6_a_OBJECTS = $(am_libospf6_a_OBJECTS) +noinst_PROGRAMS = ospf6test$(EXEEXT) +sbin_PROGRAMS = ospf6d$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) $(sbin_PROGRAMS) + +am__objects_1 = ospf6_network.$(OBJEXT) ospf6_message.$(OBJEXT) \ + ospf6_lsa.$(OBJEXT) ospf6_lsdb.$(OBJEXT) ospf6_top.$(OBJEXT) \ + ospf6_area.$(OBJEXT) ospf6_interface.$(OBJEXT) \ + ospf6_neighbor.$(OBJEXT) ospf6_flood.$(OBJEXT) \ + ospf6_route.$(OBJEXT) ospf6_intra.$(OBJEXT) \ + ospf6_zebra.$(OBJEXT) ospf6_spf.$(OBJEXT) ospf6_proto.$(OBJEXT) \ + ospf6_asbr.$(OBJEXT) ospf6_abr.$(OBJEXT) ospf6_snmp.$(OBJEXT) \ + ospf6d.$(OBJEXT) +am_ospf6d_OBJECTS = ospf6_main.$(OBJEXT) $(am__objects_1) +ospf6d_OBJECTS = $(am_ospf6d_OBJECTS) +ospf6d_DEPENDENCIES = ../lib/libzebra.a +ospf6d_LDFLAGS = +am_ospf6test_OBJECTS = ospf6_test.$(OBJEXT) $(am__objects_1) +ospf6test_OBJECTS = $(am_ospf6test_OBJECTS) +ospf6test_DEPENDENCIES = ../lib/libzebra.a +ospf6test_LDFLAGS = +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ospf6_abr.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_area.Po ./$(DEPDIR)/ospf6_asbr.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_flood.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_interface.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_intra.Po ./$(DEPDIR)/ospf6_lsa.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_lsdb.Po ./$(DEPDIR)/ospf6_main.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_message.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_neighbor.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_network.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_proto.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_route.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_snmp.Po ./$(DEPDIR)/ospf6_spf.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_test.Po ./$(DEPDIR)/ospf6_top.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf6_zebra.Po ./$(DEPDIR)/ospf6d.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CFLAGS = @CFLAGS@ +DIST_SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES) \ + $(ospf6test_SOURCES) +DATA = $(sysconf_DATA) + +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = README $(noinst_HEADERS) ChangeLog Makefile.am \ + Makefile.in +SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES) $(ospf6test_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign ospf6d/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libospf6.a: $(libospf6_a_OBJECTS) $(libospf6_a_DEPENDENCIES) + -rm -f libospf6.a + $(libospf6_a_AR) libospf6.a $(libospf6_a_OBJECTS) $(libospf6_a_LIBADD) + $(RANLIB) libospf6.a + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) +sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \ + rm -f $(DESTDIR)$(sbindir)/$$f; \ + done + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) +ospf6d$(EXEEXT): $(ospf6d_OBJECTS) $(ospf6d_DEPENDENCIES) + @rm -f ospf6d$(EXEEXT) + $(LINK) $(ospf6d_LDFLAGS) $(ospf6d_OBJECTS) $(ospf6d_LDADD) $(LIBS) +ospf6test$(EXEEXT): $(ospf6test_OBJECTS) $(ospf6test_DEPENDENCIES) + @rm -f ospf6test$(EXEEXT) + $(LINK) $(ospf6test_LDFLAGS) $(ospf6test_OBJECTS) $(ospf6test_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_abr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_area.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_asbr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_flood.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_interface.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_intra.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_lsa.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_lsdb.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_message.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_neighbor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_network.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_proto.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_route.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_snmp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_spf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_top.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_zebra.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6d.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `cygpath -w $<` +CCDEPMODE = @CCDEPMODE@ +uninstall-info-am: +sysconfDATA_INSTALL = $(INSTALL_DATA) + +uninstall-sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(sysconf_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \ + rm -f $(DESTDIR)$(sysconfdir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-noinstPROGRAMS \ + clean-sbinPROGRAMS mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-sbinPROGRAMS install-sysconfDATA + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \ + uninstall-sysconfDATA + +.PHONY: GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES clean-noinstPROGRAMS clean-sbinPROGRAMS \ + distclean distclean-compile distclean-depend distclean-generic \ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-sbinPROGRAMS install-strip install-sysconfDATA \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic tags uninstall uninstall-am \ + uninstall-info-am uninstall-sbinPROGRAMS uninstall-sysconfDATA + + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/ospf6d/README b/ospf6d/README new file mode 100644 index 0000000..883486f --- /dev/null +++ b/ospf6d/README @@ -0,0 +1,93 @@ + + Zebra OSPF daemon for IPv6 network + + 2003/08/18 + +README for newer code is not yet. General usage should remain +the same. For further usage, see command helps by typing '?' +in vty, and then imagin ! ;p) Previous README contents follows. + + Zebra OSPF daemon for IPv6 network + + 2001/12/20 + +Zebra OSPF6d is OSPF version 3 daemon which is specified by +"OSPF for IPv6" (RFC 2740). + +*** NOTE *** + Zebra ospf6d is in development yet. It may lack some functionalities, + and may have some bugs. Use the latest version from the anoncvs + repository (http://www.zebra.org/cvs.html) ! + +This file README is like memo yet, so please feel free to ask + by E-mail. Patches will be appriciated. + +ospf6d's vty port was default to 2606/tcp. +Use commands below. + +VIEW NODE: + show ipv6 ospf6 + To see Router-ID, uptime of ospf6d, some statistics. + + show ipv6 ospf6 database ... + This command shows LSA database. You can specify + LS-type/LS-ID/Advertising-Router of LSAs. '*' is recognized. + + show ipv6 ospf6 interface ... + To see the status of the OSPF interface, and the configuration + like interface costs. + + show ipv6 ospf6 neighbor ... + Shows state of neighbors and choosed (Backup) DR on the I/F. + + show ipv6 ospf6 route (X::X) + This command shows internal routing table of the ospf6d. + Routes not calculated by OSPFv3 (like connected routes) + are not shown. If Address is specified (X::X), shows the route + that the address matches. + + show ipv6 ospf6 route redistribute (X::X) + Shows the routes advertised as AS-External routes by the router + itself. If Address is specified (X::X), shows the route + that the address matches. + +CONFIG NODE: + interface NAME + To enter INTERFACE NODE + + router ospf6 ... + To enter OSPF6 NODE + +INTERFACE NODE: + ipv6 ospf6 cost COST + Sets the interface's output cost. default 1 + + ipv6 ospf6 hello-interval HELLOINTERVAL + Sets the interface's Hello Interval. default 10 + + ipv6 ospf6 dead-interval DEADINTERVAL + Sets the interface's Router Dead Interval. default 40 + + ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL + Sets the interface's Rxmt Interval. default 5 + + ipv6 ospf6 priority PRIORITY + Sets the interface's Router Priority. default 1 + + ipv6 ospf6 transmit-delay TRANSMITDELAY + Sets the interface's Inf-Trans-Delay. default 1 + +OSPF6 NODE: + router-id A.B.C.D + Sets the router's Router-ID + + interface NAME area AREA + Binds interface to specified Area, and start + sending OSPFv3 packets. + +Sample configuration is in ospf6d.conf.sample. + +-- +Yasuhiro Ohara +Kunihiro Ishiguro + diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c new file mode 100644 index 0000000..014c71a --- /dev/null +++ b/ospf6d/ospf6_abr.c @@ -0,0 +1,887 @@ +/* + * Area Border Router function. + * Copyright (C) 2004 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "prefix.h" +#include "table.h" +#include "vty.h" +#include "linklist.h" +#include "command.h" +#include "thread.h" +#include "plist.h" +#include "filter.h" + +#include "ospf6_proto.h" +#include "ospf6_route.h" +#include "ospf6_lsa.h" +#include "ospf6_route.h" +#include "ospf6_lsdb.h" +#include "ospf6_message.h" + +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" + +#include "ospf6_flood.h" +#include "ospf6_intra.h" +#include "ospf6_abr.h" +#include "ospf6d.h" + +unsigned char conf_debug_ospf6_abr; + +int +ospf6_is_router_abr (struct ospf6 *o) +{ + listnode node; + struct ospf6_area *oa; + int area_count = 0; + + for (node = listhead (o->area_list); node; nextnode (node)) + { + oa = OSPF6_AREA (getdata (node)); + if (IS_AREA_ENABLED (oa)) + area_count++; + } + + if (area_count > 1) + return 1; + return 0; +} + +void +ospf6_abr_enable_area (struct ospf6_area *area) +{ + struct ospf6_area *oa; + struct ospf6_route *ro; + listnode node; + + for (node = listhead (area->ospf6->area_list); node; nextnode (node)) + { + oa = OSPF6_AREA (getdata (node)); + + /* update B bit for each area */ + OSPF6_ROUTER_LSA_SCHEDULE (oa); + + /* install other area's configured address range */ + if (oa != area) + { + for (ro = ospf6_route_head (oa->range_table); ro; + ro = ospf6_route_next (ro)) + { + if (CHECK_FLAG (ro->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) + ospf6_abr_originate_summary_to_area (ro, area); + } + } + } + + /* install calculated routes to border routers */ + for (ro = ospf6_route_head (area->ospf6->brouter_table); ro; + ro = ospf6_route_next (ro)) + ospf6_abr_originate_summary_to_area (ro, area); + + /* install calculated routes to network (may be rejected by ranges) */ + for (ro = ospf6_route_head (area->ospf6->route_table); ro; + ro = ospf6_route_next (ro)) + ospf6_abr_originate_summary_to_area (ro, area); +} + +void +ospf6_abr_disable_area (struct ospf6_area *area) +{ + struct ospf6_area *oa; + struct ospf6_route *ro; + struct ospf6_lsa *old; + listnode node; + + /* Withdraw all summary prefixes previously originated */ + for (ro = ospf6_route_head (area->summary_prefix); ro; + ro = ospf6_route_next (ro)) + { + old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, + area->ospf6->router_id, area->lsdb); + if (old) + ospf6_lsa_purge (old); + ospf6_route_remove (ro, area->summary_prefix); + } + + /* Withdraw all summary router-routes previously originated */ + for (ro = ospf6_route_head (area->summary_router); ro; + ro = ospf6_route_next (ro)) + { + old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, + area->ospf6->router_id, area->lsdb); + if (old) + ospf6_lsa_purge (old); + ospf6_route_remove (ro, area->summary_router); + } + + /* Schedule Router-LSA for each area (ABR status may change) */ + for (node = listhead (area->ospf6->area_list); node; nextnode (node)) + { + oa = OSPF6_AREA (getdata (node)); + + /* update B bit for each area */ + OSPF6_ROUTER_LSA_SCHEDULE (oa); + } +} + +/* RFC 2328 12.4.3. Summary-LSAs */ +void +ospf6_abr_originate_summary_to_area (struct ospf6_route *route, + struct ospf6_area *area) +{ + struct ospf6_lsa *lsa, *old = NULL; + struct ospf6_interface *oi; + struct ospf6_route *summary, *range = NULL; + struct ospf6_area *route_area; + char buffer[OSPF6_MAX_LSASIZE]; + struct ospf6_lsa_header *lsa_header; + caddr_t p; + struct ospf6_inter_prefix_lsa *prefix_lsa; + struct ospf6_inter_router_lsa *router_lsa; + struct ospf6_route_table *summary_table = NULL; + u_int16_t type; + char buf[64]; + int is_debug = 0; + + if (route->type == OSPF6_DEST_TYPE_ROUTER) + { + if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_ROUTER)) + { + is_debug++; + inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), + buf, sizeof (buf)); + zlog_info ("Originating summary in area %s for ASBR %s", + area->name, buf); + } + summary_table = area->summary_router; + } + else + { + if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_PREFIX)) + { + is_debug++; + prefix2str (&route->prefix, buf, sizeof (buf)); + zlog_info ("Originating summary in area %s for %s", + area->name, buf); + } + summary_table = area->summary_prefix; + } + + summary = ospf6_route_lookup (&route->prefix, summary_table); + if (summary) + old = ospf6_lsdb_lookup (summary->path.origin.type, + summary->path.origin.id, + area->ospf6->router_id, area->lsdb); + + /* if this route has just removed, remove corresponding LSA */ + if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE)) + { + if (is_debug) + zlog_info ("The route has just removed, purge previous LSA"); + if (summary) + ospf6_route_remove (summary, summary_table); + if (old) + ospf6_lsa_purge (old); + return; + } + + /* Only destination type network, range or ASBR are considered */ + if (route->type != OSPF6_DEST_TYPE_NETWORK && + route->type != OSPF6_DEST_TYPE_RANGE && + (route->type != OSPF6_DEST_TYPE_ROUTER || + ! CHECK_FLAG (route->path.router_bits, OSPF6_ROUTER_BIT_E))) + { + if (is_debug) + zlog_info ("Route type is none of network, range nor ASBR, withdraw"); + if (summary) + ospf6_route_remove (summary, summary_table); + if (old) + ospf6_lsa_purge (old); + return; + } + + /* AS External routes are never considered */ + if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 || + route->path.type == OSPF6_PATH_TYPE_EXTERNAL2) + { + if (is_debug) + zlog_info ("Path type is external, withdraw"); + if (summary) + ospf6_route_remove (summary, summary_table); + if (old) + ospf6_lsa_purge (old); + return; + } + + /* do not generate if the path's area is the same as target area */ + if (route->path.area_id == area->area_id) + { + if (is_debug) + zlog_info ("The route is in the area itself, ignore"); + if (summary) + ospf6_route_remove (summary, summary_table); + if (old) + ospf6_lsa_purge (old); + return; + } + + /* do not generate if the nexthops belongs to the target area */ + oi = ospf6_interface_lookup_by_ifindex (route->nexthop[0].ifindex); + if (oi && oi->area && oi->area == area) + { + if (is_debug) + zlog_info ("The route's nexthop is in the same area, ignore"); + if (summary) + ospf6_route_remove (summary, summary_table); + if (old) + ospf6_lsa_purge (old); + return; + } + + /* do not generate if the route cost is greater or equal to LSInfinity */ + if (route->path.cost >= LS_INFINITY) + { + if (is_debug) + zlog_info ("The cost exceeds LSInfinity, withdraw"); + if (summary) + ospf6_route_remove (summary, summary_table); + if (old) + ospf6_lsa_purge (old); + return; + } + + /* if this is a route to ASBR */ + if (route->type == OSPF6_DEST_TYPE_ROUTER) + { + /* Only the prefered best path is considered */ + if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST)) + { + if (is_debug) + zlog_info ("This is the secondary path to the ASBR, ignore"); + if (summary) + ospf6_route_remove (summary, summary_table); + if (old) + ospf6_lsa_purge (old); + return; + } + + /* Do not generate if the area is stub */ + /* XXX */ + } + + /* if this is an intra-area route, this may be suppressed by aggregation */ + if (route->type == OSPF6_DEST_TYPE_NETWORK && + route->path.type == OSPF6_PATH_TYPE_INTRA) + { + /* search for configured address range for the route's area */ + route_area = ospf6_area_lookup (route->path.area_id, area->ospf6); + assert (route_area); + range = ospf6_route_lookup_bestmatch (&route->prefix, + route_area->range_table); + + /* ranges are ignored when originate backbone routes to transit area. + Otherwise, if ranges are configured, the route is suppressed. */ + if (range && ! CHECK_FLAG (range->flag, OSPF6_ROUTE_REMOVE) && + (route->path.area_id != BACKBONE_AREA_ID || + ! IS_AREA_TRANSIT (area))) + { + if (is_debug) + { + prefix2str (&range->prefix, buf, sizeof (buf)); + zlog_info ("Suppressed by range %s of area %s", + buf, route_area->name); + } + + if (summary) + ospf6_route_remove (summary, summary_table); + if (old) + ospf6_lsa_purge (old); + return; + } + } + + /* If this is a configured address range */ + if (route->type == OSPF6_DEST_TYPE_RANGE) + { + /* If DoNotAdvertise is set */ + if (CHECK_FLAG (route->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) + { + if (is_debug) + zlog_info ("This is the range with DoNotAdvertise set. ignore"); + if (summary) + ospf6_route_remove (summary, summary_table); + if (old) + ospf6_lsa_purge (old); + return; + } + + /* Whether the route have active longer prefix */ + if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) + { + if (is_debug) + zlog_info ("The range is not active. withdraw"); + if (summary) + ospf6_route_remove (summary, summary_table); + if (old) + ospf6_lsa_purge (old); + return; + } + } + + /* Check export list */ + if (EXPORT_NAME (area)) + { + if (EXPORT_LIST (area) == NULL) + EXPORT_LIST (area) = + access_list_lookup (AFI_IP6, EXPORT_NAME (area)); + + if (EXPORT_LIST (area)) + if (access_list_apply (EXPORT_LIST (area), + &route->prefix) == FILTER_DENY) + { + if (is_debug) + { + inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), + buf, sizeof(buf)); + zlog_debug ("prefix %s was denied by export list", buf); + } + return; + } + } + + /* Check filter-list */ + if (PREFIX_NAME_OUT (area)) + { + if (PREFIX_LIST_OUT (area) == NULL) + PREFIX_LIST_OUT (area) = + prefix_list_lookup(AFI_IP6, PREFIX_NAME_OUT (area)); + + if (PREFIX_LIST_OUT (area)) + if (prefix_list_apply (PREFIX_LIST_OUT (area), + &route->prefix) != PREFIX_PERMIT) + { + if (is_debug) + { + inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), + buf, sizeof (buf)); + zlog_debug ("prefix %s was denied by filter-list out", buf); + } + return; + } + } + + /* the route is going to be originated. store it in area's summary_table */ + if (summary == NULL) + { + summary = ospf6_route_copy (route); + if (route->type == OSPF6_DEST_TYPE_NETWORK || + route->type == OSPF6_DEST_TYPE_RANGE) + summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX); + else + summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER); + summary->path.origin.adv_router = area->ospf6->router_id; + summary->path.origin.id = + ospf6_new_ls_id (summary->path.origin.type, + summary->path.origin.adv_router, area->lsdb); + summary = ospf6_route_add (summary, summary_table); + } + else + { + summary->type = route->type; + gettimeofday (&summary->changed, NULL); + } + + summary->path.router_bits = route->path.router_bits; + summary->path.options[0] = route->path.options[0]; + summary->path.options[1] = route->path.options[1]; + summary->path.options[2] = route->path.options[2]; + summary->path.prefix_options = route->path.prefix_options; + summary->path.area_id = area->area_id; + summary->path.type = OSPF6_PATH_TYPE_INTER; + summary->path.cost = route->path.cost; + summary->nexthop[0] = route->nexthop[0]; + + /* prepare buffer */ + memset (buffer, 0, sizeof (buffer)); + lsa_header = (struct ospf6_lsa_header *) buffer; + + if (route->type == OSPF6_DEST_TYPE_ROUTER) + { + router_lsa = (struct ospf6_inter_router_lsa *) + ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); + p = (caddr_t) router_lsa + sizeof (struct ospf6_inter_router_lsa); + + /* Fill Inter-Area-Router-LSA */ + router_lsa->options[0] = route->path.options[0]; + router_lsa->options[1] = route->path.options[1]; + router_lsa->options[2] = route->path.options[2]; + OSPF6_ABR_SUMMARY_METRIC_SET (router_lsa, route->path.cost); + router_lsa->router_id = ADV_ROUTER_IN_PREFIX (&route->prefix); + type = htons (OSPF6_LSTYPE_INTER_ROUTER); + } + else + { + prefix_lsa = (struct ospf6_inter_prefix_lsa *) + ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); + p = (caddr_t) prefix_lsa + sizeof (struct ospf6_inter_prefix_lsa); + + /* Fill Inter-Area-Prefix-LSA */ + OSPF6_ABR_SUMMARY_METRIC_SET (prefix_lsa, route->path.cost); + prefix_lsa->prefix.prefix_length = route->prefix.prefixlen; + prefix_lsa->prefix.prefix_options = route->path.prefix_options; + + /* set Prefix */ + memcpy (p, &route->prefix.u.prefix6, + OSPF6_PREFIX_SPACE (route->prefix.prefixlen)); + ospf6_prefix_apply_mask (&prefix_lsa->prefix); + p += OSPF6_PREFIX_SPACE (route->prefix.prefixlen); + type = htons (OSPF6_LSTYPE_INTER_PREFIX); + } + + /* Fill LSA Header */ + lsa_header->age = 0; + lsa_header->type = type; + lsa_header->id = summary->path.origin.id; + lsa_header->adv_router = area->ospf6->router_id; + lsa_header->seqnum = + ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, + lsa_header->adv_router, area->lsdb); + lsa_header->length = htons ((caddr_t) p - (caddr_t) lsa_header); + + /* LSA checksum */ + ospf6_lsa_checksum (lsa_header); + + /* create LSA */ + lsa = ospf6_lsa_create (lsa_header); + + /* Originate */ + ospf6_lsa_originate_area (lsa, area); +} + +void +ospf6_abr_range_update (struct ospf6_route *range) +{ + u_int32_t cost = 0; + struct ospf6_route *ro; + + assert (range->type == OSPF6_DEST_TYPE_RANGE); + + /* update range's cost and active flag */ + for (ro = ospf6_route_match_head (&range->prefix, ospf6->route_table); + ro; ro = ospf6_route_match_next (&range->prefix, ro)) + { + if (ro->path.area_id == range->path.area_id && + ! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE)) + cost = MAX (cost, ro->path.cost); + } + + if (range->path.cost != cost) + { + range->path.cost = cost; + + if (range->path.cost) + SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); + else + UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); + + ospf6_abr_originate_summary (range); + } +} + +void +ospf6_abr_originate_summary (struct ospf6_route *route) +{ + listnode node; + struct ospf6_area *oa; + struct ospf6_route *range = NULL; + + if (route->type == OSPF6_DEST_TYPE_NETWORK) + { + oa = ospf6_area_lookup (route->path.area_id, ospf6); + range = ospf6_route_lookup_bestmatch (&route->prefix, oa->range_table); + if (range) + ospf6_abr_range_update (range); + } + + for (node = listhead (ospf6->area_list); node; nextnode (node)) + { + oa = (struct ospf6_area *) getdata (node); + ospf6_abr_originate_summary_to_area (route, oa); + } +} + +/* RFC 2328 16.2. Calculating the inter-area routes */ +void +ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) +{ + struct prefix prefix, abr_prefix; + struct ospf6_route_table *table = NULL; + struct ospf6_route *range, *route, *old = NULL; + struct ospf6_route *abr_entry; + u_char type = 0; + char options[3] = {0, 0, 0}; + u_int8_t prefix_options = 0; + u_int32_t cost = 0; + u_char router_bits = 0; + int i; + char buf[64]; + int is_debug = 0; + + if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX)) + { + struct ospf6_inter_prefix_lsa *prefix_lsa; + + if (IS_OSPF6_DEBUG_EXAMIN (INTER_PREFIX)) + { + is_debug++; + zlog_info ("Examin %s in area %s", lsa->name, oa->name); + } + + prefix_lsa = (struct ospf6_inter_prefix_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); + prefix.family = AF_INET6; + prefix.prefixlen = prefix_lsa->prefix.prefix_length; + ospf6_prefix_in6_addr (&prefix.u.prefix6, &prefix_lsa->prefix); + prefix2str (&prefix, buf, sizeof (buf)); + table = oa->ospf6->route_table; + type = OSPF6_DEST_TYPE_NETWORK; + prefix_options = prefix_lsa->prefix.prefix_options; + cost = OSPF6_ABR_SUMMARY_METRIC (prefix_lsa); + } + else if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_ROUTER)) + { + struct ospf6_inter_router_lsa *router_lsa; + + if (IS_OSPF6_DEBUG_EXAMIN (INTER_ROUTER)) + { + is_debug++; + zlog_info ("Examin %s in area %s", lsa->name, oa->name); + } + + router_lsa = (struct ospf6_inter_router_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); + ospf6_linkstate_prefix (router_lsa->router_id, htonl (0), &prefix); + inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf)); + table = oa->ospf6->brouter_table; + type = OSPF6_DEST_TYPE_ROUTER; + options[0] = router_lsa->options[0]; + options[1] = router_lsa->options[1]; + options[2] = router_lsa->options[2]; + cost = OSPF6_ABR_SUMMARY_METRIC (router_lsa); + SET_FLAG (router_bits, OSPF6_ROUTER_BIT_E); + } + else + assert (0); + + /* Find existing route */ + route = ospf6_route_lookup (&prefix, table); + if (route) + ospf6_route_lock (route); + while (route && ospf6_route_is_prefix (&prefix, route)) + { + if (route->path.area_id == oa->area_id && + route->path.origin.type == lsa->header->type && + route->path.origin.id == lsa->header->id && + route->path.origin.adv_router == lsa->header->adv_router) + old = route; + route = ospf6_route_next (route); + } + + /* (1) if cost == LSInfinity or if the LSA is MaxAge */ + if (cost == LS_INFINITY) + { + if (is_debug) + zlog_info ("cost is LS_INFINITY, ignore"); + if (old) + ospf6_route_remove (old, table); + return; + } + if (OSPF6_LSA_IS_MAXAGE (lsa)) + { + if (is_debug) + zlog_info ("LSA is MaxAge, ignore"); + if (old) + ospf6_route_remove (old, table); + return; + } + + /* (2) if the LSA is self-originated, ignore */ + if (lsa->header->adv_router == oa->ospf6->router_id) + { + if (is_debug) + zlog_info ("LSA is self-originated, ignore"); + if (old) + ospf6_route_remove (old, table); + return; + } + + /* (3) if the prefix is equal to an active configured address range */ + if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX)) + { + range = ospf6_route_lookup (&prefix, oa->range_table); + if (range) + { + if (is_debug) + zlog_info ("Prefix is equal to address range, ignore"); + if (old) + ospf6_route_remove (old, table); + return; + } + } + + /* (4) if the routing table entry for the ABR does not exist */ + ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &abr_prefix); + abr_entry = ospf6_route_lookup (&abr_prefix, oa->ospf6->brouter_table); + if (abr_entry == NULL || abr_entry->path.area_id != oa->area_id || + CHECK_FLAG (abr_entry->flag, OSPF6_ROUTE_REMOVE) || + ! CHECK_FLAG (abr_entry->path.router_bits, OSPF6_ROUTER_BIT_B)) + { + if (is_debug) + zlog_info ("ABR router entry does not exist, ignore"); + if (old) + ospf6_route_remove (old, table); + return; + } + + /* Check import list */ + if (IMPORT_NAME (oa)) + { + if (IMPORT_LIST (oa) == NULL) + IMPORT_LIST (oa) = access_list_lookup (AFI_IP6, IMPORT_NAME (oa)); + + if (IMPORT_LIST (oa)) + if (access_list_apply (IMPORT_LIST (oa), &prefix) == FILTER_DENY) + { + if (is_debug) + zlog_debug ("Prefix was denied by import-list"); + if (old) + ospf6_route_remove (old, table); + return; + } + } + + /* Check input prefix-list */ + if (PREFIX_NAME_IN (oa)) + { + if (PREFIX_LIST_IN (oa) == NULL) + PREFIX_LIST_IN (oa) = prefix_list_lookup (AFI_IP6, PREFIX_NAME_IN (oa)); + + if (PREFIX_LIST_IN (oa)) + if (prefix_list_apply (PREFIX_LIST_IN (oa), &prefix) != PREFIX_PERMIT) + { + if (is_debug) + zlog_debug ("Prefix was denied by prefix-list"); + if (old) + ospf6_route_remove (old, table); + return; + } + } + + /* (5),(6),(7) the path preference is handled by the sorting + in the routing table. Always install the path by substituting + old route (if any). */ + if (old) + route = ospf6_route_copy (old); + else + route = ospf6_route_create (); + + route->type = type; + route->prefix = prefix; + route->path.origin.type = lsa->header->type; + route->path.origin.id = lsa->header->id; + route->path.origin.adv_router = lsa->header->adv_router; + route->path.router_bits = router_bits; + route->path.options[0] = options[0]; + route->path.options[1] = options[1]; + route->path.options[2] = options[2]; + route->path.prefix_options = prefix_options; + route->path.area_id = oa->area_id; + route->path.type = OSPF6_PATH_TYPE_INTER; + route->path.cost = abr_entry->path.cost + cost; + for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) + route->nexthop[i] = abr_entry->nexthop[i]; + + if (is_debug) + zlog_info ("Install route: %s", buf); + ospf6_route_add (route, table); +} + +void +ospf6_abr_examin_brouter (u_int32_t router_id) +{ + struct ospf6_lsa *lsa; + struct ospf6_area *oa; + listnode node; + u_int16_t type; + + type = htons (OSPF6_LSTYPE_INTER_ROUTER); + for (node = listhead (ospf6->area_list); node; nextnode (node)) + { + oa = OSPF6_AREA (getdata (node)); + for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa; + lsa = ospf6_lsdb_type_router_next (type, router_id, lsa)) + ospf6_abr_examin_summary (lsa, oa); + } + + type = htons (OSPF6_LSTYPE_INTER_PREFIX); + for (node = listhead (ospf6->area_list); node; nextnode (node)) + { + oa = OSPF6_AREA (getdata (node)); + for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa; + lsa = ospf6_lsdb_type_router_next (type, router_id, lsa)) + ospf6_abr_examin_summary (lsa, oa); + } +} + +void +ospf6_abr_reimport (struct ospf6_area *oa) +{ + struct ospf6_lsa *lsa; + u_int16_t type; + + type = htons (OSPF6_LSTYPE_INTER_ROUTER); + for (lsa = ospf6_lsdb_type_head (type, oa->lsdb); lsa; + lsa = ospf6_lsdb_type_next (type, lsa)) + ospf6_abr_examin_summary (lsa, oa); + + type = htons (OSPF6_LSTYPE_INTER_PREFIX); + for (lsa = ospf6_lsdb_type_head (type, oa->lsdb); lsa; + lsa = ospf6_lsdb_type_next (type, lsa)) + ospf6_abr_examin_summary (lsa, oa); +} + + + +/* Display functions */ +int +ospf6_inter_area_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + struct ospf6_inter_prefix_lsa *prefix_lsa; + struct in6_addr in6; + char buf[64]; + + prefix_lsa = (struct ospf6_inter_prefix_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); + + vty_out (vty, " Metric: %lu%s", + (u_long) OSPF6_ABR_SUMMARY_METRIC (prefix_lsa), VNL); + + ospf6_prefix_options_printbuf (prefix_lsa->prefix.prefix_options, + buf, sizeof (buf)); + vty_out (vty, " Prefix Options: %s%s", buf, VNL); + + ospf6_prefix_in6_addr (&in6, &prefix_lsa->prefix); + inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); + vty_out (vty, " Prefix: %s/%d%s", buf, + prefix_lsa->prefix.prefix_length, VNL); + + return 0; +} + +int +ospf6_inter_area_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + struct ospf6_inter_router_lsa *router_lsa; + char buf[64]; + + router_lsa = (struct ospf6_inter_router_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); + + ospf6_options_printbuf (router_lsa->options, buf, sizeof (buf)); + vty_out (vty, " Options: %s%s", buf, VNL); + vty_out (vty, " Metric: %lu%s", + (u_long) OSPF6_ABR_SUMMARY_METRIC (router_lsa), VNL); + inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf)); + vty_out (vty, " Destination Router ID: %s%s", buf, VNL); + + return 0; +} + +/* Debug commands */ +DEFUN (debug_ospf6_abr, + debug_ospf6_abr_cmd, + "debug ospf6 abr", + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 ABR function\n" + ) +{ + OSPF6_DEBUG_ABR_ON (); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf6_abr, + no_debug_ospf6_abr_cmd, + "no debug ospf6 abr", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 ABR function\n" + ) +{ + OSPF6_DEBUG_ABR_OFF (); + return CMD_SUCCESS; +} + +int +config_write_ospf6_debug_abr (struct vty *vty) +{ + if (IS_OSPF6_DEBUG_ABR) + vty_out (vty, "debug ospf6 abr%s", VNL); + return 0; +} + +void +install_element_ospf6_debug_abr () +{ + install_element (ENABLE_NODE, &debug_ospf6_abr_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_abr_cmd); + install_element (CONFIG_NODE, &debug_ospf6_abr_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_abr_cmd); +} + +struct ospf6_lsa_handler inter_prefix_handler = +{ + OSPF6_LSTYPE_INTER_PREFIX, + "Inter-Prefix", + ospf6_inter_area_prefix_lsa_show +}; + +struct ospf6_lsa_handler inter_router_handler = +{ + OSPF6_LSTYPE_INTER_ROUTER, + "Inter-Router", + ospf6_inter_area_router_lsa_show +}; + +void +ospf6_abr_init () +{ + ospf6_install_lsa_handler (&inter_prefix_handler); + ospf6_install_lsa_handler (&inter_router_handler); +} + + diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h new file mode 100644 index 0000000..84c6fa5 --- /dev/null +++ b/ospf6d/ospf6_abr.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2004 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_ABR_H +#define OSPF6_ABR_H + +/* Debug option */ +extern unsigned char conf_debug_ospf6_abr; +#define OSPF6_DEBUG_ABR_ON() \ + (conf_debug_ospf6_abr = 1) +#define OSPF6_DEBUG_ABR_OFF() \ + (conf_debug_ospf6_abr = 0) +#define IS_OSPF6_DEBUG_ABR \ + (conf_debug_ospf6_abr) + +/* Inter-Area-Prefix-LSA */ +struct ospf6_inter_prefix_lsa +{ + u_int32_t metric; + struct ospf6_prefix prefix; +}; + +/* Inter-Area-Router-LSA */ +struct ospf6_inter_router_lsa +{ + u_char mbz; + u_char options[3]; + u_int32_t metric; + u_int32_t router_id; +}; + +#define OSPF6_ABR_SUMMARY_METRIC(E) (ntohl ((E)->metric & htonl (0x00ffffff))) +#define OSPF6_ABR_SUMMARY_METRIC_SET(E,C) \ + { (E)->metric &= htonl (0x00000000); \ + (E)->metric |= htonl (0x00ffffff) & htonl (C); } + +int ospf6_is_router_abr (struct ospf6 *o); + +void ospf6_abr_enable_area (struct ospf6_area *oa); +void ospf6_abr_disable_area (struct ospf6_area *oa); + +void ospf6_abr_originate_summary_to_area (struct ospf6_route *route, + struct ospf6_area *area); +void ospf6_abr_originate_summary (struct ospf6_route *route); +void ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa); +void ospf6_abr_examin_brouter (u_int32_t router_id); +void ospf6_abr_reimport (struct ospf6_area *oa); + +int config_write_ospf6_debug_abr (struct vty *vty); +void install_element_ospf6_debug_abr (); +int ospf6_abr_config_write (struct vty *vty); + +void ospf6_abr_init (); + +#endif /*OSPF6_ABR_H*/ + + diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c new file mode 100644 index 0000000..f4cb039 --- /dev/null +++ b/ospf6d/ospf6_area.c @@ -0,0 +1,782 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "memory.h" +#include "linklist.h" +#include "thread.h" +#include "vty.h" +#include "command.h" +#include "if.h" +#include "prefix.h" +#include "table.h" +#include "plist.h" +#include "filter.h" + +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_route.h" +#include "ospf6_spf.h" +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_intra.h" +#include "ospf6_abr.h" +#include "ospf6d.h" + +int +ospf6_area_cmp (void *va, void *vb) +{ + struct ospf6_area *oa = (struct ospf6_area *) va; + struct ospf6_area *ob = (struct ospf6_area *) vb; + return (ntohl (oa->area_id) < ntohl (ob->area_id) ? -1 : 1); +} + +/* schedule routing table recalculation */ +void +ospf6_area_lsdb_hook_add (struct ospf6_lsa *lsa) +{ + switch (ntohs (lsa->header->type)) + { + case OSPF6_LSTYPE_ROUTER: + case OSPF6_LSTYPE_NETWORK: + if (IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type)) + { + zlog_info ("Examin %s", lsa->name); + zlog_info ("Schedule SPF Calculation for %s", + OSPF6_AREA (lsa->lsdb->data)->name); + } + ospf6_spf_schedule (OSPF6_AREA (lsa->lsdb->data)); + break; + + case OSPF6_LSTYPE_INTRA_PREFIX: + ospf6_intra_prefix_lsa_add (lsa); + break; + + case OSPF6_LSTYPE_INTER_PREFIX: + case OSPF6_LSTYPE_INTER_ROUTER: + ospf6_abr_examin_summary (lsa, (struct ospf6_area *) lsa->lsdb->data); + break; + + default: + break; + } +} + +void +ospf6_area_lsdb_hook_remove (struct ospf6_lsa *lsa) +{ + switch (ntohs (lsa->header->type)) + { + case OSPF6_LSTYPE_ROUTER: + case OSPF6_LSTYPE_NETWORK: + if (IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type)) + { + zlog_info ("LSA disappearing: %s", lsa->name); + zlog_info ("Schedule SPF Calculation for %s", + OSPF6_AREA (lsa->lsdb->data)->name); + } + ospf6_spf_schedule (OSPF6_AREA (lsa->lsdb->data)); + break; + + case OSPF6_LSTYPE_INTRA_PREFIX: + ospf6_intra_prefix_lsa_remove (lsa); + break; + + case OSPF6_LSTYPE_INTER_PREFIX: + case OSPF6_LSTYPE_INTER_ROUTER: + ospf6_abr_examin_summary (lsa, (struct ospf6_area *) lsa->lsdb->data); + break; + + default: + break; + } +} + +void +ospf6_area_route_hook_add (struct ospf6_route *route) +{ + struct ospf6_route *copy = ospf6_route_copy (route); + ospf6_route_add (copy, ospf6->route_table); +} + +void +ospf6_area_route_hook_remove (struct ospf6_route *route) +{ + struct ospf6_route *copy; + + copy = ospf6_route_lookup_identical (route, ospf6->route_table); + if (copy) + ospf6_route_remove (copy, ospf6->route_table); +} + +/* Make new area structure */ +struct ospf6_area * +ospf6_area_create (u_int32_t area_id, struct ospf6 *o) +{ + struct ospf6_area *oa; + struct ospf6_route *route; + + oa = XCALLOC (MTYPE_OSPF6_AREA, sizeof (struct ospf6_area)); + + inet_ntop (AF_INET, &area_id, oa->name, sizeof (oa->name)); + oa->area_id = area_id; + oa->if_list = list_new (); + + oa->lsdb = ospf6_lsdb_create (oa); + oa->lsdb->hook_add = ospf6_area_lsdb_hook_add; + oa->lsdb->hook_remove = ospf6_area_lsdb_hook_remove; + oa->lsdb_self = ospf6_lsdb_create (oa); + + oa->spf_table = ospf6_route_table_create (); + oa->route_table = ospf6_route_table_create (); + oa->route_table->hook_add = ospf6_area_route_hook_add; + oa->route_table->hook_remove = ospf6_area_route_hook_remove; + + oa->range_table = ospf6_route_table_create (); + oa->summary_prefix = ospf6_route_table_create (); + oa->summary_router = ospf6_route_table_create (); + + /* set default options */ + OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6); + OSPF6_OPT_SET (oa->options, OSPF6_OPT_E); + OSPF6_OPT_SET (oa->options, OSPF6_OPT_R); + + oa->ospf6 = o; + listnode_add_sort (o->area_list, oa); + + /* import athoer area's routes as inter-area routes */ + for (route = ospf6_route_head (o->route_table); route; + route = ospf6_route_next (route)) + ospf6_abr_originate_summary_to_area (route, oa); + + return oa; +} + +void +ospf6_area_delete (struct ospf6_area *oa) +{ + listnode n; + struct ospf6_interface *oi; + + ospf6_route_table_delete (oa->range_table); + ospf6_route_table_delete (oa->summary_prefix); + ospf6_route_table_delete (oa->summary_router); + + /* ospf6 interface list */ + for (n = listhead (oa->if_list); n; nextnode (n)) + { + oi = (struct ospf6_interface *) getdata (n); + ospf6_interface_delete (oi); + } + list_delete (oa->if_list); + + ospf6_lsdb_delete (oa->lsdb); + ospf6_lsdb_delete (oa->lsdb_self); + + ospf6_route_table_delete (oa->spf_table); + ospf6_route_table_delete (oa->route_table); + +#if 0 + ospf6_spftree_delete (oa->spf_tree); + ospf6_route_table_delete (oa->topology_table); +#endif /*0*/ + + THREAD_OFF (oa->thread_spf_calculation); + THREAD_OFF (oa->thread_route_calculation); + + listnode_delete (oa->ospf6->area_list, oa); + oa->ospf6 = NULL; + + /* free area */ + XFREE (MTYPE_OSPF6_AREA, oa); +} + +struct ospf6_area * +ospf6_area_lookup (u_int32_t area_id, struct ospf6 *ospf6) +{ + struct ospf6_area *oa; + listnode n; + + for (n = listhead (ospf6->area_list); n; nextnode (n)) + { + oa = (struct ospf6_area *) getdata (n); + if (oa->area_id == area_id) + return oa; + } + + return (struct ospf6_area *) NULL; +} + +struct ospf6_area * +ospf6_area_get (u_int32_t area_id, struct ospf6 *o) +{ + struct ospf6_area *oa; + oa = ospf6_area_lookup (area_id, o); + if (oa == NULL) + oa = ospf6_area_create (area_id, o); + return oa; +} + +void +ospf6_area_enable (struct ospf6_area *oa) +{ + listnode i; + struct ospf6_interface *oi; + + SET_FLAG (oa->flag, OSPF6_AREA_ENABLE); + + for (i = listhead (oa->if_list); i; nextnode (i)) + { + oi = (struct ospf6_interface *) getdata (i); + ospf6_interface_enable (oi); + } +} + +void +ospf6_area_disable (struct ospf6_area *oa) +{ + listnode i; + struct ospf6_interface *oi; + + UNSET_FLAG (oa->flag, OSPF6_AREA_ENABLE); + + for (i = listhead (oa->if_list); i; nextnode (i)) + { + oi = (struct ospf6_interface *) getdata (i); + ospf6_interface_disable (oi); + } +} + + +void +ospf6_area_show (struct vty *vty, struct ospf6_area *oa) +{ + listnode i; + struct ospf6_interface *oi; + + vty_out (vty, " Area %s%s", oa->name, VNL); + vty_out (vty, " Number of Area scoped LSAs is %u%s", + oa->lsdb->count, VNL); + + vty_out (vty, " Interface attached to this area:"); + for (i = listhead (oa->if_list); i; nextnode (i)) + { + oi = (struct ospf6_interface *) getdata (i); + vty_out (vty, " %s", oi->interface->name); + } + vty_out (vty, "%s", VNL); +} + + +#define OSPF6_CMD_AREA_LOOKUP(str, oa) \ +{ \ + u_int32_t area_id = 0; \ + if (inet_pton (AF_INET, str, &area_id) != 1) \ + { \ + vty_out (vty, "Malformed Area-ID: %s%s", str, VNL); \ + return CMD_SUCCESS; \ + } \ + oa = ospf6_area_lookup (area_id, ospf6); \ + if (oa == NULL) \ + { \ + vty_out (vty, "No such Area: %s%s", str, VNL); \ + return CMD_SUCCESS; \ + } \ +} + +#define OSPF6_CMD_AREA_GET(str, oa) \ +{ \ + u_int32_t area_id = 0; \ + if (inet_pton (AF_INET, str, &area_id) != 1) \ + { \ + vty_out (vty, "Malformed Area-ID: %s%s", str, VNL); \ + return CMD_SUCCESS; \ + } \ + oa = ospf6_area_get (area_id, ospf6); \ +} + +DEFUN (area_range, + area_range_cmd, + "area A.B.C.D range X:X::X:X/M", + "OSPF area parameters\n" + OSPF6_AREA_ID_STR + "Configured address range\n" + "Specify IPv6 prefix\n" + ) +{ + int ret; + struct ospf6_area *oa; + struct prefix prefix; + struct ospf6_route *range; + + OSPF6_CMD_AREA_GET (argv[0], oa); + argc--; + argv++; + + ret = str2prefix (argv[0], &prefix); + if (ret != 1 || prefix.family != AF_INET6) + { + vty_out (vty, "Malformed argument: %s%s", argv[0], VNL); + return CMD_SUCCESS; + } + argc--; + argv++; + + range = ospf6_route_lookup (&prefix, oa->range_table); + if (range == NULL) + { + range = ospf6_route_create (); + range->type = OSPF6_DEST_TYPE_RANGE; + range->prefix = prefix; + } + + if (argc) + { + if (! strcmp (argv[0], "not-advertise")) + SET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE); + else if (! strcmp (argv[0], "advertise")) + UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE); + } + + ospf6_route_add (range, oa->range_table); + return CMD_SUCCESS; +} + +ALIAS (area_range, + area_range_advertise_cmd, + "area A.B.C.D range X:X::X:X/M (advertise|not-advertise)", + "OSPF area parameters\n" + OSPF6_AREA_ID_STR + "Configured address range\n" + "Specify IPv6 prefix\n" + ); + +DEFUN (no_area_range, + no_area_range_cmd, + "no area A.B.C.D range X:X::X:X/M", + "OSPF area parameters\n" + OSPF6_AREA_ID_STR + "Configured address range\n" + "Specify IPv6 prefix\n" + ) +{ + int ret; + struct ospf6_area *oa; + struct prefix prefix; + struct ospf6_route *range; + + OSPF6_CMD_AREA_GET (argv[0], oa); + argc--; + argv++; + + ret = str2prefix (argv[0], &prefix); + if (ret != 1 || prefix.family != AF_INET6) + { + vty_out (vty, "Malformed argument: %s%s", argv[0], VNL); + return CMD_SUCCESS; + } + + range = ospf6_route_lookup (&prefix, oa->range_table); + if (range == NULL) + { + vty_out (vty, "Range %s does not exists.%s", argv[0], VNL); + return CMD_SUCCESS; + } + + ospf6_route_remove (range, oa->range_table); + return CMD_SUCCESS; +} + +void +ospf6_area_config_write (struct vty *vty) +{ + listnode node; + struct ospf6_area *oa; + struct ospf6_route *range; + char buf[128]; + + for (node = listhead (ospf6->area_list); node; nextnode (node)) + { + oa = OSPF6_AREA (getdata (node)); + + for (range = ospf6_route_head (oa->range_table); range; + range = ospf6_route_next (range)) + { + prefix2str (&range->prefix, buf, sizeof (buf)); + vty_out (vty, " area %s range %s%s", oa->name, buf, VNL); + } + } +} + +DEFUN (area_filter_list, + area_filter_list_cmd, + "area A.B.C.D filter-list prefix WORD (in|out)", + "OSPFv6 area parameters\n" + "OSPFv6 area ID in IP address format\n" + "Filter networks between OSPFv6 areas\n" + "Filter prefixes between OSPFv6 areas\n" + "Name of an IPv6 prefix-list\n" + "Filter networks sent to this area\n" + "Filter networks sent from this area\n") +{ + struct ospf6_area *area; + struct prefix_list *plist; + + OSPF6_CMD_AREA_GET (argv[0], area); + argc--; + argv++; + + plist = prefix_list_lookup (AFI_IP6, argv[1]); + if (strncmp (argv[2], "in", 2) == 0) + { + PREFIX_LIST_IN (area) = plist; + if (PREFIX_NAME_IN (area)) + free (PREFIX_NAME_IN (area)); + + PREFIX_NAME_IN (area) = strdup (argv[1]); + ospf6_abr_reimport (area); + } + else + { + PREFIX_LIST_OUT (area) = plist; + if (PREFIX_NAME_OUT (area)) + free (PREFIX_NAME_OUT (area)); + + PREFIX_NAME_OUT (area) = strdup (argv[1]); + ospf6_abr_enable_area (area); + } + + return CMD_SUCCESS; +} + +DEFUN (no_area_filter_list, + no_area_filter_list_cmd, + "no area A.B.C.D filter-list prefix WORD (in|out)", + NO_STR + "OSPFv6 area parameters\n" + "OSPFv6 area ID in IP address format\n" + "Filter networks between OSPFv6 areas\n" + "Filter prefixes between OSPFv6 areas\n" + "Name of an IPv6 prefix-list\n" + "Filter networks sent to this area\n" + "Filter networks sent from this area\n") +{ + struct ospf6_area *area; + struct prefix_list *plist; + + OSPF6_CMD_AREA_GET (argv[0], area); + argc--; + argv++; + + plist = prefix_list_lookup (AFI_IP6, argv[1]); + if (strncmp (argv[2], "in", 2) == 0) + { + if (PREFIX_NAME_IN (area)) + if (strcmp (PREFIX_NAME_IN (area), argv[1]) != 0) + return CMD_SUCCESS; + + PREFIX_LIST_IN (area) = NULL; + if (PREFIX_NAME_IN (area)) + free (PREFIX_NAME_IN (area)); + + PREFIX_NAME_IN (area) = NULL; + ospf6_abr_reimport (area); + } + else + { + if (PREFIX_NAME_OUT (area)) + if (strcmp (PREFIX_NAME_OUT (area), argv[1]) != 0) + return CMD_SUCCESS; + + PREFIX_LIST_OUT (area) = NULL; + if (PREFIX_NAME_OUT (area)) + free (PREFIX_NAME_OUT (area)); + + PREFIX_NAME_OUT (area) = NULL; + ospf6_abr_enable_area (area); + } + + return CMD_SUCCESS; +} + +DEFUN (area_import_list, + area_import_list_cmd, + "area A.B.C.D import-list NAME", + "OSPFv6 area parameters\n" + "OSPFv6 area ID in IP address format\n" + "Set the filter for networks from other areas announced to the specified one\n" + "Name of the acess-list\n") +{ + struct ospf6_area *area; + struct access_list *list; + + OSPF6_CMD_AREA_GET(argv[0], area); + + list = access_list_lookup (AFI_IP6, argv[1]); + + IMPORT_LIST (area) = list; + + if (IMPORT_NAME (area)) + free (IMPORT_NAME (area)); + + IMPORT_NAME (area) = strdup (argv[1]); + ospf6_abr_reimport (area); + + return CMD_SUCCESS; +} + +DEFUN (no_area_import_list, + no_area_import_list_cmd, + "no area A.B.C.D import-list NAME", + "OSPFv6 area parameters\n" + "OSPFv6 area ID in IP address format\n" + "Unset the filter for networks announced to other areas\n" + "NAme of the access-list\n") +{ + struct ospf6_area *area; + + OSPF6_CMD_AREA_GET(argv[0], area); + + IMPORT_LIST (area) = 0; + + if (IMPORT_NAME (area)) + free (IMPORT_NAME (area)); + + IMPORT_NAME (area) = NULL; + ospf6_abr_reimport (area); + + return CMD_SUCCESS; +} + +DEFUN (area_export_list, + area_export_list_cmd, + "area A.B.C.D export-list NAME", + "OSPFv6 area parameters\n" + "OSPFv6 area ID in IP address format\n" + "Set the filter for networks announced to other areas\n" + "Name of the acess-list\n") +{ + struct ospf6_area *area; + struct access_list *list; + + OSPF6_CMD_AREA_GET(argv[0], area); + + list = access_list_lookup (AFI_IP6, argv[1]); + + EXPORT_LIST (area) = list; + + if (EXPORT_NAME (area)) + free (EXPORT_NAME (area)); + + EXPORT_NAME (area) = strdup (argv[1]); + ospf6_abr_enable_area (area); + + return CMD_SUCCESS; +} + +DEFUN (no_area_export_list, + no_area_export_list_cmd, + "no area A.B.C.D export-list NAME", + "OSPFv6 area parameters\n" + "OSPFv6 area ID in IP address format\n" + "Unset the filter for networks announced to other areas\n" + "Name of the access-list\n") +{ + struct ospf6_area *area; + + OSPF6_CMD_AREA_GET(argv[0], area); + + EXPORT_LIST (area) = 0; + + if (EXPORT_NAME (area)) + free (EXPORT_NAME (area)); + + EXPORT_NAME (area) = NULL; + ospf6_abr_enable_area (area); + + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_ospf6_spf_tree, + show_ipv6_ospf6_spf_tree_cmd, + "show ipv6 ospf6 spf tree", + SHOW_STR + IP6_STR + OSPF6_STR + "Shortest Path First caculation\n" + "Show SPF tree\n") +{ + listnode node; + struct ospf6_area *oa; + struct ospf6_vertex *root; + struct ospf6_route *route; + struct prefix prefix; + + ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix); + for (node = listhead (ospf6->area_list); node; nextnode (node)) + { + oa = (struct ospf6_area *) getdata (node); + route = ospf6_route_lookup (&prefix, oa->spf_table); + if (route == NULL) + { + vty_out (vty, "LS entry for root not found in area %s%s", + oa->name, VNL); + continue; + } + root = (struct ospf6_vertex *) route->route_option; + ospf6_spf_display_subtree (vty, "", 0, root); + } + + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_ospf6_area_spf_tree, + show_ipv6_ospf6_area_spf_tree_cmd, + "show ipv6 ospf6 area A.B.C.D spf tree", + SHOW_STR + IP6_STR + OSPF6_STR + OSPF6_AREA_STR + OSPF6_AREA_ID_STR + "Shortest Path First caculation\n" + "Show SPF tree\n") +{ + u_int32_t area_id; + struct ospf6_area *oa; + struct ospf6_vertex *root; + struct ospf6_route *route; + struct prefix prefix; + + ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix); + + if (inet_pton (AF_INET, argv[0], &area_id) != 1) + { + vty_out (vty, "Malformed Area-ID: %s%s", argv[0], VNL); + return CMD_SUCCESS; + } + oa = ospf6_area_lookup (area_id, ospf6); + if (oa == NULL) + { + vty_out (vty, "No such Area: %s%s", argv[0], VNL); + return CMD_SUCCESS; + } + + route = ospf6_route_lookup (&prefix, oa->spf_table); + if (route == NULL) + { + vty_out (vty, "LS entry for root not found in area %s%s", + oa->name, VNL); + return CMD_SUCCESS; + } + root = (struct ospf6_vertex *) route->route_option; + ospf6_spf_display_subtree (vty, "", 0, root); + + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_ospf6_simulate_spf_tree_root, + show_ipv6_ospf6_simulate_spf_tree_root_cmd, + "show ipv6 ospf6 simulate spf-tree A.B.C.D area A.B.C.D", + SHOW_STR + IP6_STR + OSPF6_STR + "Shortest Path First caculation\n" + "Show SPF tree\n" + "Specify root's router-id to calculate another router's SPF tree\n") +{ + u_int32_t area_id; + struct ospf6_area *oa; + struct ospf6_vertex *root; + struct ospf6_route *route; + struct prefix prefix; + u_int32_t router_id; + struct ospf6_route_table *spf_table; + unsigned char tmp_debug_ospf6_spf = 0; + + inet_pton (AF_INET, argv[0], &router_id); + ospf6_linkstate_prefix (router_id, htonl (0), &prefix); + + if (inet_pton (AF_INET, argv[1], &area_id) != 1) + { + vty_out (vty, "Malformed Area-ID: %s%s", argv[1], VNL); + return CMD_SUCCESS; + } + oa = ospf6_area_lookup (area_id, ospf6); + if (oa == NULL) + { + vty_out (vty, "No such Area: %s%s", argv[1], VNL); + return CMD_SUCCESS; + } + + tmp_debug_ospf6_spf = conf_debug_ospf6_spf; + conf_debug_ospf6_spf = 0; + + spf_table = ospf6_route_table_create (); + ospf6_spf_calculation (router_id, spf_table, oa); + + conf_debug_ospf6_spf = tmp_debug_ospf6_spf; + + route = ospf6_route_lookup (&prefix, spf_table); + if (route == NULL) + { + ospf6_spf_table_finish (spf_table); + ospf6_route_table_delete (spf_table); + return CMD_SUCCESS; + } + root = (struct ospf6_vertex *) route->route_option; + ospf6_spf_display_subtree (vty, "", 0, root); + + ospf6_spf_table_finish (spf_table); + ospf6_route_table_delete (spf_table); + + return CMD_SUCCESS; +} + +void +ospf6_area_init () +{ + install_element (VIEW_NODE, &show_ipv6_ospf6_spf_tree_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd); + + install_element (ENABLE_NODE, &show_ipv6_ospf6_spf_tree_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd); + + install_element (OSPF6_NODE, &area_range_cmd); + install_element (OSPF6_NODE, &area_range_advertise_cmd); + install_element (OSPF6_NODE, &no_area_range_cmd); + + install_element (OSPF6_NODE, &area_import_list_cmd); + install_element (OSPF6_NODE, &no_area_import_list_cmd); + install_element (OSPF6_NODE, &area_export_list_cmd); + install_element (OSPF6_NODE, &no_area_export_list_cmd); + + install_element (OSPF6_NODE, &area_filter_list_cmd); + install_element (OSPF6_NODE, &no_area_filter_list_cmd); + +} + + diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h new file mode 100644 index 0000000..eac2fd4 --- /dev/null +++ b/ospf6d/ospf6_area.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF_AREA_H +#define OSPF_AREA_H + +#include "ospf6_top.h" + +struct ospf6_area +{ + /* Reference to Top data structure */ + struct ospf6 *ospf6; + + /* Area-ID */ + u_int32_t area_id; + + /* Area-ID string */ + char name[16]; + + /* flag */ + u_char flag; + + /* OSPF Option */ + u_char options[3]; + + /* Summary routes to be originated (includes Configured Address Ranges) */ + struct ospf6_route_table *range_table; + struct ospf6_route_table *summary_prefix; + struct ospf6_route_table *summary_router; + + /* OSPF interface list */ + list if_list; + + struct ospf6_lsdb *lsdb; + struct ospf6_lsdb *lsdb_self; + + struct ospf6_route_table *spf_table; + struct ospf6_route_table *route_table; + + struct thread *thread_spf_calculation; + struct thread *thread_route_calculation; + + struct thread *thread_router_lsa; + struct thread *thread_intra_prefix_lsa; + u_int32_t router_lsa_size_limit; + + /* Area announce list */ + struct + { + char *name; + struct access_list *list; + } export; +#define EXPORT_NAME(A) (A)->export.name +#define EXPORT_LIST(A) (A)->export.list + + /* Area acceptance list */ + struct + { + char *name; + struct access_list *list; + } import; +#define IMPORT_NAME(A) (A)->import.name +#define IMPORT_LIST(A) (A)->import.list + + /* Type 3 LSA Area prefix-list */ + struct + { + char *name; + struct prefix_list *list; + } plist_in; +#define PREFIX_NAME_IN(A) (A)->plist_in.name +#define PREFIX_LIST_IN(A) (A)->plist_in.list + + struct + { + char *name; + struct prefix_list *list; + } plist_out; +#define PREFIX_NAME_OUT(A) (A)->plist_out.name +#define PREFIX_LIST_OUT(A) (A)->plist_out.list + +}; + +#define OSPF6_AREA_ENABLE 0x01 +#define OSPF6_AREA_ACTIVE 0x02 +#define OSPF6_AREA_TRANSIT 0x04 /* TransitCapability */ +#define OSPF6_AREA_STUB 0x08 + +#define BACKBONE_AREA_ID (htonl (0)) +#define IS_AREA_BACKBONE(oa) ((oa)->area_id == BACKBONE_AREA_ID) +#define IS_AREA_ENABLED(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ENABLE)) +#define IS_AREA_ACTIVE(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ACTIVE)) +#define IS_AREA_TRANSIT(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_TRANSIT)) +#define IS_AREA_STUB(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_STUB)) + +/* prototypes */ +int ospf6_area_cmp (void *va, void *vb); + +struct ospf6_area *ospf6_area_create (u_int32_t, struct ospf6 *); +void ospf6_area_delete (struct ospf6_area *); +struct ospf6_area *ospf6_area_lookup (u_int32_t, struct ospf6 *); + +void ospf6_area_enable (struct ospf6_area *); +void ospf6_area_disable (struct ospf6_area *); + +void ospf6_area_show (struct vty *, struct ospf6_area *); + +void ospf6_area_config_write (struct vty *vty); +void ospf6_area_init (); + +#endif /* OSPF_AREA_H */ + diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c new file mode 100644 index 0000000..49bba79 --- /dev/null +++ b/ospf6d/ospf6_asbr.c @@ -0,0 +1,1300 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "memory.h" +#include "prefix.h" +#include "command.h" +#include "vty.h" +#include "routemap.h" +#include "table.h" +#include "plist.h" +#include "thread.h" +#include "linklist.h" + +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_route.h" +#include "ospf6_zebra.h" +#include "ospf6_message.h" + +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" +#include "ospf6_asbr.h" +#include "ospf6_intra.h" +#include "ospf6_flood.h" +#include "ospf6d.h" + +unsigned char conf_debug_ospf6_asbr = 0; + +char *zroute_name[] = +{ "system", "kernel", "connected", "static", + "rip", "ripng", "ospf", "ospf6", "bgp", "unknown" }; + +char *zroute_abname[] = +{ "X", "K", "C", "S", "R", "R", "O", "O", "B", "?" }; + +#define ZROUTE_NAME(x) \ + (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? zroute_name[(x)] : \ + zroute_name[ZEBRA_ROUTE_MAX]) +#define ZROUTE_ABNAME(x) \ + (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? zroute_abname[(x)] : \ + zroute_abname[ZEBRA_ROUTE_MAX]) + +/* AS External LSA origination */ +void +ospf6_as_external_lsa_originate (struct ospf6_route *route) +{ + char buffer[OSPF6_MAX_LSASIZE]; + struct ospf6_lsa_header *lsa_header; + struct ospf6_lsa *old, *lsa; + + struct ospf6_as_external_lsa *as_external_lsa; + char buf[64]; + caddr_t p; + + /* find previous LSA */ + old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_AS_EXTERNAL), + route->path.origin.id, ospf6->router_id, + ospf6->lsdb); + + if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE (AS_EXTERNAL)) + { + prefix2str (&route->prefix, buf, sizeof (buf)); + zlog_info ("Originate AS-External-LSA for %s", buf); + } + + /* prepare buffer */ + memset (buffer, 0, sizeof (buffer)); + lsa_header = (struct ospf6_lsa_header *) buffer; + as_external_lsa = (struct ospf6_as_external_lsa *) + ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); + p = (caddr_t) + ((caddr_t) as_external_lsa + sizeof (struct ospf6_as_external_lsa)); + + /* Fill AS-External-LSA */ + /* Metric type */ + if (route->path.metric_type == 2) + SET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E); + else + UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E); + + /* forwarding address */ + if (! IN6_IS_ADDR_UNSPECIFIED (&route->nexthop[0].address)) + SET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F); + else + UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F); + + /* external route tag */ + UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T); + + /* Set metric */ + OSPF6_ASBR_METRIC_SET (as_external_lsa, route->path.cost); + + /* prefixlen */ + as_external_lsa->prefix.prefix_length = route->prefix.prefixlen; + + /* PrefixOptions */ + as_external_lsa->prefix.prefix_options = route->path.prefix_options; + + /* don't use refer LS-type */ + as_external_lsa->prefix.prefix_refer_lstype = htons (0); + + /* set Prefix */ + memcpy (p, &route->prefix.u.prefix6, + OSPF6_PREFIX_SPACE (route->prefix.prefixlen)); + ospf6_prefix_apply_mask (&as_external_lsa->prefix); + p += OSPF6_PREFIX_SPACE (route->prefix.prefixlen); + + /* Forwarding address */ + if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F)) + { + memcpy (p, &route->nexthop[0].address, sizeof (struct in6_addr)); + p += sizeof (struct in6_addr); + } + + /* External Route Tag */ + if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) + { + /* xxx */ + } + + /* Fill LSA Header */ + lsa_header->age = 0; + lsa_header->type = htons (OSPF6_LSTYPE_AS_EXTERNAL); + lsa_header->id = route->path.origin.id; + lsa_header->adv_router = ospf6->router_id; + lsa_header->seqnum = + ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, + lsa_header->adv_router, ospf6->lsdb); + lsa_header->length = htons ((caddr_t) p - (caddr_t) lsa_header); + + /* LSA checksum */ + ospf6_lsa_checksum (lsa_header); + + /* create LSA */ + lsa = ospf6_lsa_create (lsa_header); + + /* Originate */ + ospf6_lsa_originate_process (lsa, ospf6); +} + + +void +ospf6_asbr_lsa_add (struct ospf6_lsa *lsa) +{ + struct ospf6_as_external_lsa *external; + struct prefix asbr_id; + struct ospf6_route *asbr_entry, *route; + char buf[64]; + int i; + + external = (struct ospf6_as_external_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); + + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + zlog_info ("Calculate AS-External route for %s", lsa->name); + + if (lsa->header->adv_router == ospf6->router_id) + { + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + zlog_info ("Ignore self-originated AS-External-LSA"); + return; + } + + if (OSPF6_ASBR_METRIC (external) == LS_INFINITY) + { + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + zlog_info ("Ignore LSA with LSInfinity Metric"); + return; + } + + ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &asbr_id); + asbr_entry = ospf6_route_lookup (&asbr_id, ospf6->brouter_table); + if (asbr_entry == NULL || + ! CHECK_FLAG (asbr_entry->path.router_bits, OSPF6_ROUTER_BIT_E)) + { + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + { + prefix2str (&asbr_id, buf, sizeof (buf)); + zlog_info ("ASBR entry not found: %s", buf); + } + return; + } + + route = ospf6_route_create (); + route->type = OSPF6_DEST_TYPE_NETWORK; + route->prefix.family = AF_INET6; + route->prefix.prefixlen = external->prefix.prefix_length; + ospf6_prefix_in6_addr (&route->prefix.u.prefix6, &external->prefix); + + route->path.area_id = asbr_entry->path.area_id; + route->path.origin.type = lsa->header->type; + route->path.origin.id = lsa->header->id; + route->path.origin.adv_router = lsa->header->adv_router; + + route->path.prefix_options = external->prefix.prefix_options; + if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E)) + { + route->path.type = OSPF6_PATH_TYPE_EXTERNAL2; + route->path.metric_type = 2; + route->path.cost = asbr_entry->path.cost; + route->path.cost_e2 = OSPF6_ASBR_METRIC (external); + } + else + { + route->path.type = OSPF6_PATH_TYPE_EXTERNAL1; + route->path.metric_type = 1; + route->path.cost = asbr_entry->path.cost + OSPF6_ASBR_METRIC (external); + route->path.cost_e2 = 0; + } + + for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) + ospf6_nexthop_copy (&route->nexthop[i], &asbr_entry->nexthop[i]); + + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + { + prefix2str (&route->prefix, buf, sizeof (buf)); + zlog_info ("AS-External route add: %s", buf); + } + + ospf6_route_add (route, ospf6->route_table); +} + +void +ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa) +{ + struct ospf6_as_external_lsa *external; + struct prefix prefix; + struct ospf6_route *route; + char buf[64]; + + external = (struct ospf6_as_external_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); + + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + zlog_info ("Withdraw AS-External route for %s", lsa->name); + + if (lsa->header->adv_router == ospf6->router_id) + { + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + zlog_info ("Ignore self-originated AS-External-LSA"); + return; + } + + memset (&prefix, 0, sizeof (struct prefix)); + prefix.family = AF_INET6; + prefix.prefixlen = external->prefix.prefix_length; + ospf6_prefix_in6_addr (&prefix.u.prefix6, &external->prefix); + + route = ospf6_route_lookup (&prefix, ospf6->route_table); + if (route == NULL) + { + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + { + prefix2str (&prefix, buf, sizeof (buf)); + zlog_info ("AS-External route %s not found", buf); + } + return; + } + + for (ospf6_route_lock (route); + route && ospf6_route_is_prefix (&prefix, route); + route = ospf6_route_next (route)) + { + if (route->type != OSPF6_DEST_TYPE_NETWORK) + continue; + if (route->path.origin.type != lsa->header->type) + continue; + if (route->path.origin.id != lsa->header->id) + continue; + if (route->path.origin.adv_router != lsa->header->adv_router) + continue; + + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + { + prefix2str (&route->prefix, buf, sizeof (buf)); + zlog_info ("AS-External route remove: %s", buf); + } + ospf6_route_remove (route, ospf6->route_table); + } +} + +void +ospf6_asbr_lsentry_add (struct ospf6_route *asbr_entry) +{ + char buf[64]; + struct ospf6_lsa *lsa; + u_int16_t type; + u_int32_t router; + + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + { + ospf6_linkstate_prefix2str (&asbr_entry->prefix, buf, sizeof (buf)); + zlog_info ("New ASBR %s found", buf); + } + + type = htons (OSPF6_LSTYPE_AS_EXTERNAL); + router = ospf6_linkstate_prefix_adv_router (&asbr_entry->prefix); + for (lsa = ospf6_lsdb_type_router_head (type, router, ospf6->lsdb); + lsa; lsa = ospf6_lsdb_type_router_next (type, router, lsa)) + { + if (! OSPF6_LSA_IS_MAXAGE (lsa)) + ospf6_asbr_lsa_add (lsa); + } + + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + { + ospf6_linkstate_prefix2str (&asbr_entry->prefix, buf, sizeof (buf)); + zlog_info ("Calculation for new ASBR %s done", buf); + } +} + +void +ospf6_asbr_lsentry_remove (struct ospf6_route *asbr_entry) +{ + char buf[64]; + struct ospf6_lsa *lsa; + u_int16_t type; + u_int32_t router; + + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + { + ospf6_linkstate_prefix2str (&asbr_entry->prefix, buf, sizeof (buf)); + zlog_info ("ASBR %s disappeared", buf); + } + + type = htons (OSPF6_LSTYPE_AS_EXTERNAL); + router = ospf6_linkstate_prefix_adv_router (&asbr_entry->prefix); + for (lsa = ospf6_lsdb_type_router_head (type, router, ospf6->lsdb); + lsa; lsa = ospf6_lsdb_type_router_next (type, router, lsa)) + ospf6_asbr_lsa_remove (lsa); + + if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) + { + ospf6_linkstate_prefix2str (&asbr_entry->prefix, buf, sizeof (buf)); + zlog_info ("Calculation for old ASBR %s done", buf); + } +} + + + +/* redistribute function */ + +void +ospf6_asbr_routemap_set (int type, char *mapname) +{ + if (ospf6->rmap[type].name) + free (ospf6->rmap[type].name); + ospf6->rmap[type].name = strdup (mapname); + ospf6->rmap[type].map = route_map_lookup_by_name (mapname); +} + +void +ospf6_asbr_routemap_unset (int type) +{ + if (ospf6->rmap[type].name) + free (ospf6->rmap[type].name); + ospf6->rmap[type].name = NULL; + ospf6->rmap[type].map = NULL; +} + +void +ospf6_asbr_routemap_update (char *mapname) +{ + int type; + + if (ospf6 == NULL) + return; + + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + { + if (ospf6->rmap[type].name) + ospf6->rmap[type].map = + route_map_lookup_by_name (ospf6->rmap[type].name); + else + ospf6->rmap[type].map = NULL; + } +} + +int +ospf6_asbr_is_asbr (struct ospf6 *o) +{ + return o->external_table->count; +} + +void +ospf6_asbr_redistribute_set (int type) +{ + ospf6_zebra_redistribute (type); +} + +void +ospf6_asbr_redistribute_unset (int type) +{ + struct ospf6_route *route; + struct ospf6_external_info *info; + + ospf6_zebra_no_redistribute (type); + + for (route = ospf6_route_head (ospf6->external_table); route; + route = ospf6_route_next (route)) + { + info = route->route_option; + if (info->type != type) + continue; + + ospf6_asbr_redistribute_remove (info->type, route->nexthop[0].ifindex, + &route->prefix); + } +} + +void +ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix, + u_int nexthop_num, struct in6_addr *nexthop) +{ + int ret; + struct ospf6_route troute; + struct ospf6_external_info tinfo; + struct ospf6_route *route, *match; + struct ospf6_external_info *info; + struct prefix prefix_id; + struct route_node *node; + char pbuf[64], ibuf[16]; + listnode lnode; + struct ospf6_area *oa; + + if (! ospf6_zebra_is_redistribute (type)) + return; + + if (IS_OSPF6_DEBUG_ASBR) + { + prefix2str (prefix, pbuf, sizeof (pbuf)); + zlog_info ("Redistribute %s (%s)", pbuf, ZROUTE_NAME (type)); + } + + /* if route-map was specified but not found, do not advertise */ + if (ospf6->rmap[type].name) + { + if (ospf6->rmap[type].map == NULL) + ospf6_asbr_routemap_update (NULL); + if (ospf6->rmap[type].map == NULL) + { + zlog_warn ("route-map \"%s\" not found, suppress redistributing", + ospf6->rmap[type].name); + return; + } + } + + /* apply route-map */ + if (ospf6->rmap[type].map) + { + memset (&troute, 0, sizeof (troute)); + memset (&tinfo, 0, sizeof (tinfo)); + troute.route_option = &tinfo; + + ret = route_map_apply (ospf6->rmap[type].map, prefix, + RMAP_OSPF6, &troute); + if (ret != RMAP_MATCH) + { + if (IS_OSPF6_DEBUG_ASBR) + zlog_info ("Denied by route-map \"%s\"", ospf6->rmap[type].name); + return; + } + } + + match = ospf6_route_lookup (prefix, ospf6->external_table); + if (match) + { + info = match->route_option; + + /* copy result of route-map */ + if (ospf6->rmap[type].map) + { + if (troute.path.metric_type) + match->path.metric_type = troute.path.metric_type; + if (troute.path.cost) + match->path.cost = troute.path.cost; + if (! IN6_IS_ADDR_UNSPECIFIED (&tinfo.forwarding)) + memcpy (&info->forwarding, &tinfo.forwarding, + sizeof (struct in6_addr)); + } + + info->type = type; + match->nexthop[0].ifindex = ifindex; + if (nexthop_num && nexthop) + memcpy (&match->nexthop[0].address, nexthop, sizeof (struct in6_addr)); + + /* create/update binding in external_id_table */ + prefix_id.family = AF_INET; + prefix_id.prefixlen = 32; + prefix_id.u.prefix4.s_addr = htonl (info->id); + node = route_node_get (ospf6->external_id_table, &prefix_id); + node->info = match; + + if (IS_OSPF6_DEBUG_ASBR) + { + inet_ntop (AF_INET, &prefix_id.u.prefix4, ibuf, sizeof (ibuf)); + zlog_info ("Advertise as AS-External Id:%s", ibuf); + } + + match->path.origin.id = htonl (info->id); + ospf6_as_external_lsa_originate (match); + return; + } + + /* create new entry */ + route = ospf6_route_create (); + route->type = OSPF6_DEST_TYPE_NETWORK; + memcpy (&route->prefix, prefix, sizeof (struct prefix)); + + info = (struct ospf6_external_info *) + XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO, sizeof (struct ospf6_external_info)); + memset (info, 0, sizeof (struct ospf6_external_info)); + route->route_option = info; + info->id = ospf6->external_id++; + + /* copy result of route-map */ + if (ospf6->rmap[type].map) + { + if (troute.path.metric_type) + route->path.metric_type = troute.path.metric_type; + if (troute.path.cost) + route->path.cost = troute.path.cost; + if (! IN6_IS_ADDR_UNSPECIFIED (&tinfo.forwarding)) + memcpy (&info->forwarding, &tinfo.forwarding, + sizeof (struct in6_addr)); + } + + info->type = type; + route->nexthop[0].ifindex = ifindex; + if (nexthop_num && nexthop) + memcpy (&route->nexthop[0].address, nexthop, sizeof (struct in6_addr)); + + /* create/update binding in external_id_table */ + prefix_id.family = AF_INET; + prefix_id.prefixlen = 32; + prefix_id.u.prefix4.s_addr = htonl (info->id); + node = route_node_get (ospf6->external_id_table, &prefix_id); + node->info = route; + + route = ospf6_route_add (route, ospf6->external_table); + route->route_option = info; + + if (IS_OSPF6_DEBUG_ASBR) + { + inet_ntop (AF_INET, &prefix_id.u.prefix4, ibuf, sizeof (ibuf)); + zlog_info ("Advertise as AS-External Id:%s", ibuf); + } + + route->path.origin.id = htonl (info->id); + ospf6_as_external_lsa_originate (route); + + /* Router-Bit (ASBR Flag) may have to be updated */ + for (lnode = listhead (ospf6->area_list); lnode; nextnode (lnode)) + { + oa = (struct ospf6_area *) getdata (lnode); + OSPF6_ROUTER_LSA_SCHEDULE (oa); + } +} + +void +ospf6_asbr_redistribute_remove (int type, int ifindex, struct prefix *prefix) +{ + struct ospf6_route *match; + struct ospf6_external_info *info = NULL; + struct route_node *node; + struct ospf6_lsa *lsa; + struct prefix prefix_id; + char pbuf[64], ibuf[16]; + listnode lnode; + struct ospf6_area *oa; + + match = ospf6_route_lookup (prefix, ospf6->external_table); + if (match == NULL) + { + if (IS_OSPF6_DEBUG_ASBR) + { + prefix2str (prefix, pbuf, sizeof (pbuf)); + zlog_info ("No such route %s to withdraw", pbuf); + } + return; + } + + info = match->route_option; + assert (info); + + if (info->type != type) + { + if (IS_OSPF6_DEBUG_ASBR) + { + prefix2str (prefix, pbuf, sizeof (pbuf)); + zlog_info ("Original protocol mismatch: %s", pbuf); + } + return; + } + + if (IS_OSPF6_DEBUG_ASBR) + { + prefix2str (prefix, pbuf, sizeof (pbuf)); + inet_ntop (AF_INET, &prefix_id.u.prefix4, ibuf, sizeof (ibuf)); + zlog_info ("Withdraw %s (AS-External Id:%s)", pbuf, ibuf); + } + + lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_AS_EXTERNAL), + htonl (info->id), ospf6->router_id, ospf6->lsdb); + if (lsa) + ospf6_lsa_purge (lsa); + + /* remove binding in external_id_table */ + prefix_id.family = AF_INET; + prefix_id.prefixlen = 32; + prefix_id.u.prefix4.s_addr = htonl (info->id); + node = route_node_lookup (ospf6->external_id_table, &prefix_id); + assert (node); + node->info = NULL; + route_unlock_node (node); + + ospf6_route_remove (match, ospf6->external_table); + XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info); + + /* Router-Bit (ASBR Flag) may have to be updated */ + for (lnode = listhead (ospf6->area_list); lnode; nextnode (lnode)) + { + oa = (struct ospf6_area *) getdata (lnode); + OSPF6_ROUTER_LSA_SCHEDULE (oa); + } +} + +DEFUN (ospf6_redistribute, + ospf6_redistribute_cmd, + "redistribute (static|kernel|connected|ripng|bgp)", + "Redistribute\n" + "Static route\n" + "Kernel route\n" + "Connected route\n" + "RIPng route\n" + "BGP route\n" + ) +{ + int type = 0; + + if (strncmp (argv[0], "sta", 3) == 0) + type = ZEBRA_ROUTE_STATIC; + else if (strncmp (argv[0], "ker", 3) == 0) + type = ZEBRA_ROUTE_KERNEL; + else if (strncmp (argv[0], "con", 3) == 0) + type = ZEBRA_ROUTE_CONNECT; + else if (strncmp (argv[0], "rip", 3) == 0) + type = ZEBRA_ROUTE_RIPNG; + else if (strncmp (argv[0], "bgp", 3) == 0) + type = ZEBRA_ROUTE_BGP; + + ospf6_asbr_redistribute_unset (type); + ospf6_asbr_routemap_unset (type); + ospf6_asbr_redistribute_set (type); + return CMD_SUCCESS; +} + +DEFUN (ospf6_redistribute_routemap, + ospf6_redistribute_routemap_cmd, + "redistribute (static|kernel|connected|ripng|bgp) route-map WORD", + "Redistribute\n" + "Static routes\n" + "Kernel route\n" + "Connected route\n" + "RIPng route\n" + "BGP route\n" + "Route map reference\n" + "Route map name\n" + ) +{ + int type = 0; + + if (strncmp (argv[0], "sta", 3) == 0) + type = ZEBRA_ROUTE_STATIC; + else if (strncmp (argv[0], "ker", 3) == 0) + type = ZEBRA_ROUTE_KERNEL; + else if (strncmp (argv[0], "con", 3) == 0) + type = ZEBRA_ROUTE_CONNECT; + else if (strncmp (argv[0], "rip", 3) == 0) + type = ZEBRA_ROUTE_RIPNG; + else if (strncmp (argv[0], "bgp", 3) == 0) + type = ZEBRA_ROUTE_BGP; + + ospf6_asbr_redistribute_unset (type); + ospf6_asbr_routemap_set (type, argv[1]); + ospf6_asbr_redistribute_set (type); + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_redistribute, + no_ospf6_redistribute_cmd, + "no redistribute (static|kernel|connected|ripng|bgp)", + NO_STR + "Redistribute\n" + "Static route\n" + "Kernel route\n" + "Connected route\n" + "RIPng route\n" + "BGP route\n" + ) +{ + int type = 0; + + if (strncmp (argv[0], "sta", 3) == 0) + type = ZEBRA_ROUTE_STATIC; + else if (strncmp (argv[0], "ker", 3) == 0) + type = ZEBRA_ROUTE_KERNEL; + else if (strncmp (argv[0], "con", 3) == 0) + type = ZEBRA_ROUTE_CONNECT; + else if (strncmp (argv[0], "rip", 3) == 0) + type = ZEBRA_ROUTE_RIPNG; + else if (strncmp (argv[0], "bgp", 3) == 0) + type = ZEBRA_ROUTE_BGP; + + ospf6_asbr_redistribute_unset (type); + ospf6_asbr_routemap_unset (type); + + return CMD_SUCCESS; +} + +int +ospf6_redistribute_config_write (struct vty *vty) +{ + int type; + + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + { + if (type == ZEBRA_ROUTE_OSPF6) + continue; + if (! ospf6_zebra_is_redistribute (type)) + continue; + + if (ospf6->rmap[type].name) + vty_out (vty, " redistribute %s route-map %s%s", + ZROUTE_NAME (type), ospf6->rmap[type].name, VNL); + else + vty_out (vty, " redistribute %s%s", + ZROUTE_NAME (type), VNL); + } + + return 0; +} + +void +ospf6_redistribute_show_config (struct vty *vty) +{ + int type; + int nroute[ZEBRA_ROUTE_MAX]; + int total; + struct ospf6_route *route; + struct ospf6_external_info *info; + + total = 0; + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + nroute[type] = 0; + for (route = ospf6_route_head (ospf6->external_table); route; + route = ospf6_route_next (route)) + { + info = route->route_option; + nroute[info->type]++; + total++; + } + + vty_out (vty, "Redistributing External Routes from:%s", VNL); + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + { + if (type == ZEBRA_ROUTE_OSPF6) + continue; + if (! ospf6_zebra_is_redistribute (type)) + continue; + + if (ospf6->rmap[type].name) + vty_out (vty, " %d: %s with route-map \"%s\"%s%s", nroute[type], + ZROUTE_NAME (type), ospf6->rmap[type].name, + (ospf6->rmap[type].map ? "" : " (not found !)"), + VNL); + else + vty_out (vty, " %d: %s%s", nroute[type], + ZROUTE_NAME (type), VNL); + } + vty_out (vty, "Total %d routes%s", total, VNL); +} + + + +/* Routemap Functions */ +route_map_result_t +ospf6_routemap_rule_match_address_prefixlist (void *rule, + struct prefix *prefix, + route_map_object_t type, + void *object) +{ + struct prefix_list *plist; + + if (type != RMAP_OSPF6) + return RMAP_NOMATCH; + + plist = prefix_list_lookup (AFI_IP6, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); +} + +void * +ospf6_routemap_rule_match_address_prefixlist_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +ospf6_routemap_rule_match_address_prefixlist_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd +ospf6_routemap_rule_match_address_prefixlist_cmd = +{ + "ipv6 address prefix-list", + ospf6_routemap_rule_match_address_prefixlist, + ospf6_routemap_rule_match_address_prefixlist_compile, + ospf6_routemap_rule_match_address_prefixlist_free, +}; + +route_map_result_t +ospf6_routemap_rule_set_metric_type (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + char *metric_type = rule; + struct ospf6_route *route = object; + + if (type != RMAP_OSPF6) + return RMAP_OKAY; + + if (strcmp (metric_type, "type-2") == 0) + route->path.metric_type = 2; + else + route->path.metric_type = 1; + + return RMAP_OKAY; +} + +void * +ospf6_routemap_rule_set_metric_type_compile (char *arg) +{ + if (strcmp (arg, "type-2") && strcmp (arg, "type-1")) + return NULL; + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +ospf6_routemap_rule_set_metric_type_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd +ospf6_routemap_rule_set_metric_type_cmd = +{ + "metric-type", + ospf6_routemap_rule_set_metric_type, + ospf6_routemap_rule_set_metric_type_compile, + ospf6_routemap_rule_set_metric_type_free, +}; + +route_map_result_t +ospf6_routemap_rule_set_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + char *metric = rule; + struct ospf6_route *route = object; + + if (type != RMAP_OSPF6) + return RMAP_OKAY; + + route->path.cost = atoi (metric); + return RMAP_OKAY; +} + +void * +ospf6_routemap_rule_set_metric_compile (char *arg) +{ + u_int32_t metric; + char *endp; + metric = strtoul (arg, &endp, 0); + if (metric > LS_INFINITY || *endp != '\0') + return NULL; + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +ospf6_routemap_rule_set_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd +ospf6_routemap_rule_set_metric_cmd = +{ + "metric", + ospf6_routemap_rule_set_metric, + ospf6_routemap_rule_set_metric_compile, + ospf6_routemap_rule_set_metric_free, +}; + +route_map_result_t +ospf6_routemap_rule_set_forwarding (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + char *forwarding = rule; + struct ospf6_route *route = object; + struct ospf6_external_info *info = route->route_option; + + if (type != RMAP_OSPF6) + return RMAP_OKAY; + + if (inet_pton (AF_INET6, forwarding, &info->forwarding) != 1) + { + memset (&info->forwarding, 0, sizeof (struct in6_addr)); + return RMAP_ERROR; + } + + return RMAP_OKAY; +} + +void * +ospf6_routemap_rule_set_forwarding_compile (char *arg) +{ + struct in6_addr a; + if (inet_pton (AF_INET6, arg, &a) != 1) + return NULL; + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +ospf6_routemap_rule_set_forwarding_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd +ospf6_routemap_rule_set_forwarding_cmd = +{ + "forwarding-address", + ospf6_routemap_rule_set_forwarding, + ospf6_routemap_rule_set_forwarding_compile, + ospf6_routemap_rule_set_forwarding_free, +}; + +int +route_map_command_status (struct vty *vty, int ret) +{ + if (! ret) + return CMD_SUCCESS; + + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "Can't find rule.%s", VNL); + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "Argument is malformed.%s", VNL); + break; + default: + vty_out (vty, "route-map add set failed.%s", VNL); + break; + } + return CMD_WARNING; +} + +/* add "match address" */ +DEFUN (ospf6_routemap_match_address_prefixlist, + ospf6_routemap_match_address_prefixlist_cmd, + "match ipv6 address prefix-list WORD", + "Match values\n" + IPV6_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IPv6 prefix-list name\n") +{ + int ret = route_map_add_match ((struct route_map_index *) vty->index, + "ipv6 address prefix-list", argv[0]); + return route_map_command_status (vty, ret); +} + +/* delete "match address" */ +DEFUN (ospf6_routemap_no_match_address_prefixlist, + ospf6_routemap_no_match_address_prefixlist_cmd, + "no match ipv6 address prefix-list WORD", + NO_STR + "Match values\n" + IPV6_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IPv6 prefix-list name\n") +{ + int ret = route_map_delete_match ((struct route_map_index *) vty->index, + "ipv6 address prefix-list", argv[0]); + return route_map_command_status (vty, ret); +} + +/* add "set metric-type" */ +DEFUN (ospf6_routemap_set_metric_type, + ospf6_routemap_set_metric_type_cmd, + "set metric-type (type-1|type-2)", + "Set value\n" + "Type of metric\n" + "OSPF6 external type 1 metric\n" + "OSPF6 external type 2 metric\n") +{ + int ret = route_map_add_set ((struct route_map_index *) vty->index, + "metric-type", argv[0]); + return route_map_command_status (vty, ret); +} + +/* delete "set metric-type" */ +DEFUN (ospf6_routemap_no_set_metric_type, + ospf6_routemap_no_set_metric_type_cmd, + "no set metric-type (type-1|type-2)", + NO_STR + "Set value\n" + "Type of metric\n" + "OSPF6 external type 1 metric\n" + "OSPF6 external type 2 metric\n") +{ + int ret = route_map_delete_set ((struct route_map_index *) vty->index, + "metric-type", argv[0]); + return route_map_command_status (vty, ret); +} + +/* add "set metric" */ +DEFUN (set_metric, + set_metric_cmd, + "set metric <0-4294967295>", + "Set value\n" + "Metric value\n" + "Metric value\n") +{ + int ret = route_map_add_set ((struct route_map_index *) vty->index, + "metric", argv[0]); + return route_map_command_status (vty, ret); +} + +/* delete "set metric" */ +DEFUN (no_set_metric, + no_set_metric_cmd, + "no set metric <0-4294967295>", + NO_STR + "Set value\n" + "Metric\n" + "METRIC value\n") +{ + int ret = route_map_delete_set ((struct route_map_index *) vty->index, + "metric", argv[0]); + return route_map_command_status (vty, ret); +} + +/* add "set forwarding-address" */ +DEFUN (ospf6_routemap_set_forwarding, + ospf6_routemap_set_forwarding_cmd, + "set forwarding-address X:X::X:X", + "Set value\n" + "Forwarding Address\n" + "IPv6 Address\n") +{ + int ret = route_map_add_set ((struct route_map_index *) vty->index, + "forwarding-address", argv[0]); + return route_map_command_status (vty, ret); +} + +/* delete "set forwarding-address" */ +DEFUN (ospf6_routemap_no_set_forwarding, + ospf6_routemap_no_set_forwarding_cmd, + "no set forwarding-address X:X::X:X", + NO_STR + "Set value\n" + "Forwarding Address\n" + "IPv6 Address\n") +{ + int ret = route_map_delete_set ((struct route_map_index *) vty->index, + "forwarding-address", argv[0]); + return route_map_command_status (vty, ret); +} + +void +ospf6_routemap_init () +{ + route_map_init (); + route_map_init_vty (); + route_map_add_hook (ospf6_asbr_routemap_update); + route_map_delete_hook (ospf6_asbr_routemap_update); + + route_map_install_match (&ospf6_routemap_rule_match_address_prefixlist_cmd); + route_map_install_set (&ospf6_routemap_rule_set_metric_type_cmd); + route_map_install_set (&ospf6_routemap_rule_set_metric_cmd); + route_map_install_set (&ospf6_routemap_rule_set_forwarding_cmd); + + /* Match address prefix-list */ + install_element (RMAP_NODE, &ospf6_routemap_match_address_prefixlist_cmd); + install_element (RMAP_NODE, &ospf6_routemap_no_match_address_prefixlist_cmd); + + /* ASE Metric Type (e.g. Type-1/Type-2) */ + install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd); + install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd); + + /* ASE Metric */ + install_element (RMAP_NODE, &set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_cmd); + + /* ASE Metric */ + install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd); + install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd); +} + + +/* Display functions */ +int +ospf6_as_external_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + struct ospf6_as_external_lsa *external; + char buf[64]; + struct in6_addr in6, *forwarding; + + assert (lsa->header); + external = (struct ospf6_as_external_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); + + /* bits */ + snprintf (buf, sizeof (buf), "%c%c%c", + (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ? 'E' : '-'), + (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ? 'F' : '-'), + (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ? 'T' : '-')); + + vty_out (vty, " Bits: %s%s", buf, VNL); + vty_out (vty, " Metric: %5lu%s", (u_long) OSPF6_ASBR_METRIC (external), + VNL); + + ospf6_prefix_options_printbuf (external->prefix.prefix_options, + buf, sizeof (buf)); + vty_out (vty, " Prefix Options: %s%s", buf, + VNL); + + vty_out (vty, " Referenced LSType: %d%s", + ntohs (external->prefix.prefix_refer_lstype), + VNL); + + ospf6_prefix_in6_addr (&in6, &external->prefix); + inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); + vty_out (vty, " Prefix: %s/%d%s", buf, + external->prefix.prefix_length, VNL); + + /* Forwarding-Address */ + if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F)) + { + forwarding = (struct in6_addr *) + ((caddr_t) external + sizeof (struct ospf6_as_external_lsa) + + OSPF6_PREFIX_SPACE (external->prefix.prefix_length)); + inet_ntop (AF_INET6, forwarding, buf, sizeof (buf)); + vty_out (vty, " Forwarding-Address: %s%s", buf, VNL); + } + + return 0; +} + +void +ospf6_asbr_external_route_show (struct vty *vty, struct ospf6_route *route) +{ + struct ospf6_external_info *info = route->route_option; + char prefix[64], id[16], forwarding[64]; + u_int32_t tmp_id; + + prefix2str (&route->prefix, prefix, sizeof (prefix)); + tmp_id = ntohl (info->id); + inet_ntop (AF_INET, &tmp_id, id, sizeof (id)); + if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding)) + inet_ntop (AF_INET6, &info->forwarding, forwarding, sizeof (forwarding)); + else + snprintf (forwarding, sizeof (forwarding), ":: (ifindex %d)", + route->nexthop[0].ifindex); + + vty_out (vty, "%s %-32s %-15s type-%d %5lu %s%s", + ZROUTE_ABNAME (info->type), + prefix, id, route->path.metric_type, + (u_long) (route->path.metric_type == 2 ? + route->path.cost_e2 : route->path.cost), + forwarding, VNL); +} + +DEFUN (show_ipv6_ospf6_redistribute, + show_ipv6_ospf6_redistribute_cmd, + "show ipv6 ospf6 redistribute", + SHOW_STR + IP6_STR + OSPF6_STR + "redistributing External information\n" + ) +{ + struct ospf6_route *route; + + ospf6_redistribute_show_config (vty); + + for (route = ospf6_route_head (ospf6->external_table); route; + route = ospf6_route_next (route)) + ospf6_asbr_external_route_show (vty, route); + + return CMD_SUCCESS; +} + +struct ospf6_lsa_handler as_external_handler = +{ + OSPF6_LSTYPE_AS_EXTERNAL, + "AS-External", + ospf6_as_external_lsa_show +}; + +void +ospf6_asbr_init () +{ + ospf6_routemap_init (); + + ospf6_install_lsa_handler (&as_external_handler); + + install_element (VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_redistribute_cmd); + + install_element (OSPF6_NODE, &ospf6_redistribute_cmd); + install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd); + install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd); +} + + +DEFUN (debug_ospf6_asbr, + debug_ospf6_asbr_cmd, + "debug ospf6 asbr", + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 ASBR function\n" + ) +{ + OSPF6_DEBUG_ASBR_ON (); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf6_asbr, + no_debug_ospf6_asbr_cmd, + "no debug ospf6 asbr", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 ASBR function\n" + ) +{ + OSPF6_DEBUG_ASBR_OFF (); + return CMD_SUCCESS; +} + +int +config_write_ospf6_debug_asbr (struct vty *vty) +{ + if (IS_OSPF6_DEBUG_ASBR) + vty_out (vty, "debug ospf6 asbr%s", VNL); + return 0; +} + +void +install_element_ospf6_debug_asbr () +{ + install_element (ENABLE_NODE, &debug_ospf6_asbr_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_asbr_cmd); + install_element (CONFIG_NODE, &debug_ospf6_asbr_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_asbr_cmd); +} + + diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h new file mode 100644 index 0000000..f3aabc8 --- /dev/null +++ b/ospf6d/ospf6_asbr.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2001 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_ASBR_H +#define OSPF6_ASBR_H + +/* Debug option */ +extern unsigned char conf_debug_ospf6_asbr; +#define OSPF6_DEBUG_ASBR_ON() \ + (conf_debug_ospf6_asbr = 1) +#define OSPF6_DEBUG_ASBR_OFF() \ + (conf_debug_ospf6_asbr = 0) +#define IS_OSPF6_DEBUG_ASBR \ + (conf_debug_ospf6_asbr) + +struct ospf6_external_info +{ + /* External route type */ + int type; + + /* Originating Link State ID */ + u_int32_t id; + + struct in6_addr forwarding; + /* u_int32_t tag; */ +}; + +/* AS-External-LSA */ +struct ospf6_as_external_lsa +{ + u_int32_t bits_metric; + + struct ospf6_prefix prefix; + /* followed by none or one forwarding address */ + /* followed by none or one external route tag */ + /* followed by none or one referenced LS-ID */ +}; + +#define OSPF6_ASBR_BIT_T ntohl (0x01000000) +#define OSPF6_ASBR_BIT_F ntohl (0x02000000) +#define OSPF6_ASBR_BIT_E ntohl (0x04000000) + +#define OSPF6_ASBR_METRIC(E) (ntohl ((E)->bits_metric & htonl (0x00ffffff))) +#define OSPF6_ASBR_METRIC_SET(E,C) \ + { (E)->bits_metric &= htonl (0xff000000); \ + (E)->bits_metric |= htonl (0x00ffffff) & htonl (C); } + +void ospf6_asbr_lsa_add (struct ospf6_lsa *lsa); +void ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa); +void ospf6_asbr_lsentry_add (struct ospf6_route *asbr_entry); +void ospf6_asbr_lsentry_remove (struct ospf6_route *asbr_entry); + +int ospf6_asbr_is_asbr (struct ospf6 *o); +void +ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix, + u_int nexthop_num, struct in6_addr *nexthop); +void +ospf6_asbr_redistribute_remove (int type, int ifindex, struct prefix *prefix); + +int ospf6_redistribute_config_write (struct vty *vty); + +void ospf6_asbr_init (); + +int config_write_ospf6_debug_asbr (struct vty *vty); +void install_element_ospf6_debug_asbr (); + +#endif /* OSPF6_ASBR_H */ + diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c new file mode 100644 index 0000000..e9ba52b --- /dev/null +++ b/ospf6d/ospf6_flood.c @@ -0,0 +1,1047 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "thread.h" +#include "linklist.h" +#include "vty.h" +#include "command.h" + +#include "ospf6d.h" +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_message.h" +#include "ospf6_route.h" +#include "ospf6_spf.h" + +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" + +#include "ospf6_flood.h" + +unsigned char conf_debug_ospf6_flooding; + +struct ospf6_lsdb * +ospf6_get_scoped_lsdb (struct ospf6_lsa *lsa) +{ + struct ospf6_lsdb *lsdb = NULL; + switch (OSPF6_LSA_SCOPE (lsa->header->type)) + { + case OSPF6_SCOPE_LINKLOCAL: + lsdb = OSPF6_INTERFACE (lsa->lsdb->data)->lsdb; + break; + case OSPF6_SCOPE_AREA: + lsdb = OSPF6_AREA (lsa->lsdb->data)->lsdb; + break; + case OSPF6_SCOPE_AS: + lsdb = OSPF6_PROCESS (lsa->lsdb->data)->lsdb; + break; + default: + assert (0); + break; + } + return lsdb; +} + +struct ospf6_lsdb * +ospf6_get_scoped_lsdb_self (struct ospf6_lsa *lsa) +{ + struct ospf6_lsdb *lsdb_self = NULL; + switch (OSPF6_LSA_SCOPE (lsa->header->type)) + { + case OSPF6_SCOPE_LINKLOCAL: + lsdb_self = OSPF6_INTERFACE (lsa->lsdb->data)->lsdb_self; + break; + case OSPF6_SCOPE_AREA: + lsdb_self = OSPF6_AREA (lsa->lsdb->data)->lsdb_self; + break; + case OSPF6_SCOPE_AS: + lsdb_self = OSPF6_PROCESS (lsa->lsdb->data)->lsdb_self; + break; + default: + assert (0); + break; + } + return lsdb_self; +} + +void +ospf6_lsa_originate (struct ospf6_lsa *lsa) +{ + struct ospf6_lsa *old; + struct ospf6_lsdb *lsdb_self; + + /* find previous LSA */ + old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, + lsa->header->adv_router, lsa->lsdb); + + /* if the new LSA does not differ from previous, + suppress this update of the LSA */ + if (old && ! OSPF6_LSA_IS_DIFFER (lsa, old)) + { + if (IS_OSPF6_DEBUG_ORIGINATE_TYPE (lsa->header->type)) + zlog_info ("Suppress updating LSA: %s", lsa->name); + ospf6_lsa_delete (lsa); + return; + } + + /* store it in the LSDB for self-originated LSAs */ + lsdb_self = ospf6_get_scoped_lsdb_self (lsa); + ospf6_lsdb_add (ospf6_lsa_copy (lsa), lsdb_self); + + lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa, + LS_REFRESH_TIME); + + if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type) || + IS_OSPF6_DEBUG_ORIGINATE_TYPE (lsa->header->type)) + { + zlog_info ("LSA Originate:"); + ospf6_lsa_header_print (lsa); + } + + if (old) + ospf6_flood_clear (old); + ospf6_flood (NULL, lsa); + ospf6_install_lsa (lsa); +} + +void +ospf6_lsa_originate_process (struct ospf6_lsa *lsa, + struct ospf6 *process) +{ + lsa->lsdb = process->lsdb; + ospf6_lsa_originate (lsa); +} + +void +ospf6_lsa_originate_area (struct ospf6_lsa *lsa, + struct ospf6_area *oa) +{ + lsa->lsdb = oa->lsdb; + ospf6_lsa_originate (lsa); +} + +void +ospf6_lsa_originate_interface (struct ospf6_lsa *lsa, + struct ospf6_interface *oi) +{ + lsa->lsdb = oi->lsdb; + ospf6_lsa_originate (lsa); +} + +void +ospf6_lsa_purge (struct ospf6_lsa *lsa) +{ + struct ospf6_lsa *self; + struct ospf6_lsdb *lsdb_self; + + /* remove it from the LSDB for self-originated LSAs */ + lsdb_self = ospf6_get_scoped_lsdb_self (lsa); + self = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, + lsa->header->adv_router, lsdb_self); + if (self) + { + THREAD_OFF (self->expire); + THREAD_OFF (self->refresh); + ospf6_lsdb_remove (self, lsdb_self); + } + + ospf6_lsa_premature_aging (lsa); +} + + +void +ospf6_increment_retrans_count (struct ospf6_lsa *lsa) +{ + /* The LSA must be the original one (see the description + in ospf6_decrement_retrans_count () below) */ + lsa->retrans_count++; +} + +void +ospf6_decrement_retrans_count (struct ospf6_lsa *lsa) +{ + struct ospf6_lsdb *lsdb; + struct ospf6_lsa *orig; + + /* The LSA must be on the retrans-list of a neighbor. It means + the "lsa" is a copied one, and we have to decrement the + retransmission count of the original one (instead of this "lsa"'s). + In order to find the original LSA, first we have to find + appropriate LSDB that have the original LSA. */ + lsdb = ospf6_get_scoped_lsdb (lsa); + + /* Find the original LSA of which the retrans_count should be decremented */ + orig = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, + lsa->header->adv_router, lsdb); + if (orig) + { + orig->retrans_count--; + assert (orig->retrans_count >= 0); + } +} + +/* RFC2328 section 13.2 Installing LSAs in the database */ +void +ospf6_install_lsa (struct ospf6_lsa *lsa) +{ + struct ospf6_lsa *old; + struct timeval now; + + if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type) || + IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type)) + zlog_info ("Install LSA: %s", lsa->name); + + /* Remove the old instance from all neighbors' Link state + retransmission list (RFC2328 13.2 last paragraph) */ + old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, + lsa->header->adv_router, lsa->lsdb); + if (old) + { + THREAD_OFF (old->expire); + ospf6_flood_clear (old); + } + + gettimeofday (&now, (struct timezone *) NULL); + if (! OSPF6_LSA_IS_MAXAGE (lsa)) + lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa, + MAXAGE + lsa->birth.tv_sec - now.tv_sec); + else + lsa->expire = NULL; + + /* actually install */ + lsa->installed = now; + ospf6_lsdb_add (lsa, lsa->lsdb); + + return; +} + +/* RFC2740 section 3.5.2. Sending Link State Update packets */ +/* RFC2328 section 13.3 Next step in the flooding procedure */ +void +ospf6_flood_interface (struct ospf6_neighbor *from, + struct ospf6_lsa *lsa, struct ospf6_interface *oi) +{ + listnode node; + struct ospf6_neighbor *on; + struct ospf6_lsa *req; + int retrans_added = 0; + int is_debug = 0; + + if (IS_OSPF6_DEBUG_FLOODING || + IS_OSPF6_DEBUG_FLOOD_TYPE (lsa->header->type)) + { + is_debug++; + zlog_info ("Flooding on %s: %s", oi->interface->name, lsa->name); + } + + /* (1) For each neighbor */ + for (node = listhead (oi->neighbor_list); node; nextnode (node)) + { + on = (struct ospf6_neighbor *) getdata (node); + + if (is_debug) + zlog_info ("To neighbor %s", on->name); + + /* (a) if neighbor state < Exchange, examin next */ + if (on->state < OSPF6_NEIGHBOR_EXCHANGE) + { + if (is_debug) + zlog_info ("Neighbor state less than ExChange, next neighbor"); + continue; + } + + /* (b) if neighbor not yet Full, check request-list */ + if (on->state != OSPF6_NEIGHBOR_FULL) + { + if (is_debug) + zlog_info ("Neighbor not yet Full"); + + req = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, + lsa->header->adv_router, on->request_list); + if (req == NULL) + { + if (is_debug) + zlog_info ("Not on request-list for this neighbor"); + /* fall through */ + } + else + { + /* If new LSA less recent, examin next neighbor */ + if (ospf6_lsa_compare (lsa, req) > 0) + { + if (is_debug) + zlog_info ("Requesting is newer, next neighbor"); + continue; + } + + /* If the same instance, delete from request-list and + examin next neighbor */ + if (ospf6_lsa_compare (lsa, req) == 0) + { + if (is_debug) + zlog_info ("Requesting the same, remove it, next neighbor"); + ospf6_lsdb_remove (req, on->request_list); + continue; + } + + /* If the new LSA is more recent, delete from request-list */ + if (ospf6_lsa_compare (lsa, req) < 0) + { + if (is_debug) + zlog_info ("Received is newer, remove requesting"); + ospf6_lsdb_remove (req, on->request_list); + /* fall through */ + } + } + } + + /* (c) If the new LSA was received from this neighbor, + examin next neighbor */ + if (from == on) + { + if (is_debug) + zlog_info ("Received is from the neighbor, next neighbor"); + continue; + } + + /* (d) add retrans-list, schedule retransmission */ + if (is_debug) + zlog_info ("Add retrans-list of this neighbor"); + ospf6_increment_retrans_count (lsa); + ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list); + if (on->thread_send_lsupdate == NULL) + on->thread_send_lsupdate = + thread_add_event (master, ospf6_lsupdate_send_neighbor, + on, on->ospf6_if->rxmt_interval); + retrans_added++; + } + + /* (2) examin next interface if not added to retrans-list */ + if (retrans_added == 0) + { + if (is_debug) + zlog_info ("No retransmission scheduled, next interface"); + return; + } + + /* (3) If the new LSA was received on this interface, + and it was from DR or BDR, examin next interface */ + if (from && from->ospf6_if == oi && + (from->router_id == oi->drouter || from->router_id == oi->bdrouter)) + { + if (is_debug) + zlog_info ("Received is from the I/F's DR or BDR, next interface"); + return; + } + + /* (4) If the new LSA was received on this interface, + and the interface state is BDR, examin next interface */ + if (from && from->ospf6_if == oi && oi->state == OSPF6_INTERFACE_BDR) + { + if (is_debug) + zlog_info ("Received is from the I/F, itself BDR, next interface"); + return; + } + + /* (5) flood the LSA out the interface. */ + if (is_debug) + zlog_info ("Schedule flooding for the interface"); + if (if_is_broadcast (oi->interface)) + { + ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsupdate_list); + if (oi->thread_send_lsupdate == NULL) + oi->thread_send_lsupdate = + thread_add_event (master, ospf6_lsupdate_send_interface, oi, 0); + } + else + { + /* reschedule retransmissions to all neighbors */ + for (node = listhead (oi->neighbor_list); node; nextnode (node)) + { + on = (struct ospf6_neighbor *) getdata (node); + THREAD_OFF (on->thread_send_lsupdate); + on->thread_send_lsupdate = + thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); + } + } +} + +void +ospf6_flood_area (struct ospf6_neighbor *from, + struct ospf6_lsa *lsa, struct ospf6_area *oa) +{ + listnode node; + struct ospf6_interface *oi; + + for (node = listhead (oa->if_list); node; nextnode (node)) + { + oi = OSPF6_INTERFACE (getdata (node)); + + if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_LINKLOCAL && + oi != OSPF6_INTERFACE (lsa->lsdb->data)) + continue; + +#if 0 + if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AS && + ospf6_is_interface_virtual_link (oi)) + continue; +#endif/*0*/ + + ospf6_flood_interface (from, lsa, oi); + } +} + +void +ospf6_flood_process (struct ospf6_neighbor *from, + struct ospf6_lsa *lsa, struct ospf6 *process) +{ + listnode node; + struct ospf6_area *oa; + + for (node = listhead (process->area_list); node; nextnode (node)) + { + oa = OSPF6_AREA (getdata (node)); + + if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AREA && + oa != OSPF6_AREA (lsa->lsdb->data)) + continue; + if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_LINKLOCAL && + oa != OSPF6_INTERFACE (lsa->lsdb->data)->area) + continue; + + if (ntohs (lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL && + IS_AREA_STUB (oa)) + continue; + + ospf6_flood_area (from, lsa, oa); + } +} + +void +ospf6_flood (struct ospf6_neighbor *from, struct ospf6_lsa *lsa) +{ + ospf6_flood_process (from, lsa, ospf6); +} + +void +ospf6_flood_clear_interface (struct ospf6_lsa *lsa, struct ospf6_interface *oi) +{ + listnode node; + struct ospf6_neighbor *on; + struct ospf6_lsa *rem; + + for (node = listhead (oi->neighbor_list); node; nextnode (node)) + { + on = OSPF6_NEIGHBOR (getdata (node)); + rem = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, + lsa->header->adv_router, on->retrans_list); + if (rem && ! ospf6_lsa_compare (rem, lsa)) + { + if (IS_OSPF6_DEBUG_FLOODING || + IS_OSPF6_DEBUG_FLOOD_TYPE (lsa->header->type)) + zlog_info ("Remove %s from retrans_list of %s", + rem->name, on->name); + ospf6_decrement_retrans_count (rem); + ospf6_lsdb_remove (rem, on->retrans_list); + } + } +} + +void +ospf6_flood_clear_area (struct ospf6_lsa *lsa, struct ospf6_area *oa) +{ + listnode node; + struct ospf6_interface *oi; + + for (node = listhead (oa->if_list); node; nextnode (node)) + { + oi = OSPF6_INTERFACE (getdata (node)); + + if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_LINKLOCAL && + oi != OSPF6_INTERFACE (lsa->lsdb->data)) + continue; + +#if 0 + if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AS && + ospf6_is_interface_virtual_link (oi)) + continue; +#endif/*0*/ + + ospf6_flood_clear_interface (lsa, oi); + } +} + +void +ospf6_flood_clear_process (struct ospf6_lsa *lsa, struct ospf6 *process) +{ + listnode node; + struct ospf6_area *oa; + + for (node = listhead (process->area_list); node; nextnode (node)) + { + oa = OSPF6_AREA (getdata (node)); + + if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AREA && + oa != OSPF6_AREA (lsa->lsdb->data)) + continue; + if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_LINKLOCAL && + oa != OSPF6_INTERFACE (lsa->lsdb->data)->area) + continue; + + if (ntohs (lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL && + IS_AREA_STUB (oa)) + continue; + + ospf6_flood_clear_area (lsa, oa); + } +} + +void +ospf6_flood_clear (struct ospf6_lsa *lsa) +{ + ospf6_flood_clear_process (lsa, ospf6); +} + + +/* RFC2328 13.5 (Table 19): Sending link state acknowledgements. */ +static void +ospf6_acknowledge_lsa_bdrouter (struct ospf6_lsa *lsa, int ismore_recent, + struct ospf6_neighbor *from) +{ + struct ospf6_interface *oi; + int is_debug = 0; + + if (IS_OSPF6_DEBUG_FLOODING || + IS_OSPF6_DEBUG_FLOOD_TYPE (lsa->header->type)) + is_debug++; + + assert (from && from->ospf6_if); + oi = from->ospf6_if; + + /* LSA has been flood back out receiving interface. + No acknowledgement sent. */ + if (CHECK_FLAG (lsa->flag, OSPF6_LSA_FLOODBACK)) + { + if (is_debug) + zlog_info ("No acknowledgement (BDR & FloodBack)"); + return; + } + + /* LSA is more recent than database copy, but was not flooded + back out receiving interface. Delayed acknowledgement sent + if advertisement received from Designated Router, + otherwide do nothing. */ + if (ismore_recent < 0) + { + if (oi->drouter == from->router_id) + { + if (is_debug) + zlog_info ("Delayed acknowledgement (BDR & MoreRecent & from DR)"); + /* Delayed acknowledgement */ + ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsack_list); + if (oi->thread_send_lsack == NULL) + oi->thread_send_lsack = + thread_add_timer (master, ospf6_lsack_send_interface, oi, 3); + } + else + { + if (is_debug) + zlog_info ("No acknowledgement (BDR & MoreRecent & ! from DR)"); + } + return; + } + + /* LSA is a duplicate, and was treated as an implied acknowledgement. + Delayed acknowledgement sent if advertisement received from + Designated Router, otherwise do nothing */ + if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) && + CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK)) + { + if (oi->drouter == from->router_id) + { + if (is_debug) + zlog_info ("Delayed acknowledgement (BDR & Duplicate & ImpliedAck & from DR)"); + /* Delayed acknowledgement */ + ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsack_list); + if (oi->thread_send_lsack == NULL) + oi->thread_send_lsack = + thread_add_timer (master, ospf6_lsack_send_interface, oi, 3); + } + else + { + if (is_debug) + zlog_info ("No acknowledgement (BDR & Duplicate & ImpliedAck & ! from DR)"); + } + return; + } + + /* LSA is a duplicate, and was not treated as an implied acknowledgement. + Direct acknowledgement sent */ + if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) && + ! CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK)) + { + if (is_debug) + zlog_info ("Direct acknowledgement (BDR & Duplicate)"); + ospf6_lsdb_add (ospf6_lsa_copy (lsa), from->lsack_list); + if (from->thread_send_lsack == NULL) + from->thread_send_lsack = + thread_add_event (master, ospf6_lsack_send_neighbor, from, 0); + return; + } + + /* LSA's LS age is equal to Maxage, and there is no current instance + of the LSA in the link state database, and none of router's + neighbors are in states Exchange or Loading */ + /* Direct acknowledgement sent, but this case is handled in + early of ospf6_receive_lsa () */ +} + +static void +ospf6_acknowledge_lsa_allother (struct ospf6_lsa *lsa, int ismore_recent, + struct ospf6_neighbor *from) +{ + struct ospf6_interface *oi; + int is_debug = 0; + + if (IS_OSPF6_DEBUG_FLOODING || + IS_OSPF6_DEBUG_FLOOD_TYPE (lsa->header->type)) + is_debug++; + + assert (from && from->ospf6_if); + oi = from->ospf6_if; + + /* LSA has been flood back out receiving interface. + No acknowledgement sent. */ + if (CHECK_FLAG (lsa->flag, OSPF6_LSA_FLOODBACK)) + { + if (is_debug) + zlog_info ("No acknowledgement (AllOther & FloodBack)"); + return; + } + + /* LSA is more recent than database copy, but was not flooded + back out receiving interface. Delayed acknowledgement sent. */ + if (ismore_recent < 0) + { + if (is_debug) + zlog_info ("Delayed acknowledgement (AllOther & MoreRecent)"); + /* Delayed acknowledgement */ + ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsack_list); + if (oi->thread_send_lsack == NULL) + oi->thread_send_lsack = + thread_add_timer (master, ospf6_lsack_send_interface, oi, 3); + return; + } + + /* LSA is a duplicate, and was treated as an implied acknowledgement. + No acknowledgement sent. */ + if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) && + CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK)) + { + if (is_debug) + zlog_info ("No acknowledgement (AllOther & Duplicate & ImpliedAck)"); + return; + } + + /* LSA is a duplicate, and was not treated as an implied acknowledgement. + Direct acknowledgement sent */ + if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) && + ! CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK)) + { + if (is_debug) + zlog_info ("Direct acknowledgement (AllOther & Duplicate)"); + ospf6_lsdb_add (ospf6_lsa_copy (lsa), from->lsack_list); + if (from->thread_send_lsack == NULL) + from->thread_send_lsack = + thread_add_event (master, ospf6_lsack_send_neighbor, from, 0); + return; + } + + /* LSA's LS age is equal to Maxage, and there is no current instance + of the LSA in the link state database, and none of router's + neighbors are in states Exchange or Loading */ + /* Direct acknowledgement sent, but this case is handled in + early of ospf6_receive_lsa () */ +} + +void +ospf6_acknowledge_lsa (struct ospf6_lsa *lsa, int ismore_recent, + struct ospf6_neighbor *from) +{ + struct ospf6_interface *oi; + + assert (from && from->ospf6_if); + oi = from->ospf6_if; + + if (oi->state == OSPF6_INTERFACE_BDR) + ospf6_acknowledge_lsa_bdrouter (lsa, ismore_recent, from); + else + ospf6_acknowledge_lsa_allother (lsa, ismore_recent, from); +} + +/* RFC2328 section 13 (4): + if MaxAge LSA and if we have no instance, and no neighbor + is in states Exchange or Loading + returns 1 if match this case, else returns 0 */ +static int +ospf6_is_maxage_lsa_drop (struct ospf6_lsa *lsa, struct ospf6_neighbor *from) +{ + struct ospf6_neighbor *on; + struct ospf6_interface *oi; + struct ospf6_area *oa; + struct ospf6 *process = NULL; + listnode i, j, k; + int count = 0; + + if (! OSPF6_LSA_IS_MAXAGE (lsa)) + return 0; + + if (ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, + lsa->header->adv_router, lsa->lsdb)) + return 0; + + process = from->ospf6_if->area->ospf6; + for (i = listhead (process->area_list); i; nextnode (i)) + { + oa = OSPF6_AREA (getdata (i)); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = OSPF6_INTERFACE (getdata (j)); + for (k = listhead (oi->neighbor_list); k; nextnode (k)) + { + on = OSPF6_NEIGHBOR (getdata (k)); + if (on->state == OSPF6_NEIGHBOR_EXCHANGE || + on->state == OSPF6_NEIGHBOR_LOADING) + count++; + } + } + } + + if (count == 0) + return 1; + return 0; +} + +/* RFC2328 section 13 The Flooding Procedure */ +void +ospf6_receive_lsa (struct ospf6_neighbor *from, + struct ospf6_lsa_header *lsa_header) +{ + struct ospf6_lsa *new = NULL, *old = NULL, *rem = NULL; + int ismore_recent; + unsigned short cksum; + int is_debug = 0; + + ismore_recent = 1; + assert (from); + + /* make lsa structure for received lsa */ + new = ospf6_lsa_create (lsa_header); + + if (IS_OSPF6_DEBUG_FLOODING || + IS_OSPF6_DEBUG_FLOOD_TYPE (new->header->type)) + { + is_debug++; + zlog_info ("LSA Receive from %s", from->name); + ospf6_lsa_header_print (new); + } + + /* (1) LSA Checksum */ + cksum = ntohs (new->header->checksum); + if (ntohs (ospf6_lsa_checksum (new->header)) != cksum) + { + if (is_debug) + zlog_info ("Wrong LSA Checksum, discard"); + ospf6_lsa_delete (new); + return; + } + + /* (2) Examine the LSA's LS type. + RFC2470 3.5.1. Receiving Link State Update packets */ + if (IS_AREA_STUB (from->ospf6_if->area) && + OSPF6_LSA_SCOPE (new->header->type) == OSPF6_SCOPE_AS) + { + if (is_debug) + zlog_info ("AS-External-LSA (or AS-scope LSA) in stub area, discard"); + ospf6_lsa_delete (new); + return; + } + + /* (3) LSA which have reserved scope is discarded + RFC2470 3.5.1. Receiving Link State Update packets */ + /* Flooding scope check. LSAs with unknown scope are discarded here. + Set appropriate LSDB for the LSA */ + switch (OSPF6_LSA_SCOPE (new->header->type)) + { + case OSPF6_SCOPE_LINKLOCAL: + new->lsdb = from->ospf6_if->lsdb; + break; + case OSPF6_SCOPE_AREA: + new->lsdb = from->ospf6_if->area->lsdb; + break; + case OSPF6_SCOPE_AS: + new->lsdb = from->ospf6_if->area->ospf6->lsdb; + break; + default: + if (is_debug) + zlog_info ("LSA has reserved scope, discard"); + ospf6_lsa_delete (new); + return; + } + + /* (4) if MaxAge LSA and if we have no instance, and no neighbor + is in states Exchange or Loading */ + if (ospf6_is_maxage_lsa_drop (new, from)) + { + /* log */ + if (is_debug) + zlog_info ("Drop MaxAge LSA with direct acknowledgement."); + + /* a) Acknowledge back to neighbor (Direct acknowledgement, 13.5) */ + ospf6_lsdb_add (ospf6_lsa_copy (new), from->lsack_list); + if (from->thread_send_lsack == NULL) + from->thread_send_lsack = + thread_add_event (master, ospf6_lsack_send_neighbor, from, 0); + + /* b) Discard */ + ospf6_lsa_delete (new); + return; + } + + /* (5) */ + /* lookup the same database copy in lsdb */ + old = ospf6_lsdb_lookup (new->header->type, new->header->id, + new->header->adv_router, new->lsdb); + if (old) + { + ismore_recent = ospf6_lsa_compare (new, old); + if (ntohl (new->header->seqnum) == ntohl (old->header->seqnum)) + { + if (is_debug) + zlog_info ("Received is duplicated LSA"); + SET_FLAG (new->flag, OSPF6_LSA_DUPLICATE); + } + } + + /* if no database copy or received is more recent */ + if (old == NULL || ismore_recent < 0) + { + /* in case we have no database copy */ + ismore_recent = -1; + + /* (a) MinLSArrival check */ + if (old) + { + struct timeval now, res; + gettimeofday (&now, (struct timezone *) NULL); + timersub (&now, &old->installed, &res); + if (res.tv_sec < MIN_LS_ARRIVAL) + { + if (is_debug) + zlog_info ("LSA can't be updated within MinLSArrival, discard"); + ospf6_lsa_delete (new); + return; /* examin next lsa */ + } + } + + gettimeofday (&new->received, (struct timezone *) NULL); + + if (is_debug) + zlog_info ("Flood, Install, Possibly acknowledge the received LSA"); + + /* (b) immediately flood and (c) remove from all retrans-list */ + /* Prevent self-originated LSA to be flooded. this is to make + reoriginated instance of the LSA not to be rejected by other routers + due to MinLSArrival. */ + if (new->header->adv_router != from->ospf6_if->area->ospf6->router_id) + ospf6_flood (from, new); + + /* (c) Remove the current database copy from all neighbors' Link + state retransmission lists. */ + /* XXX, flood_clear ? */ + + /* (d), installing lsdb, which may cause routing + table calculation (replacing database copy) */ + ospf6_install_lsa (new); + + /* (e) possibly acknowledge */ + ospf6_acknowledge_lsa (new, ismore_recent, from); + + /* (f) Self Originated LSA, section 13.4 */ + if (new->header->adv_router == from->ospf6_if->area->ospf6->router_id) + { + /* Self-originated LSA (newer than ours) is received from + another router. We have to make a new instance of the LSA + or have to flush this LSA. */ + if (is_debug) + { + zlog_info ("Newer instance of the self-originated LSA"); + zlog_info ("Schedule reorigination"); + } + new->refresh = thread_add_event (master, ospf6_lsa_refresh, new, 0); + } + + return; + } + + /* (6) if there is instance on sending neighbor's request list */ + if (ospf6_lsdb_lookup (new->header->type, new->header->id, + new->header->adv_router, from->request_list)) + { + /* if no database copy, should go above state (5) */ + assert (old); + + if (is_debug) + { + zlog_info ("Received is not newer, on the neighbor's request-list"); + zlog_info ("BadLSReq, discard the received LSA"); + } + + /* BadLSReq */ + thread_add_event (master, bad_lsreq, from, 0); + + ospf6_lsa_delete (new); + return; + } + + /* (7) if neither one is more recent */ + if (ismore_recent == 0) + { + if (is_debug) + zlog_info ("The same instance as database copy (neither recent)"); + + /* (a) if on retrans-list, Treat this LSA as an Ack: Implied Ack */ + rem = ospf6_lsdb_lookup (new->header->type, new->header->id, + new->header->adv_router, from->retrans_list); + if (rem) + { + if (is_debug) + { + zlog_info ("It is on the neighbor's retrans-list."); + zlog_info ("Treat as an Implied acknowledgement"); + } + SET_FLAG (new->flag, OSPF6_LSA_IMPLIEDACK); + ospf6_decrement_retrans_count (rem); + ospf6_lsdb_remove (rem, from->retrans_list); + } + + if (is_debug) + zlog_info ("Possibly acknowledge and then discard"); + + /* (b) possibly acknowledge */ + ospf6_acknowledge_lsa (new, ismore_recent, from); + + ospf6_lsa_delete (new); + return; + } + + /* (8) previous database copy is more recent */ + { + assert (old); + + /* If database copy is in 'Seqnumber Wrapping', + simply discard the received LSA */ + if (OSPF6_LSA_IS_MAXAGE (old) && + old->header->seqnum == htonl (MAX_SEQUENCE_NUMBER)) + { + if (is_debug) + { + zlog_info ("The LSA is in Seqnumber Wrapping"); + zlog_info ("MaxAge & MaxSeqNum, discard"); + } + ospf6_lsa_delete (new); + return; + } + + /* Otherwise, Send database copy of this LSA to this neighbor */ + { + if (is_debug) + { + zlog_info ("Database copy is more recent."); + zlog_info ("Send back directly and then discard"); + } + + /* XXX, MinLSArrival check !? RFC 2328 13 (8) */ + + ospf6_lsdb_add (ospf6_lsa_copy (old), from->lsupdate_list); + if (from->thread_send_lsupdate == NULL) + from->thread_send_lsupdate = + thread_add_event (master, ospf6_lsupdate_send_neighbor, from, 0); + ospf6_lsa_delete (new); + return; + } + return; + } +} + + +DEFUN (debug_ospf6_flooding, + debug_ospf6_flooding_cmd, + "debug ospf6 flooding", + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 flooding function\n" + ) +{ + OSPF6_DEBUG_FLOODING_ON (); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf6_flooding, + no_debug_ospf6_flooding_cmd, + "no debug ospf6 flooding", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 flooding function\n" + ) +{ + OSPF6_DEBUG_FLOODING_OFF (); + return CMD_SUCCESS; +} + +int +config_write_ospf6_debug_flood (struct vty *vty) +{ + if (IS_OSPF6_DEBUG_FLOODING) + vty_out (vty, "debug ospf6 flooding%s", VNL); + return 0; +} + +void +install_element_ospf6_debug_flood () +{ + install_element (ENABLE_NODE, &debug_ospf6_flooding_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_flooding_cmd); + install_element (CONFIG_NODE, &debug_ospf6_flooding_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_flooding_cmd); +} + + + + + diff --git a/ospf6d/ospf6_flood.h b/ospf6d/ospf6_flood.h new file mode 100644 index 0000000..4851c14 --- /dev/null +++ b/ospf6d/ospf6_flood.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_FLOOD_H +#define OSPF6_FLOOD_H + +/* Debug option */ +extern unsigned char conf_debug_ospf6_flooding; +#define OSPF6_DEBUG_FLOODING_ON() \ + (conf_debug_ospf6_flooding = 1) +#define OSPF6_DEBUG_FLOODING_OFF() \ + (conf_debug_ospf6_flooding = 0) +#define IS_OSPF6_DEBUG_FLOODING \ + (conf_debug_ospf6_flooding) + +/* Function Prototypes */ +struct ospf6_lsdb *ospf6_get_scoped_lsdb (struct ospf6_lsa *lsa); +struct ospf6_lsdb *ospf6_get_scoped_lsdb_self (struct ospf6_lsa *lsa); + +/* origination & purging */ +void ospf6_lsa_originate (struct ospf6_lsa *lsa); +void ospf6_lsa_originate_process (struct ospf6_lsa *lsa, + struct ospf6 *process); +void ospf6_lsa_originate_area (struct ospf6_lsa *lsa, + struct ospf6_area *oa); +void ospf6_lsa_originate_interface (struct ospf6_lsa *lsa, + struct ospf6_interface *oi); +void ospf6_lsa_purge (struct ospf6_lsa *lsa); + +/* access method to retrans_count */ +void ospf6_increment_retrans_count (struct ospf6_lsa *lsa); +void ospf6_decrement_retrans_count (struct ospf6_lsa *lsa); + +/* flooding & clear flooding */ +void ospf6_flood_clear (struct ospf6_lsa *lsa); +void ospf6_flood (struct ospf6_neighbor *from, struct ospf6_lsa *lsa); + +/* receive & install */ +void ospf6_receive_lsa (struct ospf6_neighbor *from, + struct ospf6_lsa_header *header); +void ospf6_install_lsa (struct ospf6_lsa *lsa); + +int config_write_ospf6_debug_flood (struct vty *vty); +void install_element_ospf6_debug_flood (); + +#endif /* OSPF6_FLOOD_H */ + + diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c new file mode 100644 index 0000000..7eff743 --- /dev/null +++ b/ospf6d/ospf6_interface.c @@ -0,0 +1,1633 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "if.h" +#include "log.h" +#include "command.h" +#include "thread.h" +#include "prefix.h" +#include "plist.h" + +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_network.h" +#include "ospf6_message.h" +#include "ospf6_route.h" +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" +#include "ospf6_intra.h" +#include "ospf6_spf.h" +#include "ospf6d.h" + +unsigned char conf_debug_ospf6_interface = 0; + +char *ospf6_interface_state_str[] = +{ + "None", + "Down", + "Loopback", + "Waiting", + "PointToPoint", + "DROther", + "BDR", + "DR", + NULL +}; + +struct ospf6_interface * +ospf6_interface_lookup_by_ifindex (int ifindex) +{ + struct ospf6_interface *oi; + struct interface *ifp; + + ifp = if_lookup_by_index (ifindex); + if (ifp == NULL) + return (struct ospf6_interface *) NULL; + + oi = (struct ospf6_interface *) ifp->info; + return oi; +} + +struct ospf6_interface * +ospf6_interface_lookup_by_name (char *ifname) +{ + struct ospf6_interface *oi; + struct interface *ifp; + + ifp = if_lookup_by_name (ifname); + if (ifp == NULL) + return (struct ospf6_interface *) NULL; + + oi = (struct ospf6_interface *) ifp->info; + return oi; +} + +/* schedule routing table recalculation */ +void +ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa) +{ + switch (ntohs (lsa->header->type)) + { + case OSPF6_LSTYPE_LINK: + if (OSPF6_INTERFACE (lsa->lsdb->data)->state == OSPF6_INTERFACE_DR) + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (OSPF6_INTERFACE (lsa->lsdb->data)); + ospf6_spf_schedule (OSPF6_INTERFACE (lsa->lsdb->data)->area); + break; + + default: + break; + } +} + +/* Create new ospf6 interface structure */ +struct ospf6_interface * +ospf6_interface_create (struct interface *ifp) +{ + struct ospf6_interface *oi; + int iobuflen; + + oi = (struct ospf6_interface *) + XMALLOC (MTYPE_OSPF6_IF, sizeof (struct ospf6_interface)); + + if (oi) + memset (oi, 0, sizeof (struct ospf6_interface)); + else + { + zlog_err ("Can't malloc ospf6_interface for ifindex %d", ifp->ifindex); + return (struct ospf6_interface *) NULL; + } + + oi->area = (struct ospf6_area *) NULL; + oi->neighbor_list = list_new (); + oi->neighbor_list->cmp = ospf6_neighbor_cmp; + oi->linklocal_addr = (struct in6_addr *) NULL; + oi->instance_id = 0; + oi->transdelay = 1; + oi->priority = 1; + + oi->hello_interval = 10; + oi->dead_interval = 40; + oi->rxmt_interval = 5; + oi->cost = 1; + oi->state = OSPF6_INTERFACE_DOWN; + oi->flag = 0; + + /* Try to adjust I/O buffer size with IfMtu */ + oi->ifmtu = ifp->mtu; + iobuflen = ospf6_iobuf_size (ifp->mtu); + if (oi->ifmtu > iobuflen) + { + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_info ("Interface %s: IfMtu is adjusted to I/O buffer size: %d.", + ifp->name, iobuflen); + oi->ifmtu = iobuflen; + } + + oi->lsupdate_list = ospf6_lsdb_create (oi); + oi->lsack_list = ospf6_lsdb_create (oi); + oi->lsdb = ospf6_lsdb_create (oi); + oi->lsdb->hook_add = ospf6_interface_lsdb_hook; + oi->lsdb->hook_remove = ospf6_interface_lsdb_hook; + oi->lsdb_self = ospf6_lsdb_create (oi); + + oi->route_connected = ospf6_route_table_create (); + + /* link both */ + oi->interface = ifp; + ifp->info = oi; + + return oi; +} + +void +ospf6_interface_delete (struct ospf6_interface *oi) +{ + listnode n; + struct ospf6_neighbor *on; + + for (n = listhead (oi->neighbor_list); n; nextnode (n)) + { + on = (struct ospf6_neighbor *) getdata (n); + ospf6_neighbor_delete (on); + } + list_delete (oi->neighbor_list); + + THREAD_OFF (oi->thread_send_hello); + THREAD_OFF (oi->thread_send_lsupdate); + THREAD_OFF (oi->thread_send_lsack); + + ospf6_lsdb_remove_all (oi->lsdb); + ospf6_lsdb_remove_all (oi->lsupdate_list); + ospf6_lsdb_remove_all (oi->lsack_list); + + ospf6_lsdb_delete (oi->lsdb); + ospf6_lsdb_delete (oi->lsdb_self); + + ospf6_lsdb_delete (oi->lsupdate_list); + ospf6_lsdb_delete (oi->lsack_list); + + ospf6_route_table_delete (oi->route_connected); + + /* cut link */ + oi->interface->info = NULL; + + /* plist_name */ + if (oi->plist_name) + XFREE (MTYPE_PREFIX_LIST_STR, oi->plist_name); + + XFREE (MTYPE_OSPF6_IF, oi); +} + +void +ospf6_interface_enable (struct ospf6_interface *oi) +{ + UNSET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE); + + oi->thread_send_hello = + thread_add_event (master, ospf6_hello_send, oi, 0); +} + +void +ospf6_interface_disable (struct ospf6_interface *oi) +{ + listnode i; + struct ospf6_neighbor *on; + + SET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE); + + for (i = listhead (oi->neighbor_list); i; nextnode (i)) + { + on = (struct ospf6_neighbor *) getdata (i); + ospf6_neighbor_delete (on); + } + list_delete_all_node (oi->neighbor_list); + + ospf6_lsdb_remove_all (oi->lsdb); + ospf6_lsdb_remove_all (oi->lsupdate_list); + ospf6_lsdb_remove_all (oi->lsack_list); + + THREAD_OFF (oi->thread_send_hello); + THREAD_OFF (oi->thread_send_lsupdate); + THREAD_OFF (oi->thread_send_lsack); +} + +static struct in6_addr * +ospf6_interface_get_linklocal_address (struct interface *ifp) +{ + listnode n; + struct connected *c; + struct in6_addr *l = (struct in6_addr *) NULL; + + /* for each connected address */ + for (n = listhead (ifp->connected); n; nextnode (n)) + { + c = (struct connected *) getdata (n); + + /* if family not AF_INET6, ignore */ + if (c->address->family != AF_INET6) + continue; + + /* linklocal scope check */ + if (IN6_IS_ADDR_LINKLOCAL (&c->address->u.prefix6)) + l = &c->address->u.prefix6; + } + return l; +} + +void +ospf6_interface_if_add (struct interface *ifp) +{ + struct ospf6_interface *oi; + int iobuflen; + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + return; + + /* Try to adjust I/O buffer size with IfMtu */ + if (oi->ifmtu == 0) + oi->ifmtu = ifp->mtu; + iobuflen = ospf6_iobuf_size (ifp->mtu); + if (oi->ifmtu > iobuflen) + { + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_info ("Interface %s: IfMtu is adjusted to I/O buffer size: %d.", + ifp->name, iobuflen); + oi->ifmtu = iobuflen; + } + + /* interface start */ + if (oi->area) + thread_add_event (master, interface_up, oi, 0); +} + +void +ospf6_interface_if_del (struct interface *ifp) +{ + struct ospf6_interface *oi; + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + return; + + /* interface stop */ + if (oi->area) + thread_execute (master, interface_down, oi, 0); + + listnode_delete (oi->area->if_list, oi); + oi->area = (struct ospf6_area *) NULL; + + /* cut link */ + oi->interface = NULL; + ifp->info = NULL; + + ospf6_interface_delete (oi); +} + +void +ospf6_interface_state_update (struct interface *ifp) +{ + struct ospf6_interface *oi; + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + return; + if (oi->area == NULL) + return; + + if (if_is_up (ifp)) + thread_add_event (master, interface_up, oi, 0); + else + thread_add_event (master, interface_down, oi, 0); + + return; +} + +void +ospf6_interface_connected_route_update (struct interface *ifp) +{ + struct ospf6_interface *oi; + struct ospf6_route *route; + struct connected *c; + listnode i; + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + return; + + /* reset linklocal pointer */ + oi->linklocal_addr = ospf6_interface_get_linklocal_address (ifp); + + /* if area is null, do not make connected-route list */ + if (oi->area == NULL) + return; + + /* update "route to advertise" interface route table */ + ospf6_route_remove_all (oi->route_connected); + for (i = listhead (oi->interface->connected); i; nextnode (i)) + { + c = (struct connected *) getdata (i); + + if (c->address->family != AF_INET6) + continue; + + CONTINUE_IF_ADDRESS_LINKLOCAL (IS_OSPF6_DEBUG_INTERFACE, c->address); + CONTINUE_IF_ADDRESS_UNSPECIFIED (IS_OSPF6_DEBUG_INTERFACE, c->address); + CONTINUE_IF_ADDRESS_LOOPBACK (IS_OSPF6_DEBUG_INTERFACE, c->address); + CONTINUE_IF_ADDRESS_V4COMPAT (IS_OSPF6_DEBUG_INTERFACE, c->address); + CONTINUE_IF_ADDRESS_V4MAPPED (IS_OSPF6_DEBUG_INTERFACE, c->address); + + /* apply filter */ + if (oi->plist_name) + { + struct prefix_list *plist; + enum prefix_list_type ret; + char buf[128]; + + prefix2str (c->address, buf, sizeof (buf)); + plist = prefix_list_lookup (AFI_IP6, oi->plist_name); + ret = prefix_list_apply (plist, (void *) c->address); + if (ret == PREFIX_DENY) + { + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_info ("%s on %s filtered by prefix-list %s ", + buf, oi->interface->name, oi->plist_name); + continue; + } + } + + route = ospf6_route_create (); + memcpy (&route->prefix, c->address, sizeof (struct prefix)); + apply_mask (&route->prefix); + route->type = OSPF6_DEST_TYPE_NETWORK; + route->path.area_id = oi->area->area_id; + route->path.type = OSPF6_PATH_TYPE_INTRA; + route->path.cost = oi->cost; + route->nexthop[0].ifindex = oi->interface->ifindex; + inet_pton (AF_INET6, "::1", &route->nexthop[0].address); + ospf6_route_add (route, oi->route_connected); + } + + /* create new Link-LSA */ + OSPF6_LINK_LSA_SCHEDULE (oi); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); +} + +static void +ospf6_interface_state_change (u_char next_state, struct ospf6_interface *oi) +{ + u_char prev_state; + + prev_state = oi->state; + oi->state = next_state; + + if (prev_state == next_state) + return; + + /* log */ + if (IS_OSPF6_DEBUG_INTERFACE) + { + zlog_info ("Interface state change %s: %s -> %s", oi->interface->name, + ospf6_interface_state_str[prev_state], + ospf6_interface_state_str[next_state]); + } + + if ((prev_state == OSPF6_INTERFACE_DR || + prev_state == OSPF6_INTERFACE_BDR) && + (next_state != OSPF6_INTERFACE_DR && + next_state != OSPF6_INTERFACE_BDR)) + ospf6_leave_alldrouters (oi->interface->ifindex); + if ((prev_state != OSPF6_INTERFACE_DR && + prev_state != OSPF6_INTERFACE_BDR) && + (next_state == OSPF6_INTERFACE_DR || + next_state == OSPF6_INTERFACE_BDR)) + ospf6_join_alldrouters (oi->interface->ifindex); + + OSPF6_ROUTER_LSA_SCHEDULE (oi->area); + if (next_state == OSPF6_INTERFACE_DOWN) + { + OSPF6_NETWORK_LSA_EXECUTE (oi); + OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT (oi); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); + } + else if (prev_state == OSPF6_INTERFACE_DR || + next_state == OSPF6_INTERFACE_DR) + { + OSPF6_NETWORK_LSA_SCHEDULE (oi); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); + } +} + + +/* DR Election, RFC2328 section 9.4 */ + +#define IS_ELIGIBLE(n) \ + ((n)->state >= OSPF6_NEIGHBOR_TWOWAY && (n)->priority != 0) + +static struct ospf6_neighbor * +better_bdrouter (struct ospf6_neighbor *a, struct ospf6_neighbor *b) +{ + if ((a == NULL || ! IS_ELIGIBLE (a) || a->drouter == a->router_id) && + (b == NULL || ! IS_ELIGIBLE (b) || b->drouter == b->router_id)) + return NULL; + else if (a == NULL || ! IS_ELIGIBLE (a) || a->drouter == a->router_id) + return b; + else if (b == NULL || ! IS_ELIGIBLE (b) || b->drouter == b->router_id) + return a; + + if (a->bdrouter == a->router_id && b->bdrouter != b->router_id) + return a; + if (a->bdrouter != a->router_id && b->bdrouter == b->router_id) + return b; + + if (a->priority > b->priority) + return a; + if (a->priority < b->priority) + return b; + + if (ntohl (a->router_id) > ntohl (b->router_id)) + return a; + if (ntohl (a->router_id) < ntohl (b->router_id)) + return b; + + zlog_warn ("Router-ID duplicate ?"); + return a; +} + +static struct ospf6_neighbor * +better_drouter (struct ospf6_neighbor *a, struct ospf6_neighbor *b) +{ + if ((a == NULL || ! IS_ELIGIBLE (a) || a->drouter != a->router_id) && + (b == NULL || ! IS_ELIGIBLE (b) || b->drouter != b->router_id)) + return NULL; + else if (a == NULL || ! IS_ELIGIBLE (a) || a->drouter != a->router_id) + return b; + else if (b == NULL || ! IS_ELIGIBLE (b) || b->drouter != b->router_id) + return a; + + if (a->drouter == a->router_id && b->drouter != b->router_id) + return a; + if (a->drouter != a->router_id && b->drouter == b->router_id) + return b; + + if (a->priority > b->priority) + return a; + if (a->priority < b->priority) + return b; + + if (ntohl (a->router_id) > ntohl (b->router_id)) + return a; + if (ntohl (a->router_id) < ntohl (b->router_id)) + return b; + + zlog_warn ("Router-ID duplicate ?"); + return a; +} + +static u_char +dr_election (struct ospf6_interface *oi) +{ + listnode i; + struct ospf6_neighbor *on, *drouter, *bdrouter, myself; + struct ospf6_neighbor *best_drouter, *best_bdrouter; + u_char next_state = 0; + + drouter = bdrouter = NULL; + best_drouter = best_bdrouter = NULL; + + /* pseudo neighbor myself, including noting current DR/BDR (1) */ + memset (&myself, 0, sizeof (myself)); + inet_ntop (AF_INET, &oi->area->ospf6->router_id, myself.name, + sizeof (myself.name)); + myself.state = OSPF6_NEIGHBOR_TWOWAY; + myself.drouter = oi->drouter; + myself.bdrouter = oi->bdrouter; + myself.priority = oi->priority; + myself.router_id = oi->area->ospf6->router_id; + + /* Electing BDR (2) */ + for (i = listhead (oi->neighbor_list); i; nextnode (i)) + { + on = (struct ospf6_neighbor *) getdata (i); + bdrouter = better_bdrouter (bdrouter, on); + } + best_bdrouter = bdrouter; + bdrouter = better_bdrouter (best_bdrouter, &myself); + + /* Electing DR (3) */ + for (i = listhead (oi->neighbor_list); i; nextnode (i)) + { + on = (struct ospf6_neighbor *) getdata (i); + drouter = better_drouter (drouter, on); + } + best_drouter = drouter; + drouter = better_drouter (best_drouter, &myself); + if (drouter == NULL) + drouter = bdrouter; + + /* the router itself is newly/no longer DR/BDR (4) */ + if ((drouter == &myself && myself.drouter != myself.router_id) || + (drouter != &myself && myself.drouter == myself.router_id) || + (bdrouter == &myself && myself.bdrouter != myself.router_id) || + (bdrouter != &myself && myself.bdrouter == myself.router_id)) + { + myself.drouter = (drouter ? drouter->router_id : htonl (0)); + myself.bdrouter = (bdrouter ? bdrouter->router_id : htonl (0)); + + /* compatible to Electing BDR (2) */ + bdrouter = better_bdrouter (best_bdrouter, &myself); + + /* compatible to Electing DR (3) */ + drouter = better_drouter (best_drouter, &myself); + if (drouter == NULL) + drouter = bdrouter; + } + + /* Set interface state accordingly (5) */ + if (drouter && drouter == &myself) + next_state = OSPF6_INTERFACE_DR; + else if (bdrouter && bdrouter == &myself) + next_state = OSPF6_INTERFACE_BDR; + else + next_state = OSPF6_INTERFACE_DROTHER; + + /* If NBMA, schedule Start for each neighbor having priority of 0 (6) */ + /* XXX */ + + /* If DR or BDR change, invoke AdjOK? for each neighbor (7) */ + /* RFC 2328 section 12.4. Originating LSAs (3) will be handled + accordingly after AdjOK */ + if (oi->drouter != (drouter ? drouter->router_id : htonl (0)) || + oi->bdrouter != (bdrouter ? bdrouter->router_id : htonl (0))) + { + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_info ("DR Election on %s: DR: %s BDR: %s", oi->interface->name, + (drouter ? drouter->name : "0.0.0.0"), + (bdrouter ? bdrouter->name : "0.0.0.0")); + + for (i = listhead (oi->neighbor_list); i; nextnode (i)) + { + on = (struct ospf6_neighbor *) getdata (i); + if (on->state < OSPF6_NEIGHBOR_TWOWAY) + continue; + /* Schedule AdjOK. */ + thread_add_event (master, adj_ok, on, 0); + } + } + + oi->drouter = (drouter ? drouter->router_id : htonl (0)); + oi->bdrouter = (bdrouter ? bdrouter->router_id : htonl (0)); + return next_state; +} + + +/* Interface State Machine */ +int +interface_up (struct thread *thread) +{ + struct ospf6_interface *oi; + + oi = (struct ospf6_interface *) THREAD_ARG (thread); + assert (oi && oi->interface); + + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_info ("Interface Event %s: [InterfaceUp]", + oi->interface->name); + + /* check physical interface is up */ + if (! if_is_up (oi->interface)) + { + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_info ("Interface %s is down, can't execute [InterfaceUp]", + oi->interface->name); + return 0; + } + + /* if already enabled, do nothing */ + if (oi->state > OSPF6_INTERFACE_DOWN) + { + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_info ("Interface %s already enabled", + oi->interface->name); + return 0; + } + + /* Join AllSPFRouters */ + ospf6_join_allspfrouters (oi->interface->ifindex); + + /* Update interface route */ + ospf6_interface_connected_route_update (oi->interface); + + /* Schedule Hello */ + if (! CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE)) + thread_add_event (master, ospf6_hello_send, oi, 0); + + /* decide next interface state */ + if (if_is_pointopoint (oi->interface)) + ospf6_interface_state_change (OSPF6_INTERFACE_POINTTOPOINT, oi); + else if (oi->priority == 0) + ospf6_interface_state_change (OSPF6_INTERFACE_DROTHER, oi); + else + { + ospf6_interface_state_change (OSPF6_INTERFACE_WAITING, oi); + thread_add_timer (master, wait_timer, oi, oi->dead_interval); + } + + return 0; +} + +int +wait_timer (struct thread *thread) +{ + struct ospf6_interface *oi; + + oi = (struct ospf6_interface *) THREAD_ARG (thread); + assert (oi && oi->interface); + + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_info ("Interface Event %s: [WaitTimer]", + oi->interface->name); + + if (oi->state == OSPF6_INTERFACE_WAITING) + ospf6_interface_state_change (dr_election (oi), oi); + + return 0; +} + +int +backup_seen (struct thread *thread) +{ + struct ospf6_interface *oi; + + oi = (struct ospf6_interface *) THREAD_ARG (thread); + assert (oi && oi->interface); + + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_info ("Interface Event %s: [BackupSeen]", + oi->interface->name); + + if (oi->state == OSPF6_INTERFACE_WAITING) + ospf6_interface_state_change (dr_election (oi), oi); + + return 0; +} + +int +neighbor_change (struct thread *thread) +{ + struct ospf6_interface *oi; + + oi = (struct ospf6_interface *) THREAD_ARG (thread); + assert (oi && oi->interface); + + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_info ("Interface Event %s: [NeighborChange]", + oi->interface->name); + + if (oi->state == OSPF6_INTERFACE_DROTHER || + oi->state == OSPF6_INTERFACE_BDR || + oi->state == OSPF6_INTERFACE_DR) + ospf6_interface_state_change (dr_election (oi), oi); + + return 0; +} + +int +loopind (struct thread *thread) +{ + struct ospf6_interface *oi; + + oi = (struct ospf6_interface *) THREAD_ARG (thread); + assert (oi && oi->interface); + + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_info ("Interface Event %s: [LoopInd]", + oi->interface->name); + + /* XXX not yet */ + + return 0; +} + +int +interface_down (struct thread *thread) +{ + struct ospf6_interface *oi; + listnode n; + struct ospf6_neighbor *on; + + oi = (struct ospf6_interface *) THREAD_ARG (thread); + assert (oi && oi->interface); + + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_info ("Interface Event %s: [InterfaceDown]", + oi->interface->name); + + /* Leave AllSPFRouters */ + if (oi->state > OSPF6_INTERFACE_DOWN) + ospf6_leave_allspfrouters (oi->interface->ifindex); + + ospf6_interface_state_change (OSPF6_INTERFACE_DOWN, oi); + + for (n = listhead (oi->neighbor_list); n; nextnode (n)) + { + on = (struct ospf6_neighbor *) getdata (n); + ospf6_neighbor_delete (on); + } + list_delete_all_node (oi->neighbor_list); + + return 0; +} + + +/* show specified interface structure */ +int +ospf6_interface_show (struct vty *vty, struct interface *ifp) +{ + struct ospf6_interface *oi; + struct connected *c; + struct prefix *p; + listnode i; + char strbuf[64], drouter[32], bdrouter[32]; + char *updown[3] = {"down", "up", NULL}; + char *type; + struct timeval res, now; + char duration[32]; + struct ospf6_lsa *lsa; + + /* check physical interface type */ + if (if_is_loopback (ifp)) + type = "LOOPBACK"; + else if (if_is_broadcast (ifp)) + type = "BROADCAST"; + else if (if_is_pointopoint (ifp)) + type = "POINTOPOINT"; + else + type = "UNKNOWN"; + + vty_out (vty, "%s is %s, type %s%s", + ifp->name, updown[if_is_up (ifp)], type, + VNL); + vty_out (vty, " Interface ID: %d%s", ifp->ifindex, VNL); + + if (ifp->info == NULL) + { + vty_out (vty, " OSPF not enabled on this interface%s", VNL); + return 0; + } + else + oi = (struct ospf6_interface *) ifp->info; + + vty_out (vty, " Internet Address:%s", VNL); + for (i = listhead (ifp->connected); i; nextnode (i)) + { + c = (struct connected *)getdata (i); + p = c->address; + prefix2str (p, strbuf, sizeof (strbuf)); + switch (p->family) + { + case AF_INET: + vty_out (vty, " inet : %s%s", strbuf, + VNL); + break; + case AF_INET6: + vty_out (vty, " inet6: %s%s", strbuf, + VNL); + break; + default: + vty_out (vty, " ??? : %s%s", strbuf, + VNL); + break; + } + } + + if (oi->area) + { + vty_out (vty, " Instance ID %d, Interface MTU %d (autodetect: %d)%s", + oi->instance_id, oi->ifmtu, ifp->mtu, VNL); + inet_ntop (AF_INET, &oi->area->area_id, + strbuf, sizeof (strbuf)); + vty_out (vty, " Area ID %s, Cost %hu%s", strbuf, oi->cost, + VNL); + } + else + vty_out (vty, " Not Attached to Area%s", VNL); + + vty_out (vty, " State %s, Transmit Delay %d sec, Priority %d%s", + ospf6_interface_state_str[oi->state], + oi->transdelay, oi->priority, + VNL); + vty_out (vty, " Timer intervals configured:%s", VNL); + vty_out (vty, " Hello %d, Dead %d, Retransmit %d%s", + oi->hello_interval, oi->dead_interval, oi->rxmt_interval, + VNL); + + inet_ntop (AF_INET, &oi->drouter, drouter, sizeof (drouter)); + inet_ntop (AF_INET, &oi->bdrouter, bdrouter, sizeof (bdrouter)); + vty_out (vty, " DR: %s BDR: %s%s", drouter, bdrouter, VNL); + + vty_out (vty, " Number of I/F scoped LSAs is %u%s", + oi->lsdb->count, VNL); + + gettimeofday (&now, (struct timezone *) NULL); + + timerclear (&res); + if (oi->thread_send_lsupdate) + timersub (&oi->thread_send_lsupdate->u.sands, &now, &res); + timerstring (&res, duration, sizeof (duration)); + vty_out (vty, " %d Pending LSAs for LSUpdate in Time %s [thread %s]%s", + oi->lsupdate_list->count, duration, + (oi->thread_send_lsupdate ? "on" : "off"), + VNL); + for (lsa = ospf6_lsdb_head (oi->lsupdate_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + vty_out (vty, " %s%s", lsa->name, VNL); + + timerclear (&res); + if (oi->thread_send_lsack) + timersub (&oi->thread_send_lsack->u.sands, &now, &res); + timerstring (&res, duration, sizeof (duration)); + vty_out (vty, " %d Pending LSAs for LSAck in Time %s [thread %s]%s", + oi->lsack_list->count, duration, + (oi->thread_send_lsack ? "on" : "off"), + VNL); + for (lsa = ospf6_lsdb_head (oi->lsack_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + vty_out (vty, " %s%s", lsa->name, VNL); + + return 0; +} + +/* show interface */ +DEFUN (show_ipv6_ospf6_interface, + show_ipv6_ospf6_interface_ifname_cmd, + "show ipv6 ospf6 interface IFNAME", + SHOW_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + IFNAME_STR + ) +{ + struct interface *ifp; + listnode i; + + if (argc) + { + ifp = if_lookup_by_name (argv[0]); + if (ifp == NULL) + { + vty_out (vty, "No such Interface: %s%s", argv[0], + VNL); + return CMD_WARNING; + } + ospf6_interface_show (vty, ifp); + } + else + { + for (i = listhead (iflist); i; nextnode (i)) + { + ifp = (struct interface *) getdata (i); + ospf6_interface_show (vty, ifp); + } + } + + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_interface, + show_ipv6_ospf6_interface_cmd, + "show ipv6 ospf6 interface", + SHOW_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + ); + +DEFUN (show_ipv6_ospf6_interface_ifname_prefix, + show_ipv6_ospf6_interface_ifname_prefix_cmd, + "show ipv6 ospf6 interface IFNAME prefix", + SHOW_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + IFNAME_STR + "Display connected prefixes to advertise\n" + ) +{ + struct interface *ifp; + struct ospf6_interface *oi; + + ifp = if_lookup_by_name (argv[0]); + if (ifp == NULL) + { + vty_out (vty, "No such Interface: %s%s", argv[0], VNL); + return CMD_WARNING; + } + + oi = ifp->info; + if (oi == NULL) + { + vty_out (vty, "OSPFv3 is not enabled on %s%s", argv[0], VNL); + return CMD_WARNING; + } + + argc--; + argv++; + ospf6_route_table_show (vty, argc, argv, oi->route_connected); + + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_interface_ifname_prefix, + show_ipv6_ospf6_interface_ifname_prefix_detail_cmd, + "show ipv6 ospf6 interface IFNAME prefix (X:X::X:X|X:X::X:X/M|detail)", + SHOW_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + IFNAME_STR + "Display connected prefixes to advertise\n" + OSPF6_ROUTE_ADDRESS_STR + OSPF6_ROUTE_PREFIX_STR + "Dispaly details of the prefixes\n" + ); + +ALIAS (show_ipv6_ospf6_interface_ifname_prefix, + show_ipv6_ospf6_interface_ifname_prefix_match_cmd, + "show ipv6 ospf6 interface IFNAME prefix X:X::X:X/M (match|detail)", + SHOW_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + IFNAME_STR + "Display connected prefixes to advertise\n" + OSPF6_ROUTE_PREFIX_STR + OSPF6_ROUTE_MATCH_STR + "Dispaly details of the prefixes\n" + ); + +DEFUN (show_ipv6_ospf6_interface_prefix, + show_ipv6_ospf6_interface_prefix_cmd, + "show ipv6 ospf6 interface prefix", + SHOW_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + "Display connected prefixes to advertise\n" + ) +{ + listnode i; + struct ospf6_interface *oi; + struct interface *ifp; + + for (i = listhead (iflist); i; nextnode (i)) + { + ifp = (struct interface *) getdata (i); + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + continue; + + ospf6_route_table_show (vty, argc, argv, oi->route_connected); + } + + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_interface_prefix, + show_ipv6_ospf6_interface_prefix_detail_cmd, + "show ipv6 ospf6 interface prefix (X:X::X:X|X:X::X:X/M|detail)", + SHOW_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + "Display connected prefixes to advertise\n" + OSPF6_ROUTE_ADDRESS_STR + OSPF6_ROUTE_PREFIX_STR + "Dispaly details of the prefixes\n" + ); + +ALIAS (show_ipv6_ospf6_interface_prefix, + show_ipv6_ospf6_interface_prefix_match_cmd, + "show ipv6 ospf6 interface prefix X:X::X:X/M (match|detail)", + SHOW_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + "Display connected prefixes to advertise\n" + OSPF6_ROUTE_PREFIX_STR + OSPF6_ROUTE_MATCH_STR + "Dispaly details of the prefixes\n" + ); + + +/* interface variable set command */ +DEFUN (ipv6_ospf6_ifmtu, + ipv6_ospf6_ifmtu_cmd, + "ipv6 ospf6 ifmtu <1-65535>", + IP6_STR + OSPF6_STR + "Interface MTU\n" + "OSPFv3 Interface MTU\n" + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + int ifmtu, iobuflen; + listnode node; + struct ospf6_neighbor *on; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + ifmtu = strtol (argv[0], NULL, 10); + + if (oi->ifmtu == ifmtu) + return CMD_SUCCESS; + + if (ifp->mtu != 0 && ifp->mtu < ifmtu) + { + vty_out (vty, "%s's ospf6 ifmtu cannot go beyond physical mtu (%d)%s", + ifp->name, ifp->mtu, VNL); + return CMD_WARNING; + } + + if (oi->ifmtu < ifmtu) + { + iobuflen = ospf6_iobuf_size (ifmtu); + if (iobuflen < ifmtu) + { + vty_out (vty, "%s's ifmtu is adjusted to I/O buffer size (%d).%s", + ifp->name, iobuflen, VNL); + oi->ifmtu = iobuflen; + } + else + oi->ifmtu = ifmtu; + } + else + oi->ifmtu = ifmtu; + + /* re-establish adjacencies */ + for (node = listhead (oi->neighbor_list); node; nextnode (node)) + { + on = (struct ospf6_neighbor *) getdata (node); + THREAD_OFF (on->inactivity_timer); + thread_add_event (master, inactivity_timer, on, 0); + } + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_ospf6_ifmtu, + no_ipv6_ospf6_ifmtu_cmd, + "no ipv6 ospf6 ifmtu", + NO_STR + IP6_STR + OSPF6_STR + "Interface MTU\n" + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + int iobuflen; + listnode node; + struct ospf6_neighbor *on; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + if (oi->ifmtu < ifp->mtu) + { + iobuflen = ospf6_iobuf_size (ifp->mtu); + if (iobuflen < ifp->mtu) + { + vty_out (vty, "%s's ifmtu is adjusted to I/O buffer size (%d).%s", + ifp->name, iobuflen, VNL); + oi->ifmtu = iobuflen; + } + else + oi->ifmtu = ifp->mtu; + } + else + oi->ifmtu = ifp->mtu; + + /* re-establish adjacencies */ + for (node = listhead (oi->neighbor_list); node; nextnode (node)) + { + on = (struct ospf6_neighbor *) getdata (node); + THREAD_OFF (on->inactivity_timer); + thread_add_event (master, inactivity_timer, on, 0); + } + + return CMD_SUCCESS; +} + +DEFUN (ipv6_ospf6_cost, + ipv6_ospf6_cost_cmd, + "ipv6 ospf6 cost <1-65535>", + IP6_STR + OSPF6_STR + "Interface cost\n" + "Outgoing metric of this interface\n" + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + if (oi->cost == strtol (argv[0], NULL, 10)) + return CMD_SUCCESS; + + oi->cost = strtol (argv[0], NULL, 10); + + /* update cost held in route_connected list in ospf6_interface */ + ospf6_interface_connected_route_update (oi->interface); + + /* execute LSA hooks */ + if (oi->area) + { + OSPF6_LINK_LSA_SCHEDULE (oi); + OSPF6_ROUTER_LSA_SCHEDULE (oi->area); + OSPF6_NETWORK_LSA_SCHEDULE (oi); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); + } + + return CMD_SUCCESS; +} + +DEFUN (ipv6_ospf6_hellointerval, + ipv6_ospf6_hellointerval_cmd, + "ipv6 ospf6 hello-interval <1-65535>", + IP6_STR + OSPF6_STR + "Interval time of Hello packets\n" + SECONDS_STR + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + oi->hello_interval = strtol (argv[0], NULL, 10); + return CMD_SUCCESS; +} + +/* interface variable set command */ +DEFUN (ipv6_ospf6_deadinterval, + ipv6_ospf6_deadinterval_cmd, + "ipv6 ospf6 dead-interval <1-65535>", + IP6_STR + OSPF6_STR + "Interval time after which a neighbor is declared down\n" + SECONDS_STR + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + oi->dead_interval = strtol (argv[0], NULL, 10); + return CMD_SUCCESS; +} + +/* interface variable set command */ +DEFUN (ipv6_ospf6_transmitdelay, + ipv6_ospf6_transmitdelay_cmd, + "ipv6 ospf6 transmit-delay <1-3600>", + IP6_STR + OSPF6_STR + "Transmit delay of this interface\n" + SECONDS_STR + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + oi->transdelay = strtol (argv[0], NULL, 10); + return CMD_SUCCESS; +} + +/* interface variable set command */ +DEFUN (ipv6_ospf6_retransmitinterval, + ipv6_ospf6_retransmitinterval_cmd, + "ipv6 ospf6 retransmit-interval <1-65535>", + IP6_STR + OSPF6_STR + "Time between retransmitting lost link state advertisements\n" + SECONDS_STR + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + oi->rxmt_interval = strtol (argv[0], NULL, 10); + return CMD_SUCCESS; +} + +/* interface variable set command */ +DEFUN (ipv6_ospf6_priority, + ipv6_ospf6_priority_cmd, + "ipv6 ospf6 priority <0-255>", + IP6_STR + OSPF6_STR + "Router priority\n" + "Priority value\n" + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + oi->priority = strtol (argv[0], NULL, 10); + + if (oi->area) + ospf6_interface_state_change (dr_election (oi), oi); + + return CMD_SUCCESS; +} + +DEFUN (ipv6_ospf6_instance, + ipv6_ospf6_instance_cmd, + "ipv6 ospf6 instance-id <0-255>", + IP6_STR + OSPF6_STR + "Instance ID for this interface\n" + "Instance ID value\n" + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + + ifp = (struct interface *)vty->index; + assert (ifp); + + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + oi->instance_id = strtol (argv[0], NULL, 10); + return CMD_SUCCESS; +} + +DEFUN (ipv6_ospf6_passive, + ipv6_ospf6_passive_cmd, + "ipv6 ospf6 passive", + IP6_STR + OSPF6_STR + "passive interface, No adjacency will be formed on this interface\n" + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + listnode node; + struct ospf6_neighbor *on; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + SET_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE); + THREAD_OFF (oi->thread_send_hello); + + for (node = listhead (oi->neighbor_list); node; nextnode (node)) + { + on = (struct ospf6_neighbor *) getdata (node); + THREAD_OFF (on->inactivity_timer); + thread_add_event (master, inactivity_timer, on, 0); + } + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_ospf6_passive, + no_ipv6_ospf6_passive_cmd, + "no ipv6 ospf6 passive", + NO_STR + IP6_STR + OSPF6_STR + "passive interface: No Adjacency will be formed on this I/F\n" + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + UNSET_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE); + THREAD_OFF (oi->thread_send_hello); + oi->thread_send_hello = + thread_add_event (master, ospf6_hello_send, oi, 0); + + return CMD_SUCCESS; +} + +DEFUN (ipv6_ospf6_advertise_prefix_list, + ipv6_ospf6_advertise_prefix_list_cmd, + "ipv6 ospf6 advertise prefix-list WORD", + IP6_STR + OSPF6_STR + "Advertising options\n" + "Filter prefix using prefix-list\n" + "Prefix list name\n" + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + if (oi->plist_name) + XFREE (MTYPE_PREFIX_LIST_STR, oi->plist_name); + oi->plist_name = XSTRDUP (MTYPE_PREFIX_LIST_STR, argv[0]); + + ospf6_interface_connected_route_update (oi->interface); + OSPF6_LINK_LSA_SCHEDULE (oi); + if (oi->state == OSPF6_INTERFACE_DR) + { + OSPF6_NETWORK_LSA_SCHEDULE (oi); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); + } + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_ospf6_advertise_prefix_list, + no_ipv6_ospf6_advertise_prefix_list_cmd, + "no ipv6 ospf6 advertise prefix-list", + NO_STR + IP6_STR + OSPF6_STR + "Advertising options\n" + "Filter prefix using prefix-list\n" + ) +{ + struct ospf6_interface *oi; + struct interface *ifp; + + ifp = (struct interface *) vty->index; + assert (ifp); + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + assert (oi); + + if (oi->plist_name) + { + XFREE (MTYPE_PREFIX_LIST_STR, oi->plist_name); + oi->plist_name = NULL; + } + + ospf6_interface_connected_route_update (oi->interface); + OSPF6_LINK_LSA_SCHEDULE (oi); + if (oi->state == OSPF6_INTERFACE_DR) + { + OSPF6_NETWORK_LSA_SCHEDULE (oi); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); + } + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); + + return CMD_SUCCESS; +} + +int +config_write_ospf6_interface (struct vty *vty) +{ + listnode i; + struct ospf6_interface *oi; + struct interface *ifp; + + for (i = listhead (iflist); i; nextnode (i)) + { + ifp = (struct interface *) getdata (i); + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + continue; + + vty_out (vty, "interface %s%s", + oi->interface->name, VNL); + + if (ifp->desc) + vty_out (vty, " description %s%s", ifp->desc, VNL); + + if (ifp->mtu != oi->ifmtu) + vty_out (vty, " ipv6 ospf6 ifmtu %d%s", oi->ifmtu, VNL); + vty_out (vty, " ipv6 ospf6 cost %d%s", + oi->cost, VNL); + vty_out (vty, " ipv6 ospf6 hello-interval %d%s", + oi->hello_interval, VNL); + vty_out (vty, " ipv6 ospf6 dead-interval %d%s", + oi->dead_interval, VNL); + vty_out (vty, " ipv6 ospf6 retransmit-interval %d%s", + oi->rxmt_interval, VNL); + vty_out (vty, " ipv6 ospf6 priority %d%s", + oi->priority, VNL); + vty_out (vty, " ipv6 ospf6 transmit-delay %d%s", + oi->transdelay, VNL); + vty_out (vty, " ipv6 ospf6 instance-id %d%s", + oi->instance_id, VNL); + + if (oi->plist_name) + vty_out (vty, " ipv6 ospf6 advertise prefix-list %s%s", + oi->plist_name, VNL); + + if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE)) + vty_out (vty, " ipv6 ospf6 passive%s", VNL); + + vty_out (vty, "!%s", VNL); + } + return 0; +} + +struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", + 1 /* VTYSH */ +}; + +void +ospf6_interface_init () +{ + /* Install interface node. */ + install_node (&interface_node, config_write_ospf6_interface); + + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_detail_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_match_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_detail_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_match_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd); + + install_element (CONFIG_NODE, &interface_cmd); + install_default (INTERFACE_NODE); + install_element (INTERFACE_NODE, &interface_desc_cmd); + install_element (INTERFACE_NODE, &no_interface_desc_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd); + install_element (INTERFACE_NODE, &no_ipv6_ospf6_ifmtu_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_hellointerval_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_priority_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_retransmitinterval_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_transmitdelay_cmd); + install_element (INTERFACE_NODE, &ipv6_ospf6_instance_cmd); + + install_element (INTERFACE_NODE, &ipv6_ospf6_passive_cmd); + install_element (INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd); + + install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd); + install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd); +} + +DEFUN (debug_ospf6_interface, + debug_ospf6_interface_cmd, + "debug ospf6 interface", + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 Interface\n" + ) +{ + OSPF6_DEBUG_INTERFACE_ON (); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf6_interface, + no_debug_ospf6_interface_cmd, + "no debug ospf6 interface", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 Interface\n" + ) +{ + OSPF6_DEBUG_INTERFACE_OFF (); + return CMD_SUCCESS; +} + +int +config_write_ospf6_debug_interface (struct vty *vty) +{ + if (IS_OSPF6_DEBUG_INTERFACE) + vty_out (vty, "debug ospf6 interface%s", VNL); + return 0; +} + +void +install_element_ospf6_debug_interface () +{ + install_element (ENABLE_NODE, &debug_ospf6_interface_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_interface_cmd); + install_element (CONFIG_NODE, &debug_ospf6_interface_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_interface_cmd); +} + + diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h new file mode 100644 index 0000000..be3007d --- /dev/null +++ b/ospf6d/ospf6_interface.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_INTERFACE_H +#define OSPF6_INTERFACE_H + +#include "if.h" + +/* Debug option */ +extern unsigned char conf_debug_ospf6_interface; +#define OSPF6_DEBUG_INTERFACE_ON() \ + (conf_debug_ospf6_interface = 1) +#define OSPF6_DEBUG_INTERFACE_OFF() \ + (conf_debug_ospf6_interface = 0) +#define IS_OSPF6_DEBUG_INTERFACE \ + (conf_debug_ospf6_interface) + +/* Interface structure */ +struct ospf6_interface +{ + /* IF info from zebra */ + struct interface *interface; + + /* back pointer */ + struct ospf6_area *area; + + /* list of ospf6 neighbor */ + list neighbor_list; + + /* linklocal address of this I/F */ + struct in6_addr *linklocal_addr; + + /* Interface ID; use interface->ifindex */ + + /* ospf6 instance id */ + u_char instance_id; + + /* I/F transmission delay */ + u_int32_t transdelay; + + /* Router Priority */ + u_char priority; + + /* Time Interval */ + u_int16_t hello_interval; + u_int16_t dead_interval; + u_int32_t rxmt_interval; + + /* Cost */ + u_int32_t cost; + + /* I/F MTU */ + u_int32_t ifmtu; + + /* Interface State */ + u_char state; + + /* OSPF6 Interface flag */ + char flag; + + /* Decision of DR Election */ + u_int32_t drouter; + u_int32_t bdrouter; + u_int32_t prev_drouter; + u_int32_t prev_bdrouter; + + /* Linklocal LSA Database: includes Link-LSA */ + struct ospf6_lsdb *lsdb; + struct ospf6_lsdb *lsdb_self; + + struct ospf6_lsdb *lsupdate_list; + struct ospf6_lsdb *lsack_list; + + /* Ongoing Tasks */ + struct thread *thread_send_hello; + struct thread *thread_send_lsupdate; + struct thread *thread_send_lsack; + + struct thread *thread_network_lsa; + struct thread *thread_link_lsa; + struct thread *thread_intra_prefix_lsa; + + struct ospf6_route_table *route_connected; + + /* prefix-list name to filter connected prefix */ + char *plist_name; +}; + +/* interface state */ +#define OSPF6_INTERFACE_NONE 0 +#define OSPF6_INTERFACE_DOWN 1 +#define OSPF6_INTERFACE_LOOPBACK 2 +#define OSPF6_INTERFACE_WAITING 3 +#define OSPF6_INTERFACE_POINTTOPOINT 4 +#define OSPF6_INTERFACE_DROTHER 5 +#define OSPF6_INTERFACE_BDR 6 +#define OSPF6_INTERFACE_DR 7 +#define OSPF6_INTERFACE_MAX 8 + +extern char *ospf6_interface_state_str[]; + +/* flags */ +#define OSPF6_INTERFACE_DISABLE 0x01 +#define OSPF6_INTERFACE_PASSIVE 0x02 + + +/* Function Prototypes */ + +struct ospf6_interface *ospf6_interface_lookup_by_ifindex (int); +struct ospf6_interface *ospf6_interface_lookup_by_name (char *); +struct ospf6_interface *ospf6_interface_create (struct interface *); +void ospf6_interface_delete (struct ospf6_interface *); + +void ospf6_interface_enable (struct ospf6_interface *); +void ospf6_interface_disable (struct ospf6_interface *); + +void ospf6_interface_if_add (struct interface *); +void ospf6_interface_if_del (struct interface *); +void ospf6_interface_state_update (struct interface *); +void ospf6_interface_connected_route_update (struct interface *); + +/* interface event */ +int interface_up (struct thread *); +int interface_down (struct thread *); +int wait_timer (struct thread *); +int backup_seen (struct thread *); +int neighbor_change (struct thread *); + +void ospf6_interface_init (); + +int config_write_ospf6_debug_interface (struct vty *vty); +void install_element_ospf6_debug_interface (); + +#endif /* OSPF6_INTERFACE_H */ + diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c new file mode 100644 index 0000000..4452e62 --- /dev/null +++ b/ospf6d/ospf6_intra.c @@ -0,0 +1,1374 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "linklist.h" +#include "thread.h" +#include "memory.h" +#include "if.h" +#include "prefix.h" +#include "table.h" +#include "vty.h" +#include "command.h" + +#include "ospf6_proto.h" +#include "ospf6_message.h" +#include "ospf6_route.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" + +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" +#include "ospf6_intra.h" +#include "ospf6_asbr.h" +#include "ospf6_abr.h" +#include "ospf6_flood.h" +#include "ospf6d.h" + +/******************************/ +/* RFC2740 3.4.3.1 Router-LSA */ +/******************************/ + +int +ospf6_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + char *start, *end, *current; + char buf[32], name[32], bits[16], options[32]; + struct ospf6_router_lsa *router_lsa; + struct ospf6_router_lsdesc *lsdesc; + + router_lsa = (struct ospf6_router_lsa *) + ((char *) lsa->header + sizeof (struct ospf6_lsa_header)); + + ospf6_capability_printbuf (router_lsa->bits, bits, sizeof (bits)); + ospf6_options_printbuf (router_lsa->options, options, sizeof (options)); + vty_out (vty, " Bits: %s Options: %s%s", bits, options, VNL); + + start = (char *) router_lsa + sizeof (struct ospf6_router_lsa); + end = (char *) lsa->header + ntohs (lsa->header->length); + for (current = start; current + sizeof (struct ospf6_router_lsdesc) <= end; + current += sizeof (struct ospf6_router_lsdesc)) + { + lsdesc = (struct ospf6_router_lsdesc *) current; + + if (lsdesc->type == OSPF6_ROUTER_LSDESC_POINTTOPOINT) + snprintf (name, sizeof (name), "Point-To-Point"); + else if (lsdesc->type == OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK) + snprintf (name, sizeof (name), "Transit-Network"); + else if (lsdesc->type == OSPF6_ROUTER_LSDESC_STUB_NETWORK) + snprintf (name, sizeof (name), "Stub-Network"); + else if (lsdesc->type == OSPF6_ROUTER_LSDESC_VIRTUAL_LINK) + snprintf (name, sizeof (name), "Virtual-Link"); + else + snprintf (name, sizeof (name), "Unknown (%#x)", lsdesc->type); + + vty_out (vty, " Type: %s Metric: %d%s", + name, ntohs (lsdesc->metric), VNL); + vty_out (vty, " Interface ID: %s%s", + inet_ntop (AF_INET, &lsdesc->interface_id, + buf, sizeof (buf)), VNL); + vty_out (vty, " Neighbor Interface ID: %s%s", + inet_ntop (AF_INET, &lsdesc->neighbor_interface_id, + buf, sizeof (buf)), VNL); + vty_out (vty, " Neighbor Router ID: %s%s", + inet_ntop (AF_INET, &lsdesc->neighbor_router_id, + buf, sizeof (buf)), VNL); + } + return 0; +} + +int +ospf6_router_lsa_originate (struct thread *thread) +{ + struct ospf6_area *oa; + + char buffer [OSPF6_MAX_LSASIZE]; + struct ospf6_lsa_header *lsa_header; + struct ospf6_lsa *lsa; + + u_int32_t link_state_id = 0; + listnode i, j; + struct ospf6_interface *oi; + struct ospf6_neighbor *on, *drouter = NULL; + struct ospf6_router_lsa *router_lsa; + struct ospf6_router_lsdesc *lsdesc; + u_int16_t type; + u_int32_t router; + int count; + + oa = (struct ospf6_area *) THREAD_ARG (thread); + oa->thread_router_lsa = NULL; + + if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER)) + zlog_info ("Originate Router-LSA for Area %s", oa->name); + + memset (buffer, 0, sizeof (buffer)); + lsa_header = (struct ospf6_lsa_header *) buffer; + router_lsa = (struct ospf6_router_lsa *) + ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); + + OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_V6); + OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_E); + OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_MC); + OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_N); + OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_R); + OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_DC); + + if (ospf6_is_router_abr (ospf6)) + SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B); + else + UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B); + if (ospf6_asbr_is_asbr (ospf6)) + SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E); + else + UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E); + UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_V); + UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_W); + + /* describe links for each interfaces */ + lsdesc = (struct ospf6_router_lsdesc *) + ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa)); + + for (i = listhead (oa->if_list); i; nextnode (i)) + { + oi = (struct ospf6_interface *) getdata (i); + + /* Interfaces in state Down or Loopback are not described */ + if (oi->state == OSPF6_INTERFACE_DOWN || + oi->state == OSPF6_INTERFACE_LOOPBACK) + continue; + + /* Nor are interfaces without any full adjacencies described */ + count = 0; + for (j = listhead (oi->neighbor_list); j; nextnode (j)) + { + on = (struct ospf6_neighbor *) getdata (j); + if (on->state == OSPF6_NEIGHBOR_FULL) + count++; + } + if (count == 0) + continue; + + /* Multiple Router-LSA instance according to size limit setting */ + if (oa->router_lsa_size_limit != 0 && + (caddr_t) lsdesc + sizeof (struct ospf6_router_lsdesc) - + (caddr_t) buffer > oa->router_lsa_size_limit) + { + if ((caddr_t) lsdesc == (caddr_t) router_lsa + + sizeof (struct ospf6_router_lsa)) + { + if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER)) + zlog_info ("Size limit setting for Router-LSA too short"); + return 0; + } + + /* Fill LSA Header */ + lsa_header->age = 0; + lsa_header->type = htons (OSPF6_LSTYPE_ROUTER); + lsa_header->id = htonl (link_state_id); + lsa_header->adv_router = oa->ospf6->router_id; + lsa_header->seqnum = + ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, + lsa_header->adv_router, oa->lsdb); + lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); + + /* LSA checksum */ + ospf6_lsa_checksum (lsa_header); + + /* create LSA */ + lsa = ospf6_lsa_create (lsa_header); + + /* Originate */ + ospf6_lsa_originate_area (lsa, oa); + + /* Reset setting for consecutive origination */ + memset ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa), + 0, (caddr_t) lsdesc - (caddr_t) router_lsa); + lsdesc = (struct ospf6_router_lsdesc *) + ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa)); + link_state_id ++; + } + + /* Point-to-Point interfaces */ + if (if_is_pointopoint (oi->interface)) + { + for (j = listhead (oi->neighbor_list); j; nextnode (j)) + { + on = (struct ospf6_neighbor *) getdata (j); + if (on->state != OSPF6_NEIGHBOR_FULL) + continue; + + lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT; + lsdesc->metric = htons (oi->cost); + lsdesc->interface_id = htonl (oi->interface->ifindex); + lsdesc->neighbor_interface_id = htonl (on->ifindex); + lsdesc->neighbor_router_id = on->router_id; + + lsdesc++; + } + } + + /* Broadcast and NBMA interfaces */ + if (if_is_broadcast (oi->interface)) + { + /* If this router is not DR, + and If this router not fully adjacent with DR, + this interface is not transit yet: ignore. */ + if (oi->state != OSPF6_INTERFACE_DR) + { + drouter = ospf6_neighbor_lookup (oi->drouter, oi); + if (drouter == NULL || drouter->state != OSPF6_NEIGHBOR_FULL) + continue; + } + + lsdesc->type = OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK; + lsdesc->metric = htons (oi->cost); + lsdesc->interface_id = htonl (oi->interface->ifindex); + if (oi->state != OSPF6_INTERFACE_DR) + { + lsdesc->neighbor_interface_id = htonl (drouter->ifindex); + lsdesc->neighbor_router_id = drouter->router_id; + } + else + { + lsdesc->neighbor_interface_id = htonl (oi->interface->ifindex); + lsdesc->neighbor_router_id = oi->area->ospf6->router_id; + } + + lsdesc++; + } + + /* Virtual links */ + /* xxx */ + /* Point-to-Multipoint interfaces */ + /* xxx */ + } + + if ((caddr_t) lsdesc != (caddr_t) router_lsa + + sizeof (struct ospf6_router_lsa)) + { + /* Fill LSA Header */ + lsa_header->age = 0; + lsa_header->type = htons (OSPF6_LSTYPE_ROUTER); + lsa_header->id = htonl (link_state_id); + lsa_header->adv_router = oa->ospf6->router_id; + lsa_header->seqnum = + ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, + lsa_header->adv_router, oa->lsdb); + lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); + + /* LSA checksum */ + ospf6_lsa_checksum (lsa_header); + + /* create LSA */ + lsa = ospf6_lsa_create (lsa_header); + + /* Originate */ + ospf6_lsa_originate_area (lsa, oa); + + link_state_id ++; + } + else + { + if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER)) + zlog_info ("Nothing to describe in Router-LSA, suppress"); + } + + /* Do premature-aging of rest, undesired Router-LSAs */ + type = ntohs (OSPF6_LSTYPE_ROUTER); + router = oa->ospf6->router_id; + for (lsa = ospf6_lsdb_type_router_head (type, router, oa->lsdb); lsa; + lsa = ospf6_lsdb_type_router_next (type, router, lsa)) + { + if (ntohl (lsa->header->id) < link_state_id) + continue; + ospf6_lsa_purge (lsa); + } + + return 0; +} + +/*******************************/ +/* RFC2740 3.4.3.2 Network-LSA */ +/*******************************/ + +int +ospf6_network_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + char *start, *end, *current; + struct ospf6_network_lsa *network_lsa; + struct ospf6_network_lsdesc *lsdesc; + char buf[128], options[32]; + + network_lsa = (struct ospf6_network_lsa *) + ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); + + ospf6_options_printbuf (network_lsa->options, options, sizeof (options)); + vty_out (vty, " Options: %s%s", options, VNL); + + start = (char *) network_lsa + sizeof (struct ospf6_network_lsa); + end = (char *) lsa->header + ntohs (lsa->header->length); + for (current = start; current + sizeof (struct ospf6_network_lsdesc) <= end; + current += sizeof (struct ospf6_network_lsdesc)) + { + lsdesc = (struct ospf6_network_lsdesc *) current; + inet_ntop (AF_INET, &lsdesc->router_id, buf, sizeof (buf)); + vty_out (vty, " Attached Router: %s%s", buf, VNL); + } + return 0; +} + +int +ospf6_network_lsa_originate (struct thread *thread) +{ + struct ospf6_interface *oi; + + char buffer [OSPF6_MAX_LSASIZE]; + struct ospf6_lsa_header *lsa_header; + + int count; + struct ospf6_lsa *old, *lsa; + struct ospf6_network_lsa *network_lsa; + struct ospf6_network_lsdesc *lsdesc; + struct ospf6_neighbor *on; + struct ospf6_link_lsa *link_lsa; + listnode i; + u_int16_t type; + + oi = (struct ospf6_interface *) THREAD_ARG (thread); + oi->thread_network_lsa = NULL; + + /* The interface must be enabled until here. A Network-LSA of a + disabled interface (but was once enabled) should be flushed + by ospf6_lsa_refresh (), and does not come here. */ + assert (oi->area); + + old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_NETWORK), + htonl (oi->interface->ifindex), + oi->area->ospf6->router_id, oi->area->lsdb); + + /* Do not originate Network-LSA if not DR */ + if (oi->state != OSPF6_INTERFACE_DR) + { + if (old) + ospf6_lsa_purge (old); + return 0; + } + + if (IS_OSPF6_DEBUG_ORIGINATE (NETWORK)) + zlog_info ("Originate Network-LSA for Interface %s", oi->interface->name); + + /* If none of neighbor is adjacent to us */ + count = 0; + for (i = listhead (oi->neighbor_list); i; nextnode (i)) + { + on = (struct ospf6_neighbor *) getdata (i); + if (on->state == OSPF6_NEIGHBOR_FULL) + count++; + } + if (count == 0) + { + if (IS_OSPF6_DEBUG_ORIGINATE (NETWORK)) + zlog_info ("Interface stub, ignore"); + if (old) + ospf6_lsa_purge (old); + return 0; + } + + /* prepare buffer */ + memset (buffer, 0, sizeof (buffer)); + lsa_header = (struct ospf6_lsa_header *) buffer; + network_lsa = (struct ospf6_network_lsa *) + ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); + + /* Collect the interface's Link-LSAs to describe + network's optional capabilities */ + type = htons (OSPF6_LSTYPE_LINK); + for (lsa = ospf6_lsdb_type_head (type, oi->lsdb); lsa; + lsa = ospf6_lsdb_type_next (type, lsa)) + { + link_lsa = (struct ospf6_link_lsa *) + ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); + network_lsa->options[0] |= link_lsa->options[0]; + network_lsa->options[1] |= link_lsa->options[1]; + network_lsa->options[2] |= link_lsa->options[2]; + } + + lsdesc = (struct ospf6_network_lsdesc *) + ((caddr_t) network_lsa + sizeof (struct ospf6_network_lsa)); + + /* set Link Description to the router itself */ + lsdesc->router_id = oi->area->ospf6->router_id; + lsdesc++; + + /* Walk through the neighbors */ + for (i = listhead (oi->neighbor_list); i; nextnode (i)) + { + on = (struct ospf6_neighbor *) getdata (i); + + if (on->state != OSPF6_NEIGHBOR_FULL) + continue; + + /* set this neighbor's Router-ID to LSA */ + lsdesc->router_id = on->router_id; + lsdesc++; + } + + /* Fill LSA Header */ + lsa_header->age = 0; + lsa_header->type = htons (OSPF6_LSTYPE_NETWORK); + lsa_header->id = htonl (oi->interface->ifindex); + lsa_header->adv_router = oi->area->ospf6->router_id; + lsa_header->seqnum = + ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, + lsa_header->adv_router, oi->area->lsdb); + lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); + + /* LSA checksum */ + ospf6_lsa_checksum (lsa_header); + + /* create LSA */ + lsa = ospf6_lsa_create (lsa_header); + + /* Originate */ + ospf6_lsa_originate_area (lsa, oi->area); + + return 0; +} + + +/****************************/ +/* RFC2740 3.4.3.6 Link-LSA */ +/****************************/ + +int +ospf6_link_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + char *start, *end, *current; + struct ospf6_link_lsa *link_lsa; + int prefixnum; + char buf[128], options[32]; + struct ospf6_prefix *prefix; + char *p, *mc, *la, *nu; + struct in6_addr in6; + + link_lsa = (struct ospf6_link_lsa *) + ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); + + ospf6_options_printbuf (link_lsa->options, options, sizeof (options)); + inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf)); + prefixnum = ntohl (link_lsa->prefix_num); + + vty_out (vty, " Priority: %d Options: %s%s", + link_lsa->priority, options, VNL); + vty_out (vty, " LinkLocal Address: %s%s", buf, VNL); + vty_out (vty, " Number of Prefix: %d%s", prefixnum, VNL); + + start = (char *) link_lsa + sizeof (struct ospf6_link_lsa); + end = (char *) lsa->header + ntohs (lsa->header->length); + for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix)) + { + prefix = (struct ospf6_prefix *) current; + if (prefix->prefix_length == 0 || + current + OSPF6_PREFIX_SIZE (prefix) > end) + break; + + p = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_P) ? + "P" : "--"); + mc = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_MC) ? + "MC" : "--"); + la = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_LA) ? + "LA" : "--"); + nu = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_NU) ? + "NU" : "--"); + vty_out (vty, " Prefix Options: %s|%s|%s|%s%s", + p, mc, la, nu, VNL); + + memset (&in6, 0, sizeof (in6)); + memcpy (&in6, OSPF6_PREFIX_BODY (prefix), + OSPF6_PREFIX_SPACE (prefix->prefix_length)); + inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); + vty_out (vty, " Prefix: %s/%d%s", + buf, prefix->prefix_length, VNL); + } + + return 0; +} + +int +ospf6_link_lsa_originate (struct thread *thread) +{ + struct ospf6_interface *oi; + + char buffer[OSPF6_MAX_LSASIZE]; + struct ospf6_lsa_header *lsa_header; + struct ospf6_lsa *old, *lsa; + + struct ospf6_link_lsa *link_lsa; + struct ospf6_route *route; + struct ospf6_prefix *op; + + oi = (struct ospf6_interface *) THREAD_ARG (thread); + oi->thread_link_lsa = NULL; + + assert (oi->area); + + /* find previous LSA */ + old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_LINK), + htonl (oi->interface->ifindex), + oi->area->ospf6->router_id, oi->lsdb); + + if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE)) + { + if (old) + ospf6_lsa_purge (old); + return 0; + } + + if (IS_OSPF6_DEBUG_ORIGINATE (LINK)) + zlog_info ("Originate Link-LSA for Interface %s", oi->interface->name); + + /* can't make Link-LSA if linklocal address not set */ + if (oi->linklocal_addr == NULL) + { + if (IS_OSPF6_DEBUG_ORIGINATE (LINK)) + zlog_info ("No Linklocal address on %s, defer originating", + oi->interface->name); + if (old) + ospf6_lsa_purge (old); + return 0; + } + + /* prepare buffer */ + memset (buffer, 0, sizeof (buffer)); + lsa_header = (struct ospf6_lsa_header *) buffer; + link_lsa = (struct ospf6_link_lsa *) + ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); + + /* Fill Link-LSA */ + link_lsa->priority = oi->priority; + memcpy (link_lsa->options, oi->area->options, 3); + memcpy (&link_lsa->linklocal_addr, oi->linklocal_addr, + sizeof (struct in6_addr)); + link_lsa->prefix_num = htonl (oi->route_connected->count); + + op = (struct ospf6_prefix *) + ((caddr_t) link_lsa + sizeof (struct ospf6_link_lsa)); + + /* connected prefix to advertise */ + for (route = ospf6_route_head (oi->route_connected); route; + route = ospf6_route_next (route)) + { + op->prefix_length = route->prefix.prefixlen; + op->prefix_options = route->path.prefix_options; + op->prefix_metric = htons (0); + memcpy (OSPF6_PREFIX_BODY (op), &route->prefix.u.prefix6, + OSPF6_PREFIX_SPACE (op->prefix_length)); + op = OSPF6_PREFIX_NEXT (op); + } + + /* Fill LSA Header */ + lsa_header->age = 0; + lsa_header->type = htons (OSPF6_LSTYPE_LINK); + lsa_header->id = htonl (oi->interface->ifindex); + lsa_header->adv_router = oi->area->ospf6->router_id; + lsa_header->seqnum = + ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, + lsa_header->adv_router, oi->lsdb); + lsa_header->length = htons ((caddr_t) op - (caddr_t) buffer); + + /* LSA checksum */ + ospf6_lsa_checksum (lsa_header); + + /* create LSA */ + lsa = ospf6_lsa_create (lsa_header); + + /* Originate */ + ospf6_lsa_originate_interface (lsa, oi); + + return 0; +} + + +/*****************************************/ +/* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */ +/*****************************************/ + +int +ospf6_intra_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + char *start, *end, *current; + struct ospf6_intra_prefix_lsa *intra_prefix_lsa; + int prefixnum; + char buf[128]; + struct ospf6_prefix *prefix; + char id[16], adv_router[16]; + char *p, *mc, *la, *nu; + struct in6_addr in6; + + intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) + ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); + + prefixnum = ntohs (intra_prefix_lsa->prefix_num); + + vty_out (vty, " Number of Prefix: %d%s", prefixnum, VNL); + + inet_ntop (AF_INET, &intra_prefix_lsa->ref_id, id, sizeof (id)); + inet_ntop (AF_INET, &intra_prefix_lsa->ref_adv_router, + adv_router, sizeof (adv_router)); + vty_out (vty, " Reference: %s Id: %s Adv: %s%s", + ospf6_lstype_name (intra_prefix_lsa->ref_type), id, adv_router, + VNL); + + start = (char *) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa); + end = (char *) lsa->header + ntohs (lsa->header->length); + for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix)) + { + prefix = (struct ospf6_prefix *) current; + if (prefix->prefix_length == 0 || + current + OSPF6_PREFIX_SIZE (prefix) > end) + break; + + p = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_P) ? + "P" : "--"); + mc = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_MC) ? + "MC" : "--"); + la = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_LA) ? + "LA" : "--"); + nu = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_NU) ? + "NU" : "--"); + vty_out (vty, " Prefix Options: %s|%s|%s|%s%s", + p, mc, la, nu, VNL); + + memset (&in6, 0, sizeof (in6)); + memcpy (&in6, OSPF6_PREFIX_BODY (prefix), + OSPF6_PREFIX_SPACE (prefix->prefix_length)); + inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); + vty_out (vty, " Prefix: %s/%d%s", + buf, prefix->prefix_length, VNL); + } + + return 0; +} + +int +ospf6_intra_prefix_lsa_originate_stub (struct thread *thread) +{ + struct ospf6_area *oa; + + char buffer[OSPF6_MAX_LSASIZE]; + struct ospf6_lsa_header *lsa_header; + struct ospf6_lsa *old, *lsa; + + struct ospf6_intra_prefix_lsa *intra_prefix_lsa; + struct ospf6_interface *oi; + struct ospf6_neighbor *on; + struct ospf6_route *route; + struct ospf6_prefix *op; + listnode i, j; + int full_count = 0; + unsigned short prefix_num = 0; + char buf[BUFSIZ]; + struct ospf6_route_table *route_advertise; + + oa = (struct ospf6_area *) THREAD_ARG (thread); + oa->thread_intra_prefix_lsa = NULL; + + /* find previous LSA */ + old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_INTRA_PREFIX), + htonl (0), oa->ospf6->router_id, oa->lsdb); + + if (! IS_AREA_ENABLED (oa)) + { + if (old) + ospf6_lsa_purge (old); + return 0; + } + + if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + zlog_info ("Originate Intra-Area-Prefix-LSA for area %s's stub prefix", + oa->name); + + /* prepare buffer */ + memset (buffer, 0, sizeof (buffer)); + lsa_header = (struct ospf6_lsa_header *) buffer; + intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) + ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); + + /* Fill Intra-Area-Prefix-LSA */ + intra_prefix_lsa->ref_type = htons (OSPF6_LSTYPE_ROUTER); + intra_prefix_lsa->ref_id = htonl (0); + intra_prefix_lsa->ref_adv_router = oa->ospf6->router_id; + + route_advertise = ospf6_route_table_create (); + + for (i = listhead (oa->if_list); i; nextnode (i)) + { + oi = (struct ospf6_interface *) getdata (i); + + if (oi->state == OSPF6_INTERFACE_DOWN) + { + if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + zlog_info (" Interface %s is down, ignore", oi->interface->name); + continue; + } + + full_count = 0; + for (j = listhead (oi->neighbor_list); j; nextnode (j)) + { + on = (struct ospf6_neighbor *) getdata (j); + if (on->state == OSPF6_NEIGHBOR_FULL) + full_count++; + } + if (oi->state != OSPF6_INTERFACE_LOOPBACK && + oi->state != OSPF6_INTERFACE_POINTTOPOINT && + full_count != 0) + { + if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + zlog_info (" Interface %s is not stub, ignore", + oi->interface->name); + continue; + } + + if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + zlog_info (" Interface %s:", oi->interface->name); + + /* connected prefix to advertise */ + for (route = ospf6_route_head (oi->route_connected); route; + route = ospf6_route_best_next (route)) + { + if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + { + prefix2str (&route->prefix, buf, sizeof (buf)); + zlog_info (" include %s", buf); + } + ospf6_route_add (ospf6_route_copy (route), route_advertise); + } + } + + if (route_advertise->count == 0) + { + if (old) + ospf6_lsa_purge (old); + ospf6_route_table_delete (route_advertise); + return 0; + } + + /* put prefixes to advertise */ + prefix_num = 0; + op = (struct ospf6_prefix *) + ((caddr_t) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa)); + for (route = ospf6_route_head (route_advertise); route; + route = ospf6_route_best_next (route)) + { + op->prefix_length = route->prefix.prefixlen; + op->prefix_options = route->path.prefix_options; + op->prefix_metric = htons (route->path.cost); + memcpy (OSPF6_PREFIX_BODY (op), &route->prefix.u.prefix6, + OSPF6_PREFIX_SPACE (op->prefix_length)); + op = OSPF6_PREFIX_NEXT (op); + prefix_num++; + } + + ospf6_route_table_delete (route_advertise); + + if (prefix_num == 0) + { + if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + zlog_info ("Quit to Advertise Intra-Prefix: no route to advertise"); + return 0; + } + + intra_prefix_lsa->prefix_num = htons (prefix_num); + + /* Fill LSA Header */ + lsa_header->age = 0; + lsa_header->type = htons (OSPF6_LSTYPE_INTRA_PREFIX); + lsa_header->id = htonl (0); + lsa_header->adv_router = oa->ospf6->router_id; + lsa_header->seqnum = + ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, + lsa_header->adv_router, oa->lsdb); + lsa_header->length = htons ((caddr_t) op - (caddr_t) lsa_header); + + /* LSA checksum */ + ospf6_lsa_checksum (lsa_header); + + /* create LSA */ + lsa = ospf6_lsa_create (lsa_header); + + /* Originate */ + ospf6_lsa_originate_area (lsa, oa); + + return 0; +} + + +int +ospf6_intra_prefix_lsa_originate_transit (struct thread *thread) +{ + struct ospf6_interface *oi; + + char buffer[OSPF6_MAX_LSASIZE]; + struct ospf6_lsa_header *lsa_header; + struct ospf6_lsa *old, *lsa; + + struct ospf6_intra_prefix_lsa *intra_prefix_lsa; + struct ospf6_neighbor *on; + struct ospf6_route *route; + struct ospf6_prefix *op; + listnode i; + int full_count = 0; + unsigned short prefix_num = 0; + struct ospf6_route_table *route_advertise; + struct ospf6_link_lsa *link_lsa; + char *start, *end, *current; + u_int16_t type; + char buf[BUFSIZ]; + + oi = (struct ospf6_interface *) THREAD_ARG (thread); + oi->thread_intra_prefix_lsa = NULL; + + assert (oi->area); + + /* find previous LSA */ + old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_INTRA_PREFIX), + htonl (oi->interface->ifindex), + oi->area->ospf6->router_id, oi->area->lsdb); + + if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE)) + { + if (old) + ospf6_lsa_purge (old); + return 0; + } + + if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + zlog_info ("Originate Intra-Area-Prefix-LSA for interface %s's prefix", + oi->interface->name); + + /* prepare buffer */ + memset (buffer, 0, sizeof (buffer)); + lsa_header = (struct ospf6_lsa_header *) buffer; + intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) + ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); + + /* Fill Intra-Area-Prefix-LSA */ + intra_prefix_lsa->ref_type = htons (OSPF6_LSTYPE_NETWORK); + intra_prefix_lsa->ref_id = htonl (oi->interface->ifindex); + intra_prefix_lsa->ref_adv_router = oi->area->ospf6->router_id; + + if (oi->state != OSPF6_INTERFACE_DR) + { + if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + zlog_info (" Interface is not DR"); + if (old) + ospf6_lsa_purge (old); + return 0; + } + + full_count = 0; + for (i = listhead (oi->neighbor_list); i; nextnode (i)) + { + on = (struct ospf6_neighbor *) getdata (i); + if (on->state == OSPF6_NEIGHBOR_FULL) + full_count++; + } + if (full_count == 0) + { + if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + zlog_info (" Interface is stub"); + if (old) + ospf6_lsa_purge (old); + return 0; + } + + /* connected prefix to advertise */ + route_advertise = ospf6_route_table_create (); + + type = ntohs (OSPF6_LSTYPE_LINK); + for (lsa = ospf6_lsdb_type_head (type, oi->lsdb); lsa; + lsa = ospf6_lsdb_type_next (type, lsa)) + { + if (OSPF6_LSA_IS_MAXAGE (lsa)) + continue; + + if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + zlog_info (" include prefix from %s", lsa->name); + + if (lsa->header->adv_router != oi->area->ospf6->router_id) + { + on = ospf6_neighbor_lookup (lsa->header->adv_router, oi); + if (on == NULL || on->state != OSPF6_NEIGHBOR_FULL) + { + if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + zlog_info (" Neighbor not found or not Full, ignore"); + continue; + } + } + + link_lsa = (struct ospf6_link_lsa *) + ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); + + prefix_num = (unsigned short) ntohl (link_lsa->prefix_num); + start = (char *) link_lsa + sizeof (struct ospf6_link_lsa); + end = (char *) lsa->header + ntohs (lsa->header->length); + for (current = start; current < end && prefix_num; + current += OSPF6_PREFIX_SIZE (op)) + { + op = (struct ospf6_prefix *) current; + if (op->prefix_length == 0 || + current + OSPF6_PREFIX_SIZE (op) > end) + break; + + route = ospf6_route_create (); + + route->type = OSPF6_DEST_TYPE_NETWORK; + route->prefix.family = AF_INET6; + route->prefix.prefixlen = op->prefix_length; + memset (&route->prefix.u.prefix6, 0, sizeof (struct in6_addr)); + memcpy (&route->prefix.u.prefix6, OSPF6_PREFIX_BODY (op), + OSPF6_PREFIX_SPACE (op->prefix_length)); + + route->path.origin.type = lsa->header->type; + route->path.origin.id = lsa->header->id; + route->path.origin.adv_router = lsa->header->adv_router; + route->path.options[0] = link_lsa->options[0]; + route->path.options[1] = link_lsa->options[1]; + route->path.options[2] = link_lsa->options[2]; + route->path.prefix_options = op->prefix_options; + route->path.area_id = oi->area->area_id; + route->path.type = OSPF6_PATH_TYPE_INTRA; + + if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + { + prefix2str (&route->prefix, buf, sizeof (buf)); + zlog_info (" include %s", buf); + } + + ospf6_route_add (route, route_advertise); + prefix_num--; + } + if (current != end && IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + zlog_info ("Trailing garbage in %s", lsa->name); + } + + op = (struct ospf6_prefix *) + ((caddr_t) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa)); + + prefix_num = 0; + for (route = ospf6_route_head (route_advertise); route; + route = ospf6_route_best_next (route)) + { + op->prefix_length = route->prefix.prefixlen; + op->prefix_options = route->path.prefix_options; + op->prefix_metric = htons (0); + memcpy (OSPF6_PREFIX_BODY (op), &route->prefix.u.prefix6, + OSPF6_PREFIX_SPACE (op->prefix_length)); + op = OSPF6_PREFIX_NEXT (op); + prefix_num++; + } + + ospf6_route_table_delete (route_advertise); + + if (prefix_num == 0) + { + if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) + zlog_info ("Quit to Advertise Intra-Prefix: no route to advertise"); + return 0; + } + + intra_prefix_lsa->prefix_num = htons (prefix_num); + + /* Fill LSA Header */ + lsa_header->age = 0; + lsa_header->type = htons (OSPF6_LSTYPE_INTRA_PREFIX); + lsa_header->id = htonl (oi->interface->ifindex); + lsa_header->adv_router = oi->area->ospf6->router_id; + lsa_header->seqnum = + ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, + lsa_header->adv_router, oi->area->lsdb); + lsa_header->length = htons ((caddr_t) op - (caddr_t) lsa_header); + + /* LSA checksum */ + ospf6_lsa_checksum (lsa_header); + + /* create LSA */ + lsa = ospf6_lsa_create (lsa_header); + + /* Originate */ + ospf6_lsa_originate_area (lsa, oi->area); + + return 0; +} + +void +ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa) +{ + struct ospf6_area *oa; + struct ospf6_intra_prefix_lsa *intra_prefix_lsa; + struct prefix ls_prefix; + struct ospf6_route *route, *ls_entry; + int i, prefix_num; + struct ospf6_prefix *op; + char *start, *current, *end; + char buf[64]; + + if (OSPF6_LSA_IS_MAXAGE (lsa)) + return; + + if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) + zlog_info ("%s found", lsa->name); + + oa = OSPF6_AREA (lsa->lsdb->data); + + intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); + if (intra_prefix_lsa->ref_type == htons (OSPF6_LSTYPE_ROUTER)) + ospf6_linkstate_prefix (intra_prefix_lsa->ref_adv_router, + htonl (0), &ls_prefix); + else if (intra_prefix_lsa->ref_type == htons (OSPF6_LSTYPE_NETWORK)) + ospf6_linkstate_prefix (intra_prefix_lsa->ref_adv_router, + intra_prefix_lsa->ref_id, &ls_prefix); + else + { + if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) + zlog_info ("Unknown reference LS-type: %#hx", + ntohs (intra_prefix_lsa->ref_type)); + return; + } + + ls_entry = ospf6_route_lookup (&ls_prefix, oa->spf_table); + if (ls_entry == NULL) + { + if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) + { + ospf6_linkstate_prefix2str (&ls_prefix, buf, sizeof (buf)); + zlog_info ("LS entry does not exist: %s", buf); + } + return; + } + + prefix_num = ntohs (intra_prefix_lsa->prefix_num); + start = (caddr_t) intra_prefix_lsa + + sizeof (struct ospf6_intra_prefix_lsa); + end = OSPF6_LSA_END (lsa->header); + for (current = start; current < end; current += OSPF6_PREFIX_SIZE (op)) + { + op = (struct ospf6_prefix *) current; + if (prefix_num == 0) + break; + if (end < current + OSPF6_PREFIX_SIZE (op)) + break; + + route = ospf6_route_create (); + + memset (&route->prefix, 0, sizeof (struct prefix)); + route->prefix.family = AF_INET6; + route->prefix.prefixlen = op->prefix_length; + ospf6_prefix_in6_addr (&route->prefix.u.prefix6, op); + + route->type = OSPF6_DEST_TYPE_NETWORK; + route->path.origin.type = lsa->header->type; + route->path.origin.id = lsa->header->id; + route->path.origin.adv_router = lsa->header->adv_router; + route->path.prefix_options = op->prefix_options; + route->path.area_id = oa->area_id; + route->path.type = OSPF6_PATH_TYPE_INTRA; + route->path.metric_type = 1; + route->path.cost = ls_entry->path.cost + + ntohs (op->prefix_metric); + + for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) && + i < OSPF6_MULTI_PATH_LIMIT; i++) + ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]); + + if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) + { + prefix2str (&route->prefix, buf, sizeof (buf)); + zlog_info (" add %s", buf); + } + + ospf6_route_add (route, oa->route_table); + prefix_num--; + } + + if (current != end && IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) + zlog_info ("Trailing garbage ignored"); +} + +void +ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa) +{ + struct ospf6_area *oa; + struct ospf6_intra_prefix_lsa *intra_prefix_lsa; + struct prefix prefix; + struct ospf6_route *route; + int prefix_num; + struct ospf6_prefix *op; + char *start, *current, *end; + char buf[64]; + + if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) + zlog_info ("%s disappearing", lsa->name); + + oa = OSPF6_AREA (lsa->lsdb->data); + + intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) + OSPF6_LSA_HEADER_END (lsa->header); + + prefix_num = ntohs (intra_prefix_lsa->prefix_num); + start = (caddr_t) intra_prefix_lsa + + sizeof (struct ospf6_intra_prefix_lsa); + end = OSPF6_LSA_END (lsa->header); + for (current = start; current < end; current += OSPF6_PREFIX_SIZE (op)) + { + op = (struct ospf6_prefix *) current; + if (prefix_num == 0) + break; + if (end < current + OSPF6_PREFIX_SIZE (op)) + break; + prefix_num--; + + memset (&prefix, 0, sizeof (struct prefix)); + prefix.family = AF_INET6; + prefix.prefixlen = op->prefix_length; + ospf6_prefix_in6_addr (&prefix.u.prefix6, op); + + route = ospf6_route_lookup (&prefix, oa->route_table); + if (route == NULL) + continue; + + for (ospf6_route_lock (route); + route && ospf6_route_is_prefix (&prefix, route); + route = ospf6_route_next (route)) + { + if (route->type != OSPF6_DEST_TYPE_NETWORK) + continue; + if (route->path.area_id != oa->area_id) + continue; + if (route->path.type != OSPF6_PATH_TYPE_INTRA) + continue; + if (route->path.origin.type != lsa->header->type || + route->path.origin.id != lsa->header->id || + route->path.origin.adv_router != lsa->header->adv_router) + continue; + + if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) + { + prefix2str (&route->prefix, buf, sizeof (buf)); + zlog_info ("remove %s", buf); + } + ospf6_route_remove (route, oa->route_table); + } + } + + if (current != end && IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) + zlog_info ("Trailing garbage ignored"); +} + +void +ospf6_intra_route_calculation (struct ospf6_area *oa) +{ + struct ospf6_route *route; + u_int16_t type; + struct ospf6_lsa *lsa; + void (*hook_add) (struct ospf6_route *) = NULL; + void (*hook_remove) (struct ospf6_route *) = NULL; + + if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) + zlog_info ("Re-examin intra-routes for area %s", oa->name); + + hook_add = oa->route_table->hook_add; + hook_remove = oa->route_table->hook_remove; + oa->route_table->hook_add = NULL; + oa->route_table->hook_remove = NULL; + + for (route = ospf6_route_head (oa->route_table); route; + route = ospf6_route_next (route)) + route->flag = OSPF6_ROUTE_REMOVE; + + type = htons (OSPF6_LSTYPE_INTRA_PREFIX); + for (lsa = ospf6_lsdb_type_head (type, oa->lsdb); lsa; + lsa = ospf6_lsdb_type_next (type, lsa)) + ospf6_intra_prefix_lsa_add (lsa); + + oa->route_table->hook_add = hook_add; + oa->route_table->hook_remove = hook_remove; + + for (route = ospf6_route_head (oa->route_table); route; + route = ospf6_route_next (route)) + { + if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) && + CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD)) + { + UNSET_FLAG (route->flag, OSPF6_ROUTE_REMOVE); + UNSET_FLAG (route->flag, OSPF6_ROUTE_ADD); + } + + if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE)) + ospf6_route_remove (route, oa->route_table); + else if (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD) || + CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE)) + { + if (hook_add) + (*hook_add) (route); + } + + route->flag = 0; + } + + if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) + zlog_info ("Re-examin intra-routes for area %s: Done", oa->name); +} + +void +ospf6_intra_brouter_calculation (struct ospf6_area *oa) +{ + struct ospf6_route *lsentry, *copy; + void (*hook_add) (struct ospf6_route *) = NULL; + void (*hook_remove) (struct ospf6_route *) = NULL; + char buf[16]; + + if (IS_OSPF6_DEBUG_ROUTE (INTRA)) + zlog_info ("Border-router calculation for area %s", oa->name); + + hook_add = oa->ospf6->brouter_table->hook_add; + hook_remove = oa->ospf6->brouter_table->hook_remove; + oa->ospf6->brouter_table->hook_add = NULL; + oa->ospf6->brouter_table->hook_remove = NULL; + + /* withdraw the previous router entries for the area */ + for (lsentry = ospf6_route_head (oa->ospf6->brouter_table); lsentry; + lsentry = ospf6_route_next (lsentry)) + { + if (lsentry->path.area_id != oa->area_id) + continue; + lsentry->flag = OSPF6_ROUTE_REMOVE; + } + + for (lsentry = ospf6_route_head (oa->spf_table); lsentry; + lsentry = ospf6_route_next (lsentry)) + { + if (lsentry->type != OSPF6_DEST_TYPE_LINKSTATE) + continue; + if (ospf6_linkstate_prefix_id (&lsentry->prefix) != htonl (0)) + continue; + if (! CHECK_FLAG (lsentry->path.router_bits, OSPF6_ROUTER_BIT_E) && + ! CHECK_FLAG (lsentry->path.router_bits, OSPF6_ROUTER_BIT_B)) + continue; + + copy = ospf6_route_copy (lsentry); + copy->type = OSPF6_DEST_TYPE_ROUTER; + copy->path.area_id = oa->area_id; + ospf6_route_add (copy, oa->ospf6->brouter_table); + + if (IS_OSPF6_DEBUG_ROUTE (INTRA)) + { + inet_ntop (AF_INET, &ADV_ROUTER_IN_PREFIX (©->prefix), + buf, sizeof (buf)); + zlog_info ("Re-install router entry %s", buf); + } + } + + oa->ospf6->brouter_table->hook_add = hook_add; + oa->ospf6->brouter_table->hook_remove = hook_remove; + + for (lsentry = ospf6_route_head (oa->ospf6->brouter_table); lsentry; + lsentry = ospf6_route_next (lsentry)) + { + if (lsentry->path.area_id != oa->area_id) + continue; + + if (CHECK_FLAG (lsentry->flag, OSPF6_ROUTE_WAS_REMOVED)) + continue; + + if (CHECK_FLAG (lsentry->flag, OSPF6_ROUTE_REMOVE) && + CHECK_FLAG (lsentry->flag, OSPF6_ROUTE_ADD)) + { + UNSET_FLAG (lsentry->flag, OSPF6_ROUTE_REMOVE); + UNSET_FLAG (lsentry->flag, OSPF6_ROUTE_ADD); + } + + if (CHECK_FLAG (lsentry->flag, OSPF6_ROUTE_REMOVE)) + ospf6_route_remove (lsentry, oa->ospf6->brouter_table); + else if (CHECK_FLAG (lsentry->flag, OSPF6_ROUTE_ADD) || + CHECK_FLAG (lsentry->flag, OSPF6_ROUTE_CHANGE)) + { + if (IS_OSPF6_DEBUG_ROUTE (INTRA)) + { + inet_ntop (AF_INET, &ADV_ROUTER_IN_PREFIX (&lsentry->prefix), + buf, sizeof (buf)); + zlog_info ("Call hook for router entry %s", buf); + } + if (hook_add) + (*hook_add) (lsentry); + } + + lsentry->flag = 0; + } + + if (IS_OSPF6_DEBUG_ROUTE (INTRA)) + zlog_info ("Border-router calculation for area %s: Done", oa->name); +} + +struct ospf6_lsa_handler router_handler = +{ + OSPF6_LSTYPE_ROUTER, + "Router", + ospf6_router_lsa_show +}; + +struct ospf6_lsa_handler network_handler = +{ + OSPF6_LSTYPE_NETWORK, + "Network", + ospf6_network_lsa_show +}; + +struct ospf6_lsa_handler link_handler = +{ + OSPF6_LSTYPE_LINK, + "Link", + ospf6_link_lsa_show +}; + +struct ospf6_lsa_handler intra_prefix_handler = +{ + OSPF6_LSTYPE_INTRA_PREFIX, + "Intra-Prefix", + ospf6_intra_prefix_lsa_show +}; + +void +ospf6_intra_init () +{ + ospf6_install_lsa_handler (&router_handler); + ospf6_install_lsa_handler (&network_handler); + ospf6_install_lsa_handler (&link_handler); + ospf6_install_lsa_handler (&intra_prefix_handler); +} + + diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h new file mode 100644 index 0000000..db92f7e --- /dev/null +++ b/ospf6d/ospf6_intra.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_INTRA_H +#define OSPF6_INTRA_H + +/* Router-LSA */ +struct ospf6_router_lsa +{ + u_char bits; + u_char options[3]; + /* followed by ospf6_router_lsdesc(s) */ +}; + +/* Link State Description in Router-LSA */ +struct ospf6_router_lsdesc +{ + u_char type; + u_char reserved; + u_int16_t metric; /* output cost */ + u_int32_t interface_id; + u_int32_t neighbor_interface_id; + u_int32_t neighbor_router_id; +}; + +#define OSPF6_ROUTER_LSDESC_POINTTOPOINT 1 +#define OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK 2 +#define OSPF6_ROUTER_LSDESC_STUB_NETWORK 3 +#define OSPF6_ROUTER_LSDESC_VIRTUAL_LINK 4 + +#define ROUTER_LSDESC_IS_TYPE(t,x) \ + ((((struct ospf6_router_lsdesc *)(x))->type == \ + OSPF6_ROUTER_LSDESC_ ## t) ? 1 : 0) +#define ROUTER_LSDESC_GET_METRIC(x) \ + (ntohs (((struct ospf6_router_lsdesc *)(x))->metric)) +#define ROUTER_LSDESC_GET_IFID(x) \ + (ntohl (((struct ospf6_router_lsdesc *)(x))->interface_id)) +#define ROUTER_LSDESC_GET_NBR_IFID(x) \ + (ntohl (((struct ospf6_router_lsdesc *)(x))->neighbor_interface_id)) +#define ROUTER_LSDESC_GET_NBR_ROUTERID(x) \ + (((struct ospf6_router_lsdesc *)(x))->neighbor_router_id) + +/* Network-LSA */ +struct ospf6_network_lsa +{ + u_char reserved; + u_char options[3]; + /* followed by ospf6_netowrk_lsd(s) */ +}; + +/* Link State Description in Router-LSA */ +struct ospf6_network_lsdesc +{ + u_int32_t router_id; +}; +#define NETWORK_LSDESC_GET_NBR_ROUTERID(x) \ + (((struct ospf6_network_lsdesc *)(x))->router_id) + +/* Link-LSA */ +struct ospf6_link_lsa +{ + u_char priority; + u_char options[3]; + struct in6_addr linklocal_addr; + u_int32_t prefix_num; + /* followed by ospf6 prefix(es) */ +}; + +/* Intra-Area-Prefix-LSA */ +struct ospf6_intra_prefix_lsa +{ + u_int16_t prefix_num; + u_int16_t ref_type; + u_int32_t ref_id; + u_int32_t ref_adv_router; + /* followed by ospf6 prefix(es) */ +}; + + +#define OSPF6_ROUTER_LSA_SCHEDULE(oa) \ + do { \ + if (! (oa)->thread_router_lsa) \ + (oa)->thread_router_lsa = \ + thread_add_event (master, ospf6_router_lsa_originate, oa, 0); \ + } while (0) +#define OSPF6_NETWORK_LSA_SCHEDULE(oi) \ + do { \ + if (! (oi)->thread_network_lsa) \ + (oi)->thread_network_lsa = \ + thread_add_event (master, ospf6_network_lsa_originate, oi, 0); \ + } while (0) +#define OSPF6_LINK_LSA_SCHEDULE(oi) \ + do { \ + if (! (oi)->thread_link_lsa) \ + (oi)->thread_link_lsa = \ + thread_add_event (master, ospf6_link_lsa_originate, oi, 0); \ + } while (0) +#define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oa) \ + do { \ + if (! (oa)->thread_intra_prefix_lsa) \ + (oa)->thread_intra_prefix_lsa = \ + thread_add_event (master, ospf6_intra_prefix_lsa_originate_stub, \ + oa, 0); \ + } while (0) +#define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(oi) \ + do { \ + if (! (oi)->thread_intra_prefix_lsa) \ + (oi)->thread_intra_prefix_lsa = \ + thread_add_event (master, ospf6_intra_prefix_lsa_originate_transit, \ + oi, 0); \ + } while (0) + +#define OSPF6_NETWORK_LSA_EXECUTE(oi) \ + do { \ + THREAD_OFF ((oi)->thread_network_lsa); \ + thread_execute (master, ospf6_network_lsa_originate, oi, 0); \ + } while (0) +#define OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi) \ + do { \ + THREAD_OFF ((oi)->thread_intra_prefix_lsa); \ + thread_execute (master, ospf6_intra_prefix_lsa_originate_transit, oi, 0); \ + } while (0) + + +/* Function Prototypes */ +char *ospf6_router_lsdesc_lookup (u_char type, u_int32_t interface_id, + u_int32_t neighbor_interface_id, + u_int32_t neighbor_router_id, + struct ospf6_lsa *lsa); +char *ospf6_network_lsdesc_lookup (u_int32_t router_id, + struct ospf6_lsa *lsa); + +int ospf6_router_lsa_originate (struct thread *); +int ospf6_network_lsa_originate (struct thread *); +int ospf6_link_lsa_originate (struct thread *); +int ospf6_intra_prefix_lsa_originate_transit (struct thread *); +int ospf6_intra_prefix_lsa_originate_stub (struct thread *); +void ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa); +void ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa); + +void ospf6_intra_route_calculation (struct ospf6_area *oa); +void ospf6_intra_brouter_calculation (struct ospf6_area *oa); + +void ospf6_intra_init (); + +#endif /* OSPF6_LSA_H */ + diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c new file mode 100644 index 0000000..d4855a6 --- /dev/null +++ b/ospf6d/ospf6_lsa.c @@ -0,0 +1,1001 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +/* Include other stuffs */ +#include "log.h" +#include "linklist.h" +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "memory.h" +#include "thread.h" + +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_message.h" + +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" + +#include "ospf6_flood.h" +#include "ospf6d.h" + +vector ospf6_lsa_handler_vector; + +int +ospf6_unknown_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + u_char *start, *end, *current; + char byte[4]; + + start = (u_char *) lsa->header + sizeof (struct ospf6_lsa_header); + end = (u_char *) lsa->header + ntohs (lsa->header->length); + + vty_out (vty, " Unknown contents:%s", VNL); + for (current = start; current < end; current ++) + { + if ((current - start) % 16 == 0) + vty_out (vty, "%s ", VNL); + else if ((current - start) % 4 == 0) + vty_out (vty, " "); + + snprintf (byte, sizeof (byte), "%02x", *current); + vty_out (vty, "%s", byte); + } + + vty_out (vty, "%s%s", VNL, VNL); + return 0; +} + +struct ospf6_lsa_handler unknown_handler = +{ + OSPF6_LSTYPE_UNKNOWN, + "Unknown", + ospf6_unknown_lsa_show, + OSPF6_LSA_DEBUG, +}; + +void +ospf6_install_lsa_handler (struct ospf6_lsa_handler *handler) +{ + /* type in handler is host byte order */ + int index = handler->type & OSPF6_LSTYPE_FCODE_MASK; + vector_set_index (ospf6_lsa_handler_vector, index, handler); +} + +struct ospf6_lsa_handler * +ospf6_get_lsa_handler (u_int16_t type) +{ + struct ospf6_lsa_handler *handler = NULL; + int index = ntohs (type) & OSPF6_LSTYPE_FCODE_MASK; + + if (ospf6_lsa_handler_vector && + index < vector_max (ospf6_lsa_handler_vector)) + handler = vector_slot (ospf6_lsa_handler_vector, index); + else + handler = &unknown_handler; + + if (handler == NULL) + handler = &unknown_handler; + + return handler; +} + +char * +ospf6_lstype_name (u_int16_t type) +{ + static char buf[8]; + struct ospf6_lsa_handler *handler; + + handler = ospf6_get_lsa_handler (type); + if (handler && handler != &unknown_handler) + return handler->name; + + snprintf (buf, sizeof (buf), "0x%04hx", ntohs (type)); + return buf; +} + +u_char +ospf6_lstype_debug (u_int16_t type) +{ + struct ospf6_lsa_handler *handler; + handler = ospf6_get_lsa_handler (type); + return handler->debug; +} + +/* RFC2328: Section 13.2 */ +int +ospf6_lsa_is_differ (struct ospf6_lsa *lsa1, + struct ospf6_lsa *lsa2) +{ + int len; + + assert (OSPF6_LSA_IS_SAME (lsa1, lsa2)); + + /* XXX, Options ??? */ + + ospf6_lsa_age_current (lsa1); + ospf6_lsa_age_current (lsa2); + if (ntohs (lsa1->header->age) == MAXAGE && + ntohs (lsa2->header->age) != MAXAGE) + return 1; + if (ntohs (lsa1->header->age) != MAXAGE && + ntohs (lsa2->header->age) == MAXAGE) + return 1; + + /* compare body */ + if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length)) + return 1; + + len = ntohs (lsa1->header->length) - sizeof (struct ospf6_lsa_header); + return memcmp (lsa1->header + 1, lsa2->header + 1, len); +} + +int +ospf6_lsa_is_changed (struct ospf6_lsa *lsa1, + struct ospf6_lsa *lsa2) +{ + int length; + + if (OSPF6_LSA_IS_MAXAGE (lsa1) ^ OSPF6_LSA_IS_MAXAGE (lsa2)) + return 1; + if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length)) + return 1; + + length = OSPF6_LSA_SIZE (lsa1->header) - sizeof (struct ospf6_lsa_header); + assert (length > 0); + + return memcmp (OSPF6_LSA_HEADER_END (lsa1->header), + OSPF6_LSA_HEADER_END (lsa2->header), length); +} + +/* ospf6 age functions */ +/* calculate birth */ +static void +ospf6_lsa_age_set (struct ospf6_lsa *lsa) +{ + struct timeval now; + + assert (lsa && lsa->header); + + if (gettimeofday (&now, (struct timezone *)NULL) < 0) + zlog_warn ("LSA: gettimeofday failed, may fail LSA AGEs: %s", + strerror (errno)); + + lsa->birth.tv_sec = now.tv_sec - ntohs (lsa->header->age); + lsa->birth.tv_usec = now.tv_usec; + + return; +} + +/* this function calculates current age from its birth, + then update age field of LSA header. return value is current age */ +u_int16_t +ospf6_lsa_age_current (struct ospf6_lsa *lsa) +{ + struct timeval now; + u_int32_t ulage; + u_int16_t age; + + assert (lsa); + assert (lsa->header); + + /* current time */ + if (gettimeofday (&now, (struct timezone *)NULL) < 0) + zlog_warn ("LSA: gettimeofday failed, may fail LSA AGEs: %s", + strerror (errno)); + + /* calculate age */ + ulage = now.tv_sec - lsa->birth.tv_sec; + + /* if over MAXAGE, set to it */ + age = (ulage > MAXAGE ? MAXAGE : ulage); + + lsa->header->age = htons (age); + return age; +} + +/* update age field of LSA header with adding InfTransDelay */ +void +ospf6_lsa_age_update_to_send (struct ospf6_lsa *lsa, u_int32_t transdelay) +{ + unsigned short age; + + age = ospf6_lsa_age_current (lsa) + transdelay; + if (age > MAXAGE) + age = MAXAGE; + lsa->header->age = htons (age); +} + +void +ospf6_lsa_premature_aging (struct ospf6_lsa *lsa) +{ + /* log */ + if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) + zlog_info ("LSA: Premature aging: %s", lsa->name); + + THREAD_OFF (lsa->expire); + THREAD_OFF (lsa->refresh); + + memset (&lsa->birth, 0, sizeof (struct timeval)); + thread_execute (master, ospf6_lsa_expire, lsa, 0); +} + +/* check which is more recent. if a is more recent, return -1; + if the same, return 0; otherwise(b is more recent), return 1 */ +int +ospf6_lsa_compare (struct ospf6_lsa *a, struct ospf6_lsa *b) +{ + signed long seqnuma, seqnumb; + u_int16_t cksuma, cksumb; + u_int16_t agea, ageb; + + assert (a && a->header); + assert (b && b->header); + assert (OSPF6_LSA_IS_SAME (a, b)); + + seqnuma = ((signed long) ntohl (a->header->seqnum)) + - (signed long) INITIAL_SEQUENCE_NUMBER; + seqnumb = ((signed long) ntohl (b->header->seqnum)) + - (signed long) INITIAL_SEQUENCE_NUMBER; + + /* compare by sequence number */ + /* XXX, LS sequence number wrapping */ + if (seqnuma > seqnumb) + return -1; + else if (seqnuma < seqnumb) + return 1; + + /* Checksum */ + cksuma = ntohs (a->header->checksum); + cksumb = ntohs (b->header->checksum); + if (cksuma > cksumb) + return -1; + if (cksuma < cksumb) + return 0; + + /* Update Age */ + agea = ospf6_lsa_age_current (a); + ageb = ospf6_lsa_age_current (b); + + /* MaxAge check */ + if (agea == MAXAGE && ageb != MAXAGE) + return -1; + else if (agea != MAXAGE && ageb == MAXAGE) + return 1; + + /* Age check */ + if (agea > ageb && agea - ageb >= MAX_AGE_DIFF) + return 1; + else if (agea < ageb && ageb - agea >= MAX_AGE_DIFF) + return -1; + + /* neither recent */ + return 0; +} + +char * +ospf6_lsa_printbuf (struct ospf6_lsa *lsa, char *buf, int size) +{ + char id[16], adv_router[16]; + inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); + inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, + sizeof (adv_router)); + snprintf (buf, size, "[%s Id:%s Adv:%s]", + ospf6_lstype_name (lsa->header->type), id, adv_router); + return buf; +} + +void +ospf6_lsa_header_print_raw (struct ospf6_lsa_header *header) +{ + char id[16], adv_router[16]; + inet_ntop (AF_INET, &header->id, id, sizeof (id)); + inet_ntop (AF_INET, &header->adv_router, adv_router, + sizeof (adv_router)); + zlog_info (" [%s Id:%s Adv:%s]", + ospf6_lstype_name (header->type), id, adv_router); + zlog_info (" Age: %4hu SeqNum: %#08lx Cksum: %04hx Len: %d", + ntohs (header->age), (u_long) ntohl (header->seqnum), + ntohs (header->checksum), ntohs (header->length)); +} + +void +ospf6_lsa_header_print (struct ospf6_lsa *lsa) +{ + ospf6_lsa_age_current (lsa); + ospf6_lsa_header_print_raw (lsa->header); +} + +void +ospf6_lsa_show_summary_header (struct vty *vty) +{ + vty_out (vty, "%-12s %-15s %-15s %4s %8s %4s %4s %-8s%s", + "Type", "LSId", "AdvRouter", "Age", "SeqNum", + "Cksm", "Len", "Duration", VNL); +} + +void +ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa) +{ + char adv_router[16], id[16]; + struct timeval now, res; + char duration[16]; + + assert (lsa); + assert (lsa->header); + + inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); + inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, + sizeof (adv_router)); + + gettimeofday (&now, NULL); + timersub (&now, &lsa->installed, &res); + timerstring (&res, duration, sizeof (duration)); + + vty_out (vty, "%-12s %-15s %-15s %4hu %8lx %04hx %4hu %8s%s", + ospf6_lstype_name (lsa->header->type), + id, adv_router, ospf6_lsa_age_current (lsa), + (u_long) ntohl (lsa->header->seqnum), + ntohs (lsa->header->checksum), ntohs (lsa->header->length), + duration, VNL); +} + +void +ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa) +{ + u_char *start, *end, *current; + char byte[4]; + + start = (u_char *) lsa->header; + end = (u_char *) lsa->header + ntohs (lsa->header->length); + + vty_out (vty, "%s", VNL); + vty_out (vty, "%s:%s", lsa->name, VNL); + + for (current = start; current < end; current ++) + { + if ((current - start) % 16 == 0) + vty_out (vty, "%s ", VNL); + else if ((current - start) % 4 == 0) + vty_out (vty, " "); + + snprintf (byte, sizeof (byte), "%02x", *current); + vty_out (vty, "%s", byte); + } + + vty_out (vty, "%s%s", VNL, VNL); + return; +} + +void +ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa) +{ + char adv_router[64], id[64]; + + assert (lsa && lsa->header); + + inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); + inet_ntop (AF_INET, &lsa->header->adv_router, + adv_router, sizeof (adv_router)); + + vty_out (vty, "%s", VNL); + vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa), + ospf6_lstype_name (lsa->header->type), VNL); + vty_out (vty, "Link State ID: %s%s", id, VNL); + vty_out (vty, "Advertising Router: %s%s", adv_router, VNL); + vty_out (vty, "LS Sequence Number: %#010lx%s", + (u_long) ntohl (lsa->header->seqnum), VNL); + vty_out (vty, "CheckSum: %#06hx Length: %hu%s", + ntohs (lsa->header->checksum), + ntohs (lsa->header->length), VNL); + vty_out (vty, " Prev: %p This: %p Next: %p%s", + lsa->prev, lsa, lsa->next, VNL); + vty_out (vty, "%s", VNL); + return; +} + +void +ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) +{ + char adv_router[64], id[64]; + struct ospf6_lsa_handler *handler; + + assert (lsa && lsa->header); + + inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); + inet_ntop (AF_INET, &lsa->header->adv_router, + adv_router, sizeof (adv_router)); + + vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa), + ospf6_lstype_name (lsa->header->type), VNL); + vty_out (vty, "Link State ID: %s%s", id, VNL); + vty_out (vty, "Advertising Router: %s%s", adv_router, VNL); + vty_out (vty, "LS Sequence Number: %#010lx%s", + (u_long) ntohl (lsa->header->seqnum), VNL); + vty_out (vty, "CheckSum: %#06hx Length: %hu%s", + ntohs (lsa->header->checksum), + ntohs (lsa->header->length), VNL); + + handler = ospf6_get_lsa_handler (lsa->header->type); + if (handler->show == NULL) + handler = &unknown_handler; + (*handler->show) (vty, lsa); + + vty_out (vty, "%s", VNL); +} + +/* OSPFv3 LSA creation/deletion function */ +struct ospf6_lsa * +ospf6_lsa_create (struct ospf6_lsa_header *header) +{ + struct ospf6_lsa *lsa = NULL; + struct ospf6_lsa_header *new_header = NULL; + u_int16_t lsa_size = 0; + + /* size of the entire LSA */ + lsa_size = ntohs (header->length); /* XXX vulnerable */ + + /* allocate memory for this LSA */ + new_header = (struct ospf6_lsa_header *) + XMALLOC (MTYPE_OSPF6_LSA, lsa_size); + + /* copy LSA from original header */ + memcpy (new_header, header, lsa_size); + + /* LSA information structure */ + /* allocate memory */ + lsa = (struct ospf6_lsa *) + XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa)); + memset (lsa, 0, sizeof (struct ospf6_lsa)); + + lsa->header = (struct ospf6_lsa_header *) new_header; + + /* dump string */ + ospf6_lsa_printbuf (lsa, lsa->name, sizeof (lsa->name)); + + /* calculate birth of this lsa */ + ospf6_lsa_age_set (lsa); + + return lsa; +} + +struct ospf6_lsa * +ospf6_lsa_create_headeronly (struct ospf6_lsa_header *header) +{ + struct ospf6_lsa *lsa = NULL; + struct ospf6_lsa_header *new_header = NULL; + + /* allocate memory for this LSA */ + new_header = (struct ospf6_lsa_header *) + XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa_header)); + + /* copy LSA from original header */ + memcpy (new_header, header, sizeof (struct ospf6_lsa_header)); + + /* LSA information structure */ + /* allocate memory */ + lsa = (struct ospf6_lsa *) + XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa)); + memset (lsa, 0, sizeof (struct ospf6_lsa)); + + lsa->header = (struct ospf6_lsa_header *) new_header; + SET_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY); + + /* dump string */ + ospf6_lsa_printbuf (lsa, lsa->name, sizeof (lsa->name)); + + /* calculate birth of this lsa */ + ospf6_lsa_age_set (lsa); + + return lsa; +} + +void +ospf6_lsa_delete (struct ospf6_lsa *lsa) +{ + assert (lsa->lock == 0); + + /* cancel threads */ + THREAD_OFF (lsa->expire); + THREAD_OFF (lsa->refresh); + + /* do free */ + XFREE (MTYPE_OSPF6_LSA, lsa->header); + XFREE (MTYPE_OSPF6_LSA, lsa); +} + +struct ospf6_lsa * +ospf6_lsa_copy (struct ospf6_lsa *lsa) +{ + struct ospf6_lsa *copy = NULL; + + ospf6_lsa_age_current (lsa); + if (CHECK_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY)) + copy = ospf6_lsa_create_headeronly (lsa->header); + else + copy = ospf6_lsa_create (lsa->header); + assert (copy->lock == 0); + + copy->birth = lsa->birth; + copy->originated = lsa->originated; + copy->received = lsa->received; + copy->installed = lsa->installed; + copy->lsdb = lsa->lsdb; + + return copy; +} + +/* increment reference counter of struct ospf6_lsa */ +void +ospf6_lsa_lock (struct ospf6_lsa *lsa) +{ + lsa->lock++; + return; +} + +/* decrement reference counter of struct ospf6_lsa */ +void +ospf6_lsa_unlock (struct ospf6_lsa *lsa) +{ + /* decrement reference counter */ + assert (lsa->lock > 0); + lsa->lock--; + + if (lsa->lock != 0) + return; + + ospf6_lsa_delete (lsa); +} + + +/* ospf6 lsa expiry */ +int +ospf6_lsa_expire (struct thread *thread) +{ + struct ospf6_lsa *lsa; + + lsa = (struct ospf6_lsa *) THREAD_ARG (thread); + + assert (lsa && lsa->header); + assert (OSPF6_LSA_IS_MAXAGE (lsa)); + assert (! lsa->refresh); + + lsa->expire = (struct thread *) NULL; + + if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) + { + zlog_info ("LSA Expire:"); + ospf6_lsa_header_print (lsa); + } + + if (CHECK_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY)) + return 0; /* dbexchange will do something ... */ + + /* reflood lsa */ + ospf6_flood (NULL, lsa); + + /* reinstall lsa */ + ospf6_install_lsa (lsa); + + /* schedule maxage remover */ + ospf6_maxage_remove (ospf6); + + return 0; +} + +int +ospf6_lsa_refresh (struct thread *thread) +{ + struct ospf6_lsa *old, *self, *new; + struct ospf6_lsdb *lsdb_self; + + assert (thread); + old = (struct ospf6_lsa *) THREAD_ARG (thread); + assert (old && old->header); + + old->refresh = (struct thread *) NULL; + + lsdb_self = ospf6_get_scoped_lsdb_self (old); + self = ospf6_lsdb_lookup (old->header->type, old->header->id, + old->header->adv_router, lsdb_self); + if (self == NULL) + { + if (IS_OSPF6_DEBUG_LSA_TYPE (old->header->type)) + zlog_info ("Refresh: could not find self LSA, flush %s", old->name); + ospf6_lsa_premature_aging (old); + return 0; + } + + /* Reset age, increment LS sequence number. */ + self->header->age = htons (0); + self->header->seqnum = + ospf6_new_ls_seqnum (self->header->type, self->header->id, + self->header->adv_router, old->lsdb); + ospf6_lsa_checksum (self->header); + + new = ospf6_lsa_create (self->header); + new->lsdb = old->lsdb; + new->refresh = thread_add_timer (master, ospf6_lsa_refresh, new, + LS_REFRESH_TIME); + + /* store it in the LSDB for self-originated LSAs */ + ospf6_lsdb_add (ospf6_lsa_copy (new), lsdb_self); + + if (IS_OSPF6_DEBUG_LSA_TYPE (new->header->type)) + { + zlog_info ("LSA Refresh:"); + ospf6_lsa_header_print (new); + } + + ospf6_flood_clear (old); + ospf6_flood (NULL, new); + ospf6_install_lsa (new); + + return 0; +} + + + +/* enhanced Fletcher checksum algorithm, RFC1008 7.2 */ +#define MODX 4102 +#define LSA_CHECKSUM_OFFSET 15 + +unsigned short +ospf6_lsa_checksum (struct ospf6_lsa_header *lsa_header) +{ + u_char *sp, *ep, *p, *q; + int c0 = 0, c1 = 0; + int x, y; + u_int16_t length; + + lsa_header->checksum = 0; + length = ntohs (lsa_header->length) - 2; + sp = (u_char *) &lsa_header->type; + + for (ep = sp + length; sp < ep; sp = q) + { + q = sp + MODX; + if (q > ep) + q = ep; + for (p = sp; p < q; p++) + { + c0 += *p; + c1 += c0; + } + c0 %= 255; + c1 %= 255; + } + + /* r = (c1 << 8) + c0; */ + x = ((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255; + if (x <= 0) + x += 255; + y = 510 - c0 - x; + if (y > 255) + y -= 255; + + lsa_header->checksum = htons ((x << 8) + y); + + return (lsa_header->checksum); +} + +void +ospf6_lsa_init () +{ + ospf6_lsa_handler_vector = vector_init (0); + ospf6_install_lsa_handler (&unknown_handler); +} + + +char * +ospf6_lsa_handler_name (struct ospf6_lsa_handler *h) +{ + static char buf[64]; + int i, size = strlen (h->name); + + if (h->name == "Unknown" && + h->type != OSPF6_LSTYPE_UNKNOWN) + { + snprintf (buf, sizeof (buf), "%#04hx", h->type); + return buf; + } + + for (i = 0; i < MIN (size, sizeof (buf)); i++) + { + if (! islower (h->name[i])) + buf[i] = tolower (h->name[i]); + else + buf[i] = h->name[i]; + } + buf[size] = '\0'; + return buf; +} + +DEFUN (debug_ospf6_lsa_type, + debug_ospf6_lsa_hex_cmd, + "debug ospf6 lsa XXXX/0xXXXX", + DEBUG_STR + OSPF6_STR + "Debug Link State Advertisements (LSAs)\n" + "Specify LS type as Hexadecimal\n" + ) +{ + int i; + struct ospf6_lsa_handler *handler = NULL; + unsigned long val; + char *endptr = NULL; + u_int16_t type = 0; + + assert (argc); + + if ((strlen (argv[0]) == 6 && ! strncmp (argv[0], "0x", 2)) || + (strlen (argv[0]) == 4)) + { + val = strtoul (argv[0], &endptr, 16); + if (*endptr == '\0') + type = val; + } + + for (i = 0; i < vector_max (ospf6_lsa_handler_vector); i++) + { + handler = vector_slot (ospf6_lsa_handler_vector, i); + if (handler == NULL) + continue; + if (type && handler->type == type) + break; + if (! strcasecmp (argv[0], handler->name)) + break; + handler = NULL; + } + + if (type && handler == NULL) + { + handler = (struct ospf6_lsa_handler *) + malloc (sizeof (struct ospf6_lsa_handler)); + memset (handler, 0, sizeof (struct ospf6_lsa_handler)); + handler->type = type; + handler->name = "Unknown"; + handler->show = ospf6_unknown_lsa_show; + vector_set_index (ospf6_lsa_handler_vector, + handler->type & OSPF6_LSTYPE_FCODE_MASK, handler); + } + + if (handler == NULL) + handler = &unknown_handler; + + if (argc >= 2) + { + if (! strcmp (argv[1], "originate")) + SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE); + if (! strcmp (argv[1], "examin")) + SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN); + if (! strcmp (argv[1], "flooding")) + SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD); + } + else + SET_FLAG (handler->debug, OSPF6_LSA_DEBUG); + + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf6_lsa_type, + no_debug_ospf6_lsa_hex_cmd, + "no debug ospf6 lsa XXXX/0xXXXX", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug Link State Advertisements (LSAs)\n" + "Specify LS type as Hexadecimal\n" + ) +{ + int i; + struct ospf6_lsa_handler *handler = NULL; + unsigned long val; + char *endptr = NULL; + u_int16_t type = 0; + + assert (argc); + + if ((strlen (argv[0]) == 6 && ! strncmp (argv[0], "0x", 2)) || + (strlen (argv[0]) == 4)) + { + val = strtoul (argv[0], &endptr, 16); + if (*endptr == '\0') + type = val; + } + + for (i = 0; i < vector_max (ospf6_lsa_handler_vector); i++) + { + handler = vector_slot (ospf6_lsa_handler_vector, i); + if (handler == NULL) + continue; + if (type && handler->type == type) + break; + if (! strcasecmp (argv[0], handler->name)) + break; + } + + if (handler == NULL) + return CMD_SUCCESS; + + if (argc >= 2) + { + if (! strcmp (argv[1], "originate")) + UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE); + if (! strcmp (argv[1], "examin")) + UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN); + if (! strcmp (argv[1], "flooding")) + UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD); + } + else + UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG); + + if (handler->debug == 0 && + handler->name == "Unknown" && type != OSPF6_LSTYPE_UNKNOWN) + { + free (handler); + vector_slot (ospf6_lsa_handler_vector, i) = NULL; + } + + return CMD_SUCCESS; +} + +struct cmd_element debug_ospf6_lsa_type_cmd; +struct cmd_element debug_ospf6_lsa_type_detail_cmd; +struct cmd_element no_debug_ospf6_lsa_type_cmd; +struct cmd_element no_debug_ospf6_lsa_type_detail_cmd; + +void +install_element_ospf6_debug_lsa () +{ + int i; + struct ospf6_lsa_handler *handler; +#define STRSIZE 256 +#define DOCSIZE 1024 + static char strbuf[STRSIZE]; + static char docbuf[DOCSIZE]; + static char detail_strbuf[STRSIZE]; + static char detail_docbuf[DOCSIZE]; + char *str, *no_str; + char *doc, *no_doc; + + strbuf[0] = '\0'; + no_str = &strbuf[strlen (strbuf)]; + strncat (strbuf, "no ", STRSIZE - strlen (strbuf)); + str = &strbuf[strlen (strbuf)]; + + strncat (strbuf, "debug ospf6 lsa (", STRSIZE - strlen (strbuf)); + for (i = 0; i < vector_max (ospf6_lsa_handler_vector); i++) + { + handler = vector_slot (ospf6_lsa_handler_vector, i); + if (handler == NULL) + continue; + strncat (strbuf, ospf6_lsa_handler_name (handler), + STRSIZE - strlen (strbuf)); + strncat (strbuf, "|", STRSIZE - strlen (strbuf)); + } + strbuf[strlen (strbuf) - 1] = ')'; + strbuf[strlen (strbuf)] = '\0'; + + docbuf[0] = '\0'; + no_doc = &docbuf[strlen (docbuf)]; + strncat (docbuf, NO_STR, DOCSIZE - strlen (docbuf)); + doc = &docbuf[strlen (docbuf)]; + + strncat (docbuf, DEBUG_STR, DOCSIZE - strlen (docbuf)); + strncat (docbuf, OSPF6_STR, DOCSIZE - strlen (docbuf)); + strncat (docbuf, "Debug Link State Advertisements (LSAs)\n", + DOCSIZE - strlen (docbuf)); + + for (i = 0; i < vector_max (ospf6_lsa_handler_vector); i++) + { + handler = vector_slot (ospf6_lsa_handler_vector, i); + if (handler == NULL) + continue; + strncat (docbuf, "Debug ", DOCSIZE - strlen (docbuf)); + strncat (docbuf, handler->name, DOCSIZE - strlen (docbuf)); + strncat (docbuf, "-LSA\n", DOCSIZE - strlen (docbuf)); + } + docbuf[strlen (docbuf)] = '\0'; + + debug_ospf6_lsa_type_cmd.string = str; + debug_ospf6_lsa_type_cmd.func = debug_ospf6_lsa_type; + debug_ospf6_lsa_type_cmd.doc = doc; + + no_debug_ospf6_lsa_type_cmd.string = no_str; + no_debug_ospf6_lsa_type_cmd.func = no_debug_ospf6_lsa_type; + no_debug_ospf6_lsa_type_cmd.doc = no_doc; + + strncpy (detail_strbuf, strbuf, STRSIZE); + strncat (detail_strbuf, " (originate|examin|flooding)", + STRSIZE - strlen (detail_strbuf)); + detail_strbuf[strlen (detail_strbuf)] = '\0'; + no_str = &detail_strbuf[0]; + str = &detail_strbuf[strlen ("no ")]; + + strncpy (detail_docbuf, docbuf, DOCSIZE); + strncat (detail_docbuf, "Debug Originating LSA\n", + DOCSIZE - strlen (detail_docbuf)); + strncat (detail_docbuf, "Debug Examining LSA\n", + DOCSIZE - strlen (detail_docbuf)); + strncat (detail_docbuf, "Debug Flooding LSA\n", + DOCSIZE - strlen (detail_docbuf)); + detail_docbuf[strlen (detail_docbuf)] = '\0'; + no_doc = &detail_docbuf[0]; + doc = &detail_docbuf[strlen (NO_STR)]; + + debug_ospf6_lsa_type_detail_cmd.string = str; + debug_ospf6_lsa_type_detail_cmd.func = debug_ospf6_lsa_type; + debug_ospf6_lsa_type_detail_cmd.doc = doc; + + no_debug_ospf6_lsa_type_detail_cmd.string = no_str; + no_debug_ospf6_lsa_type_detail_cmd.func = no_debug_ospf6_lsa_type; + no_debug_ospf6_lsa_type_detail_cmd.doc = no_doc; + + install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_cmd); + install_element (ENABLE_NODE, &debug_ospf6_lsa_type_cmd); + install_element (ENABLE_NODE, &debug_ospf6_lsa_type_detail_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_lsa_type_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_lsa_type_detail_cmd); + install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_cmd); + install_element (CONFIG_NODE, &debug_ospf6_lsa_type_cmd); + install_element (CONFIG_NODE, &debug_ospf6_lsa_type_detail_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_lsa_type_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_lsa_type_detail_cmd); +} + +int +config_write_ospf6_debug_lsa (struct vty *vty) +{ + int i; + struct ospf6_lsa_handler *handler; + + for (i = 0; i < vector_max (ospf6_lsa_handler_vector); i++) + { + handler = vector_slot (ospf6_lsa_handler_vector, i); + if (handler == NULL) + continue; + if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG)) + vty_out (vty, "debug ospf6 lsa %s%s", + ospf6_lsa_handler_name (handler), VNL); + if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE)) + vty_out (vty, "debug ospf6 lsa %s originate%s", + ospf6_lsa_handler_name (handler), VNL); + if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN)) + vty_out (vty, "debug ospf6 lsa %s examin%s", + ospf6_lsa_handler_name (handler), VNL); + if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD)) + vty_out (vty, "debug ospf6 lsa %s flooding%s", + ospf6_lsa_handler_name (handler), VNL); + } + + return 0; +} + + diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h new file mode 100644 index 0000000..0623adf --- /dev/null +++ b/ospf6d/ospf6_lsa.h @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_LSA_H +#define OSPF6_LSA_H + +/* Debug option */ +#define OSPF6_LSA_DEBUG 0x01 +#define OSPF6_LSA_DEBUG_ORIGINATE 0x02 +#define OSPF6_LSA_DEBUG_EXAMIN 0x04 +#define OSPF6_LSA_DEBUG_FLOOD 0x08 + +#define IS_OSPF6_DEBUG_LSA(name) \ + (ospf6_lstype_debug (htons (OSPF6_LSTYPE_ ## name)) & \ + OSPF6_LSA_DEBUG) +#define IS_OSPF6_DEBUG_ORIGINATE(name) \ + (ospf6_lstype_debug (htons (OSPF6_LSTYPE_ ## name)) & \ + OSPF6_LSA_DEBUG_ORIGINATE) +#define IS_OSPF6_DEBUG_EXAMIN(name) \ + (ospf6_lstype_debug (htons (OSPF6_LSTYPE_ ## name)) & \ + OSPF6_LSA_DEBUG_EXAMIN) +#define IS_OSPF6_DEBUG_LSA_TYPE(type) \ + (ospf6_lstype_debug (type) & OSPF6_LSA_DEBUG) +#define IS_OSPF6_DEBUG_ORIGINATE_TYPE(type) \ + (ospf6_lstype_debug (type) & OSPF6_LSA_DEBUG_ORIGINATE) +#define IS_OSPF6_DEBUG_EXAMIN_TYPE(type) \ + (ospf6_lstype_debug (type) & OSPF6_LSA_DEBUG_EXAMIN) +#define IS_OSPF6_DEBUG_FLOOD_TYPE(type) \ + (ospf6_lstype_debug (type) & OSPF6_LSA_DEBUG_FLOOD) + +/* LSA definition */ + +#define OSPF6_MAX_LSASIZE 4096 + +/* Type */ +#define OSPF6_LSTYPE_UNKNOWN 0x0000 +#define OSPF6_LSTYPE_ROUTER 0x2001 +#define OSPF6_LSTYPE_NETWORK 0x2002 +#define OSPF6_LSTYPE_INTER_PREFIX 0x2003 +#define OSPF6_LSTYPE_INTER_ROUTER 0x2004 +#define OSPF6_LSTYPE_AS_EXTERNAL 0x4005 +#define OSPF6_LSTYPE_GROUP_MEMBERSHIP 0x2006 +#define OSPF6_LSTYPE_TYPE_7 0x2007 +#define OSPF6_LSTYPE_LINK 0x0008 +#define OSPF6_LSTYPE_INTRA_PREFIX 0x2009 +#define OSPF6_LSTYPE_SIZE 0x000a + +/* Masks for LS Type : RFC 2740 A.4.2.1 "LS type" */ +#define OSPF6_LSTYPE_UBIT_MASK 0x8000 +#define OSPF6_LSTYPE_SCOPE_MASK 0x6000 +#define OSPF6_LSTYPE_FCODE_MASK 0x1fff + +/* LSA scope */ +#define OSPF6_SCOPE_LINKLOCAL 0x0000 +#define OSPF6_SCOPE_AREA 0x2000 +#define OSPF6_SCOPE_AS 0x4000 +#define OSPF6_SCOPE_RESERVED 0x6000 + +/* XXX U-bit handling should be treated here */ +#define OSPF6_LSA_SCOPE(type) \ + (ntohs (type) & OSPF6_LSTYPE_SCOPE_MASK) + +/* LSA Header */ +struct ospf6_lsa_header +{ + u_int16_t age; /* LS age */ + u_int16_t type; /* LS type */ + u_int32_t id; /* Link State ID */ + u_int32_t adv_router; /* Advertising Router */ + u_int32_t seqnum; /* LS sequence number */ + u_int16_t checksum; /* LS checksum */ + u_int16_t length; /* LSA length */ +}; + +#define OSPF6_LSA_HEADER_END(h) \ + ((caddr_t)(h) + sizeof (struct ospf6_lsa_header)) +#define OSPF6_LSA_SIZE(h) \ + (ntohs (((struct ospf6_lsa_header *) (h))->length)) +#define OSPF6_LSA_END(h) \ + ((caddr_t)(h) + ntohs (((struct ospf6_lsa_header *) (h))->length)) +#define OSPF6_LSA_IS_TYPE(t, L) \ + ((L)->header->type == htons (OSPF6_LSTYPE_ ## t) ? 1 : 0) +#define OSPF6_LSA_IS_SAME(L1, L2) \ + ((L1)->header->adv_router == (L2)->header->adv_router && \ + (L1)->header->id == (L2)->header->id && \ + (L1)->header->type == (L2)->header->type) +#define OSPF6_LSA_IS_MATCH(t, i, a, L) \ + ((L)->header->adv_router == (a) && (L)->header->id == (i) && \ + (L)->header->type == (t)) +#define OSPF6_LSA_IS_DIFFER(L1, L2) ospf6_lsa_is_differ (L1, L2) +#define OSPF6_LSA_IS_MAXAGE(L) (ospf6_lsa_age_current (L) == MAXAGE) +#define OSPF6_LSA_IS_CHANGED(L1, L2) ospf6_lsa_is_changed (L1, L2) + +struct ospf6_lsa +{ + char name[64]; /* dump string */ + + struct ospf6_lsa *prev; + struct ospf6_lsa *next; + + unsigned char lock; /* reference counter */ + unsigned char flag; /* special meaning (e.g. floodback) */ + + struct timeval birth; /* tv_sec when LS age 0 */ + struct timeval originated; /* used by MinLSInterval check */ + struct timeval received; /* used by MinLSArrival check */ + struct timeval installed; + + struct thread *expire; + struct thread *refresh; /* For self-originated LSA */ + + int retrans_count; + + struct ospf6_lsdb *lsdb; + + /* lsa instance */ + struct ospf6_lsa_header *header; +}; + +#define OSPF6_LSA_HEADERONLY 0x01 +#define OSPF6_LSA_FLOODBACK 0x02 +#define OSPF6_LSA_DUPLICATE 0x04 +#define OSPF6_LSA_IMPLIEDACK 0x08 + +struct ospf6_lsa_handler +{ + u_int16_t type; /* host byte order */ + char *name; + int (*show) (struct vty *, struct ospf6_lsa *); + u_char debug; +}; + +extern struct ospf6_lsa_handler unknown_handler; +#define OSPF6_LSA_IS_KNOWN(type) \ + (ospf6_get_lsa_handler (type) != &unknown_handler ? 1 : 0) + +/* Macro for LSA Origination */ +/* addr is (struct prefix *) */ +#define CONTINUE_IF_ADDRESS_LINKLOCAL(debug,addr) \ + if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6)) \ + { \ + char buf[64]; \ + prefix2str (addr, buf, sizeof (buf)); \ + if (debug) \ + zlog_info ("Filter out Linklocal: %s", buf); \ + continue; \ + } + +#define CONTINUE_IF_ADDRESS_UNSPECIFIED(debug,addr) \ + if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6)) \ + { \ + char buf[64]; \ + prefix2str (addr, buf, sizeof (buf)); \ + if (debug) \ + zlog_info ("Filter out Unspecified: %s", buf); \ + continue; \ + } + +#define CONTINUE_IF_ADDRESS_LOOPBACK(debug,addr) \ + if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6)) \ + { \ + char buf[64]; \ + prefix2str (addr, buf, sizeof (buf)); \ + if (debug) \ + zlog_info ("Filter out Loopback: %s", buf); \ + continue; \ + } + +#define CONTINUE_IF_ADDRESS_V4COMPAT(debug,addr) \ + if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6)) \ + { \ + char buf[64]; \ + prefix2str (addr, buf, sizeof (buf)); \ + if (debug) \ + zlog_info ("Filter out V4Compat: %s", buf); \ + continue; \ + } + +#define CONTINUE_IF_ADDRESS_V4MAPPED(debug,addr) \ + if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6)) \ + { \ + char buf[64]; \ + prefix2str (addr, buf, sizeof (buf)); \ + if (debug) \ + zlog_info ("Filter out V4Mapped: %s", buf); \ + continue; \ + } + + +/* Function Prototypes */ +char *ospf6_lstype_name (u_int16_t type); +u_char ospf6_lstype_debug (u_int16_t type); +int ospf6_lsa_is_differ (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2); +int ospf6_lsa_is_changed (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2); +u_int16_t ospf6_lsa_age_current (struct ospf6_lsa *); +void ospf6_lsa_age_update_to_send (struct ospf6_lsa *, u_int32_t); +void ospf6_lsa_premature_aging (struct ospf6_lsa *); +int ospf6_lsa_compare (struct ospf6_lsa *, struct ospf6_lsa *); + +char *ospf6_lsa_printbuf (struct ospf6_lsa *lsa, char *buf, int size); +void ospf6_lsa_header_print_raw (struct ospf6_lsa_header *header); +void ospf6_lsa_header_print (struct ospf6_lsa *lsa); +void ospf6_lsa_show_summary_header (struct vty *vty); +void ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa); +void ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa); +void ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa); +void ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa); + +struct ospf6_lsa *ospf6_lsa_create (struct ospf6_lsa_header *header); +struct ospf6_lsa *ospf6_lsa_create_headeronly (struct ospf6_lsa_header *header); +void ospf6_lsa_delete (struct ospf6_lsa *lsa); +struct ospf6_lsa *ospf6_lsa_copy (struct ospf6_lsa *); + +void ospf6_lsa_lock (struct ospf6_lsa *); +void ospf6_lsa_unlock (struct ospf6_lsa *); + +int ospf6_lsa_expire (struct thread *); +int ospf6_lsa_refresh (struct thread *); + +unsigned short ospf6_lsa_checksum (struct ospf6_lsa_header *); +int ospf6_lsa_prohibited_duration (u_int16_t type, u_int32_t id, + u_int32_t adv_router, void *scope); + +void ospf6_install_lsa_handler (struct ospf6_lsa_handler *handler); +struct ospf6_lsa_handler *ospf6_get_lsa_handler (u_int16_t type); + +void ospf6_lsa_init (); +void ospf6_lsa_cmd_init (); + +int config_write_ospf6_debug_lsa (struct vty *vty); +void install_element_ospf6_debug_lsa (); + +#endif /* OSPF6_LSA_H */ + diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c new file mode 100644 index 0000000..706e406 --- /dev/null +++ b/ospf6d/ospf6_lsdb.c @@ -0,0 +1,584 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "log.h" +#include "command.h" +#include "prefix.h" +#include "table.h" +#include "vty.h" + +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6d.h" + +struct ospf6_lsdb * +ospf6_lsdb_create (void *data) +{ + struct ospf6_lsdb *lsdb; + + lsdb = XCALLOC (MTYPE_OSPF6_LSDB, sizeof (struct ospf6_lsdb)); + if (lsdb == NULL) + { + zlog_warn ("Can't malloc lsdb"); + return NULL; + } + memset (lsdb, 0, sizeof (struct ospf6_lsdb)); + + lsdb->data = data; + lsdb->table = route_table_init (); + return lsdb; +} + +void +ospf6_lsdb_delete (struct ospf6_lsdb *lsdb) +{ + ospf6_lsdb_remove_all (lsdb); + route_table_finish (lsdb->table); + XFREE (MTYPE_OSPF6_LSDB, lsdb); +} + +static void +ospf6_lsdb_set_key (struct prefix_ipv6 *key, void *value, int len) +{ + assert (key->prefixlen % 8 == 0); + + memcpy ((caddr_t) &key->prefix + key->prefixlen / 8, + (caddr_t) value, len); + key->family = AF_INET6; + key->prefixlen += len * 8; +} + +#ifndef NDEBUG +static void +_lsdb_count_assert (struct ospf6_lsdb *lsdb) +{ + struct ospf6_lsa *debug; + int num = 0; + for (debug = ospf6_lsdb_head (lsdb); debug; + debug = ospf6_lsdb_next (debug)) + num++; + + if (num == lsdb->count) + return; + + zlog_info ("PANIC !! lsdb[%p]->count = %d, real = %d", + lsdb, lsdb->count, num); + for (debug = ospf6_lsdb_head (lsdb); debug; + debug = ospf6_lsdb_next (debug)) + zlog_info ("%p %p %s lsdb[%p]", debug->prev, debug->next, debug->name, + debug->lsdb); + zlog_info ("DUMP END"); + + assert (num == lsdb->count); +} +#define ospf6_lsdb_count_assert(t) (_lsdb_count_assert (t)) +#else /*NDEBUG*/ +#define ospf6_lsdb_count_assert(t) ((void) 0) +#endif /*NDEBUG*/ + +void +ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) +{ + struct prefix_ipv6 key; + struct route_node *current, *nextnode, *prevnode; + struct ospf6_lsa *next, *prev, *old = NULL; + + memset (&key, 0, sizeof (key)); + ospf6_lsdb_set_key (&key, &lsa->header->type, sizeof (lsa->header->type)); + ospf6_lsdb_set_key (&key, &lsa->header->adv_router, + sizeof (lsa->header->adv_router)); + ospf6_lsdb_set_key (&key, &lsa->header->id, sizeof (lsa->header->id)); + + current = route_node_get (lsdb->table, (struct prefix *) &key); + old = current->info; + current->info = lsa; + ospf6_lsa_lock (lsa); + + if (old) + { + if (old->prev) + old->prev->next = lsa; + if (old->next) + old->next->prev = lsa; + lsa->next = old->next; + lsa->prev = old->prev; + } + else + { + /* next link */ + nextnode = current; + route_lock_node (nextnode); + do { + nextnode = route_next (nextnode); + } while (nextnode && nextnode->info == NULL); + if (nextnode == NULL) + lsa->next = NULL; + else + { + next = nextnode->info; + lsa->next = next; + next->prev = lsa; + route_unlock_node (nextnode); + } + + /* prev link */ + prevnode = current; + route_lock_node (prevnode); + do { + prevnode = route_prev (prevnode); + } while (prevnode && prevnode->info == NULL); + if (prevnode == NULL) + lsa->prev = NULL; + else + { + prev = prevnode->info; + lsa->prev = prev; + prev->next = lsa; + route_unlock_node (prevnode); + } + + lsdb->count++; + } + + if (old) + { + if (OSPF6_LSA_IS_CHANGED (old, lsa)) + { + if (OSPF6_LSA_IS_MAXAGE (lsa)) + { + if (lsdb->hook_remove) + { + (*lsdb->hook_remove) (old); + (*lsdb->hook_remove) (lsa); + } + } + else if (OSPF6_LSA_IS_MAXAGE (old)) + { + if (lsdb->hook_add) + (*lsdb->hook_add) (lsa); + } + else + { + if (lsdb->hook_remove) + (*lsdb->hook_remove) (old); + if (lsdb->hook_add) + (*lsdb->hook_add) (lsa); + } + } + } + else if (OSPF6_LSA_IS_MAXAGE (lsa)) + { + if (lsdb->hook_remove) + (*lsdb->hook_remove) (lsa); + } + else + { + if (lsdb->hook_add) + (*lsdb->hook_add) (lsa); + } + + if (old) + ospf6_lsa_unlock (old); + +#if 0 + ospf6_lsdb_count_assert (lsdb); +#endif +} + +void +ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) +{ + struct route_node *node; + struct prefix_ipv6 key; + + memset (&key, 0, sizeof (key)); + ospf6_lsdb_set_key (&key, &lsa->header->type, sizeof (lsa->header->type)); + ospf6_lsdb_set_key (&key, &lsa->header->adv_router, + sizeof (lsa->header->adv_router)); + ospf6_lsdb_set_key (&key, &lsa->header->id, sizeof (lsa->header->id)); + + node = route_node_lookup (lsdb->table, (struct prefix *) &key); + assert (node && node->info == lsa); + + if (lsa->prev) + lsa->prev->next = lsa->next; + if (lsa->next) + lsa->next->prev = lsa->prev; + + node->info = NULL; + lsdb->count--; + + if (lsdb->hook_remove) + (*lsdb->hook_remove) (lsa); + + ospf6_lsa_unlock (lsa); + route_unlock_node (node); + + ospf6_lsdb_count_assert (lsdb); +} + +struct ospf6_lsa * +ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router, + struct ospf6_lsdb *lsdb) +{ + struct route_node *node; + struct prefix_ipv6 key; + + if (lsdb == NULL) + return NULL; + + memset (&key, 0, sizeof (key)); + ospf6_lsdb_set_key (&key, &type, sizeof (type)); + ospf6_lsdb_set_key (&key, &adv_router, sizeof (adv_router)); + ospf6_lsdb_set_key (&key, &id, sizeof (id)); + + node = route_node_lookup (lsdb->table, (struct prefix *) &key); + if (node == NULL || node->info == NULL) + return NULL; + return (struct ospf6_lsa *) node->info; +} + +/* Macro version of check_bit (). */ +#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1) + +struct ospf6_lsa * +ospf6_lsdb_lookup_next (u_int16_t type, u_int32_t id, u_int32_t adv_router, + struct ospf6_lsdb *lsdb) +{ + struct route_node *node; + struct route_node *matched = NULL; + struct prefix_ipv6 key; + struct prefix *p; + + if (lsdb == NULL) + return NULL; + + memset (&key, 0, sizeof (key)); + ospf6_lsdb_set_key (&key, &type, sizeof (type)); + ospf6_lsdb_set_key (&key, &adv_router, sizeof (adv_router)); + ospf6_lsdb_set_key (&key, &id, sizeof (id)); + p = (struct prefix *) &key; + + { + char buf[64]; + prefix2str (p, buf, sizeof (buf)); + zlog_info ("lsdb_lookup_next: key: %s", buf); + } + + node = lsdb->table->top; + /* walk down tree. */ + while (node && node->p.prefixlen <= p->prefixlen && + prefix_match (&node->p, p)) + { + matched = node; + node = node->link[CHECK_BIT(&p->u.prefix, node->p.prefixlen)]; + } + + if (matched) + node = matched; + else + node = lsdb->table->top; + route_lock_node (node); + + /* skip to real existing entry */ + while (node && node->info == NULL) + node = route_next (node); + + if (! node) + return NULL; + + if (prefix_same (&node->p, p)) + { + struct route_node *prev = node; + struct ospf6_lsa *lsa_prev; + struct ospf6_lsa *lsa_next; + + node = route_next (node); + while (node && node->info == NULL) + node = route_next (node); + + lsa_prev = prev->info; + lsa_next = (node ? node->info : NULL); + assert (lsa_prev); + assert (lsa_prev->next == lsa_next); + if (lsa_next) + assert (lsa_next->prev == lsa_prev); + zlog_info ("lsdb_lookup_next: assert OK with previous LSA"); + } + + if (! node) + return NULL; + + route_unlock_node (node); + return (struct ospf6_lsa *) node->info; +} + +/* Iteration function */ +struct ospf6_lsa * +ospf6_lsdb_head (struct ospf6_lsdb *lsdb) +{ + struct route_node *node; + + node = route_top (lsdb->table); + if (node == NULL) + return NULL; + + /* skip to the existing lsdb entry */ + while (node && node->info == NULL) + node = route_next (node); + if (node == NULL) + return NULL; + + route_unlock_node (node); + if (node->info) + ospf6_lsa_lock ((struct ospf6_lsa *) node->info); + return (struct ospf6_lsa *) node->info; +} + +struct ospf6_lsa * +ospf6_lsdb_next (struct ospf6_lsa *lsa) +{ + struct ospf6_lsa *next = lsa->next; + + ospf6_lsa_unlock (lsa); + if (next) + ospf6_lsa_lock (next); + + return next; +} + +struct ospf6_lsa * +ospf6_lsdb_type_router_head (u_int16_t type, u_int32_t adv_router, + struct ospf6_lsdb *lsdb) +{ + struct route_node *node; + struct prefix_ipv6 key; + struct ospf6_lsa *lsa; + + memset (&key, 0, sizeof (key)); + ospf6_lsdb_set_key (&key, &type, sizeof (type)); + ospf6_lsdb_set_key (&key, &adv_router, sizeof (adv_router)); + + node = lsdb->table->top; + + /* Walk down tree. */ + while (node && node->p.prefixlen <= key.prefixlen && + prefix_match (&node->p, (struct prefix *) &key)) + node = node->link[CHECK_BIT(&key.prefix, node->p.prefixlen)]; + + if (node) + route_lock_node (node); + while (node && node->info == NULL) + node = route_next (node); + + if (node == NULL) + return NULL; + else + route_unlock_node (node); + + if (! prefix_match ((struct prefix *) &key, &node->p)) + return NULL; + + lsa = node->info; + ospf6_lsa_lock (lsa); + + return lsa; +} + +struct ospf6_lsa * +ospf6_lsdb_type_router_next (u_int16_t type, u_int32_t adv_router, + struct ospf6_lsa *lsa) +{ + struct ospf6_lsa *next = lsa->next; + + if (next) + { + if (next->header->type != type || + next->header->adv_router != adv_router) + next = NULL; + } + + if (next) + ospf6_lsa_lock (next); + ospf6_lsa_unlock (lsa); + return next; +} + +struct ospf6_lsa * +ospf6_lsdb_type_head (u_int16_t type, struct ospf6_lsdb *lsdb) +{ + struct route_node *node; + struct prefix_ipv6 key; + struct ospf6_lsa *lsa; + + memset (&key, 0, sizeof (key)); + ospf6_lsdb_set_key (&key, &type, sizeof (type)); + + /* Walk down tree. */ + node = lsdb->table->top; + while (node && node->p.prefixlen <= key.prefixlen && + prefix_match (&node->p, (struct prefix *) &key)) + node = node->link[CHECK_BIT(&key.prefix, node->p.prefixlen)]; + + if (node) + route_lock_node (node); + while (node && node->info == NULL) + node = route_next (node); + + if (node == NULL) + return NULL; + else + route_unlock_node (node); + + if (! prefix_match ((struct prefix *) &key, &node->p)) + return NULL; + + lsa = node->info; + ospf6_lsa_lock (lsa); + + return lsa; +} + +struct ospf6_lsa * +ospf6_lsdb_type_next (u_int16_t type, struct ospf6_lsa *lsa) +{ + struct ospf6_lsa *next = lsa->next; + + if (next) + { + if (next->header->type != type) + next = NULL; + } + + if (next) + ospf6_lsa_lock (next); + ospf6_lsa_unlock (lsa); + return next; +} + +void +ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb) +{ + struct ospf6_lsa *lsa; + for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) + ospf6_lsdb_remove (lsa, lsdb); +} + +void +ospf6_lsdb_show (struct vty *vty, int level, + u_int16_t *type, u_int32_t *id, u_int32_t *adv_router, + struct ospf6_lsdb *lsdb) +{ + struct ospf6_lsa *lsa; + void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL; + + if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) + showfunc = ospf6_lsa_show_summary; + else if (level == OSPF6_LSDB_SHOW_LEVEL_DETAIL) + showfunc = ospf6_lsa_show; + else if (level == OSPF6_LSDB_SHOW_LEVEL_INTERNAL) + showfunc = ospf6_lsa_show_internal; + else if (level == OSPF6_LSDB_SHOW_LEVEL_DUMP) + showfunc = ospf6_lsa_show_dump; + + if (type && id && adv_router) + { + lsa = ospf6_lsdb_lookup (*type, *id, *adv_router, lsdb); + if (lsa) + { + if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) + ospf6_lsa_show (vty, lsa); + else + (*showfunc) (vty, lsa); + } + return; + } + + if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) + ospf6_lsa_show_summary_header (vty); + + if (type && adv_router) + lsa = ospf6_lsdb_type_router_head (*type, *adv_router, lsdb); + else if (type) + lsa = ospf6_lsdb_type_head (*type, lsdb); + else + lsa = ospf6_lsdb_head (lsdb); + while (lsa) + { + if ((! adv_router || lsa->header->adv_router == *adv_router) && + (! id || lsa->header->id == *id)) + (*showfunc) (vty, lsa); + + if (type && adv_router) + lsa = ospf6_lsdb_type_router_next (*type, *adv_router, lsa); + else if (type) + lsa = ospf6_lsdb_type_next (*type, lsa); + else + lsa = ospf6_lsdb_next (lsa); + } +} + +/* Decide new Link State ID to originate. + note return value is network byte order */ +u_int32_t +ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router, + struct ospf6_lsdb *lsdb) +{ + struct ospf6_lsa *lsa; + u_int32_t id = 1; + + for (lsa = ospf6_lsdb_type_router_head (type, adv_router, lsdb); lsa; + lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa)) + { + if (ntohl (lsa->header->id) < id) + continue; + if (ntohl (lsa->header->id) > id) + break; + id++; + } + + return ((u_int32_t) htonl (id)); +} + +/* Decide new LS sequence number to originate. + note return value is network byte order */ +u_int32_t +ospf6_new_ls_seqnum (u_int16_t type, u_int32_t id, u_int32_t adv_router, + struct ospf6_lsdb *lsdb) +{ + struct ospf6_lsa *lsa; + signed long seqnum = 0; + + /* if current database copy not found, return InitialSequenceNumber */ + lsa = ospf6_lsdb_lookup (type, id, adv_router, lsdb); + if (lsa == NULL) + seqnum = INITIAL_SEQUENCE_NUMBER; + else + seqnum = (signed long) ntohl (lsa->header->seqnum) + 1; + + return ((u_int32_t) htonl (seqnum)); +} + + diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h new file mode 100644 index 0000000..6330b91 --- /dev/null +++ b/ospf6d/ospf6_lsdb.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_LSDB_H +#define OSPF6_LSDB_H + +#include "prefix.h" +#include "table.h" + +struct ospf6_lsdb +{ + void *data; /* data structure that holds this lsdb */ + struct route_table *table; + u_int32_t count; + void (*hook_add) (struct ospf6_lsa *); + void (*hook_remove) (struct ospf6_lsa *); +}; + +#define OSPF6_LSDB_MAXAGE_REMOVER(lsdb) \ + do { \ + struct ospf6_lsa *lsa; \ + for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) \ + { \ + if (! OSPF6_LSA_IS_MAXAGE (lsa)) \ + continue; \ + if (lsa->retrans_count != 0) \ + continue; \ + if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) \ + zlog_info ("Remove MaxAge %s", lsa->name); \ + ospf6_lsdb_remove (lsa, lsdb); \ + } \ + } while (0) + +/* Function Prototypes */ +struct ospf6_lsdb *ospf6_lsdb_create (void *data); +void ospf6_lsdb_delete (struct ospf6_lsdb *lsdb); + +struct ospf6_lsa * +ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router, + struct ospf6_lsdb *lsdb); +struct ospf6_lsa * +ospf6_lsdb_lookup_next (u_int16_t type, u_int32_t id, + u_int32_t adv_router, struct ospf6_lsdb *lsdb); + +void ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb); +void ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb); + +struct ospf6_lsa *ospf6_lsdb_head (struct ospf6_lsdb *lsdb); +struct ospf6_lsa *ospf6_lsdb_next (struct ospf6_lsa *lsa); + +struct ospf6_lsa *ospf6_lsdb_type_router_head (u_int16_t type, + u_int32_t adv_router, + struct ospf6_lsdb *lsdb); +struct ospf6_lsa *ospf6_lsdb_type_router_next (u_int16_t type, + u_int32_t adv_router, + struct ospf6_lsa *lsa); + +struct ospf6_lsa *ospf6_lsdb_type_head (u_int16_t type, + struct ospf6_lsdb *lsdb); +struct ospf6_lsa *ospf6_lsdb_type_next (u_int16_t type, + struct ospf6_lsa *lsa); + +void ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb); + +#define OSPF6_LSDB_SHOW_LEVEL_NORMAL 0 +#define OSPF6_LSDB_SHOW_LEVEL_DETAIL 1 +#define OSPF6_LSDB_SHOW_LEVEL_INTERNAL 2 +#define OSPF6_LSDB_SHOW_LEVEL_DUMP 3 + +void ospf6_lsdb_show + (struct vty *vty, int level, + u_int16_t *type, u_int32_t *id, u_int32_t *adv_router, + struct ospf6_lsdb *lsdb); + +u_int32_t ospf6_new_ls_id + (u_int16_t type, u_int32_t adv_router, struct ospf6_lsdb *lsdb); +u_int32_t ospf6_new_ls_seqnum + (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb); + +#endif /* OSPF6_LSDB_H */ + + diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c new file mode 100644 index 0000000..7225d99 --- /dev/null +++ b/ospf6d/ospf6_main.c @@ -0,0 +1,291 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "getopt.h" +#include "thread.h" +#include "log.h" +#include "version.h" +#include "command.h" +#include "vty.h" +#include "memory.h" +#include "if.h" +#include "filter.h" +#include "prefix.h" +#include "plist.h" + +#include "ospf6d.h" + +/* Default configuration file name for ospf6d. */ +#define OSPF6_DEFAULT_CONFIG "ospf6d.conf" + +/* Default port values. */ +#define OSPF6_VTY_PORT 2606 +#define OSPF6_VTYSH_PATH "/tmp/.ospf6d" + +/* ospf6d options, we use GNU getopt library. */ +struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "version", no_argument, NULL, 'v'}, + { "help", no_argument, NULL, 'h'}, + { 0 } +}; + +/* Configuration file and directory. */ +char config_current[] = OSPF6_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR OSPF6_DEFAULT_CONFIG; + +/* ospf6d program name. */ +char *progname; + +/* is daemon? */ +int daemon_mode = 0; + +/* Master of threads. */ +struct thread_master *master; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_OSPF6D_PID; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\n\ +Daemon which manages OSPF version 3.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to zebra@zebra.org\n", progname); + } + + exit (status); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog_info ("SIGHUP received"); +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + zlog_info ("SIGINT received"); + exit (0); +} + +/* SIGTERM handler. */ +void +sigterm (int sig) +{ + zlog_info ("SIGTERM received"); + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_info ("SIGUSR1 received"); + zlog_rotate (NULL); +} + +/* Signale wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigterm); + signal_set (SIGPIPE, SIG_IGN); +#ifdef SIGTSTP + signal_set (SIGTSTP, SIG_IGN); +#endif +#ifdef SIGTTIN + signal_set (SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTTOU + signal_set (SIGTTOU, SIG_IGN); +#endif + signal_set (SIGUSR1, sigusr1); +} + +/* Main routine of ospf6d. Treatment of argument and starting ospf finite + state machine is handled here. */ +int +main (int argc, char *argv[], char *envp[]) +{ + char *p; + int opt; + char *vty_addr = NULL; + int vty_port = 0; + char *config_file = NULL; + struct thread thread; + int flag; + + /* Set umask before anything for security */ + umask (0027); + + /* Preserve name of myself. */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + /* Command line argument treatment. */ + while (1) + { + opt = getopt_long (argc, argv, "df:hp:A:P:v", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'd': + daemon_mode = 1; + break; + case 'f': + config_file = optarg; + break; + case 'A': + vty_addr = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'v': + print_version (progname); + exit (0); + break; + case 'h': + usage (progname, 0); + break; + default: + usage (progname, 1); + break; + } + } + + /* thread master */ + master = thread_master_create (); + + /* Initializations. */ + if (! daemon_mode) + flag = ZLOG_STDOUT; + else + flag = 0; + + zlog_default = openzlog (progname, flag, ZLOG_OSPF6, + LOG_CONS|LOG_NDELAY|LOG_PERROR|LOG_PID, + LOG_DAEMON); + + /* initialize zebra libraries */ + signal_init (); + cmd_init (1); + vty_init (); + memory_init (); + if_init (); + access_list_init (); + prefix_list_init (); + + /* initialize ospf6 */ + ospf6_init (); + + /* sort command vector */ + sort_node (); + + /* parse config file */ + vty_read_config (config_file, config_current, config_default); + + if (daemon_mode) + daemon (0, 0); + + /* pid file create */ +#if 0 + pid_output_lock (pid_file); +#else + pid_output (pid_file); +#endif + + /* Make ospf6 vty socket. */ + vty_serv_sock (vty_addr, + vty_port ? vty_port : OSPF6_VTY_PORT, OSPF6_VTYSH_PATH); + + /* Print start message */ + zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) starts", + ZEBRA_VERSION, OSPF6_DAEMON_VERSION); + + /* Start finite state machine, here we go! */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Log in case thread failed */ + zlog_warn ("Thread failed"); + + /* Not reached. */ + exit (0); +} + + diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c new file mode 100644 index 0000000..bd189f9 --- /dev/null +++ b/ospf6d/ospf6_message.c @@ -0,0 +1,2127 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "log.h" +#include "vty.h" +#include "command.h" +#include "thread.h" +#include "linklist.h" + +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_network.h" +#include "ospf6_message.h" + +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_neighbor.h" +#include "ospf6_interface.h" + +#include "ospf6_flood.h" +#include "ospf6d.h" + +unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0}; +char *ospf6_message_type_str[] = + { "Unknown", "Hello", "DbDesc", "LSReq", "LSUpdate", "LSAck" }; + +/* print functions */ + +static void +ospf6_header_print (struct ospf6_header *oh) +{ + char router_id[16], area_id[16]; + inet_ntop (AF_INET, &oh->router_id, router_id, sizeof (router_id)); + inet_ntop (AF_INET, &oh->area_id, area_id, sizeof (area_id)); + + zlog_info (" OSPFv%d Type:%d Len:%hu Router-ID:%s", + oh->version, oh->type, ntohs (oh->length), router_id); + zlog_info (" Area-ID:%s Cksum:%hx Instance-ID:%d", + area_id, ntohs (oh->checksum), oh->instance_id); +} + +void +ospf6_hello_print (struct ospf6_header *oh) +{ + struct ospf6_hello *hello; + char options[16]; + char drouter[16], bdrouter[16], neighbor[16]; + char *p; + + ospf6_header_print (oh); + assert (oh->type == OSPF6_MESSAGE_TYPE_HELLO); + + hello = (struct ospf6_hello *) + ((caddr_t) oh + sizeof (struct ospf6_header)); + + inet_ntop (AF_INET, &hello->drouter, drouter, sizeof (drouter)); + inet_ntop (AF_INET, &hello->bdrouter, bdrouter, sizeof (bdrouter)); + ospf6_options_printbuf (hello->options, options, sizeof (options)); + + zlog_info (" I/F-Id:%ld Priority:%d Option:%s", + (u_long) ntohl (hello->interface_id), hello->priority, options); + zlog_info (" HelloInterval:%hu DeadInterval:%hu", + ntohs (hello->hello_interval), ntohs (hello->dead_interval)); + zlog_info (" DR:%s BDR:%s", drouter, bdrouter); + + for (p = (char *) ((caddr_t) hello + sizeof (struct ospf6_hello)); + p + sizeof (u_int32_t) <= OSPF6_MESSAGE_END (oh); + p += sizeof (u_int32_t)) + { + inet_ntop (AF_INET, (void *) p, neighbor, sizeof (neighbor)); + zlog_info (" Neighbor: %s", neighbor); + } + + if (p != OSPF6_MESSAGE_END (oh)) + zlog_info ("Trailing garbage exists"); +} + +void +ospf6_dbdesc_print (struct ospf6_header *oh) +{ + struct ospf6_dbdesc *dbdesc; + char options[16]; + char *p; + + ospf6_header_print (oh); + assert (oh->type == OSPF6_MESSAGE_TYPE_DBDESC); + + dbdesc = (struct ospf6_dbdesc *) + ((caddr_t) oh + sizeof (struct ospf6_header)); + + ospf6_options_printbuf (dbdesc->options, options, sizeof (options)); + + zlog_info (" MBZ: %#x Option: %s IfMTU: %hu", + dbdesc->reserved1, options, ntohs (dbdesc->ifmtu)); + zlog_info (" MBZ: %#x Bits: %s%s%s SeqNum: %#lx", + dbdesc->reserved2, + (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT) ? "I" : "-"), + (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MBIT) ? "M" : "-"), + (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT) ? "m" : "s"), + (u_long) ntohl (dbdesc->seqnum)); + + for (p = (char *) ((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc)); + p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsa_header)) + ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p); + + if (p != OSPF6_MESSAGE_END (oh)) + zlog_info ("Trailing garbage exists"); +} + +void +ospf6_lsreq_print (struct ospf6_header *oh) +{ + char id[16], adv_router[16]; + char *p; + + ospf6_header_print (oh); + assert (oh->type == OSPF6_MESSAGE_TYPE_LSREQ); + + for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header)); + p + sizeof (struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsreq_entry)) + { + struct ospf6_lsreq_entry *e = (struct ospf6_lsreq_entry *) p; + inet_ntop (AF_INET, &e->adv_router, adv_router, sizeof (adv_router)); + inet_ntop (AF_INET, &e->id, id, sizeof (id)); + zlog_info (" [%s Id:%s Adv:%s]", + ospf6_lstype_name (e->type), id, adv_router); + } + + if (p != OSPF6_MESSAGE_END (oh)) + zlog_info ("Trailing garbage exists"); +} + +void +ospf6_lsupdate_print (struct ospf6_header *oh) +{ + struct ospf6_lsupdate *lsupdate; + u_long num; + char *p; + + ospf6_header_print (oh); + assert (oh->type == OSPF6_MESSAGE_TYPE_LSUPDATE); + + lsupdate = (struct ospf6_lsupdate *) + ((caddr_t) oh + sizeof (struct ospf6_header)); + + num = ntohl (lsupdate->lsa_number); + zlog_info (" Number of LSA: %ld", num); + + for (p = (char *) ((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); + p < OSPF6_MESSAGE_END (oh) && + p + OSPF6_LSA_SIZE (p) <= OSPF6_MESSAGE_END (oh); + p += OSPF6_LSA_SIZE (p)) + { + ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p); + if (OSPF6_LSA_SIZE (p) < sizeof (struct ospf6_lsa_header)) + { + zlog_info (" Malformed LSA length, quit printing"); + break; + } + } + + if (p != OSPF6_MESSAGE_END (oh)) + { + char buf[32]; + + int num = 0; + memset (buf, 0, sizeof (buf)); + + zlog_info (" Trailing garbage exists"); + while (p < OSPF6_MESSAGE_END (oh)) + { + snprintf (buf, sizeof (buf), "%s %2x", buf, *p++); + num++; + if (num == 8) + { + zlog_info (" %s", buf); + memset (buf, 0, sizeof (buf)); + num = 0; + } + } + if (num) + zlog_info (" %s", buf); + } +} + +void +ospf6_lsack_print (struct ospf6_header *oh) +{ + char *p; + + ospf6_header_print (oh); + assert (oh->type == OSPF6_MESSAGE_TYPE_LSACK); + + for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header)); + p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsa_header)) + ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p); + + if (p != OSPF6_MESSAGE_END (oh)) + zlog_info ("Trailing garbage exists"); +} + +/* Receive function */ +#define MSG_OK 0 +#define MSG_NG 1 +static int +ospf6_header_examin (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) +{ + u_char type; + type = OSPF6_MESSAGE_TYPE_CANONICAL (oh->type); + + /* version check */ + if (oh->version != OSPFV3_VERSION) + { + if (IS_OSPF6_DEBUG_MESSAGE (type, RECV)) + zlog_info ("Message with unknown version"); + return MSG_NG; + } + + /* Area-ID check */ + if (oh->area_id != oi->area->area_id) + { + if (oh->area_id == BACKBONE_AREA_ID) + { + if (IS_OSPF6_DEBUG_MESSAGE (type, RECV)) + zlog_info ("Message may be via Virtual Link: not supported"); + return MSG_NG; + } + + if (IS_OSPF6_DEBUG_MESSAGE (type, RECV)) + zlog_info ("Area-ID mismatch"); + return MSG_NG; + } + + /* Instance-ID check */ + if (oh->instance_id != oi->instance_id) + { + if (IS_OSPF6_DEBUG_MESSAGE (type, RECV)) + zlog_info ("Instance-ID mismatch"); + return MSG_NG; + } + + /* Router-ID check */ + if (oh->router_id == oi->area->ospf6->router_id) + zlog_warn ("Detect duplicate Router-ID"); + + return MSG_OK; +} + +void +ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) +{ + struct ospf6_hello *hello; + struct ospf6_neighbor *on; + char *p; + int twoway = 0; + int neighborchange = 0; + int backupseen = 0; + + if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) + return; + + hello = (struct ospf6_hello *) + ((caddr_t) oh + sizeof (struct ospf6_header)); + + /* HelloInterval check */ + if (ntohs (hello->hello_interval) != oi->hello_interval) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("HelloInterval mismatch"); + return; + } + + /* RouterDeadInterval check */ + if (ntohs (hello->dead_interval) != oi->dead_interval) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("RouterDeadInterval mismatch"); + return; + } + + /* E-bit check */ + if (OSPF6_OPT_ISSET (hello->options, OSPF6_OPT_E) != + OSPF6_OPT_ISSET (oi->area->options, OSPF6_OPT_E)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("E-bit mismatch"); + return; + } + + /* Find neighbor, create if not exist */ + on = ospf6_neighbor_lookup (oh->router_id, oi); + if (on == NULL) + { + on = ospf6_neighbor_create (oh->router_id, oi); + on->prev_drouter = on->drouter = hello->drouter; + on->prev_bdrouter = on->bdrouter = hello->bdrouter; + on->priority = hello->priority; + } + + /* always override neighbor's source address and ifindex */ + on->ifindex = ntohl (hello->interface_id); + memcpy (&on->linklocal_addr, src, sizeof (struct in6_addr)); + + /* TwoWay check */ + for (p = (char *) ((caddr_t) hello + sizeof (struct ospf6_hello)); + p + sizeof (u_int32_t) <= OSPF6_MESSAGE_END (oh); + p += sizeof (u_int32_t)) + { + u_int32_t *router_id = (u_int32_t *) p; + + if (*router_id == oi->area->ospf6->router_id) + twoway++; + } + + if (p != OSPF6_MESSAGE_END (oh)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Trailing garbage ignored"); + } + + /* RouterPriority check */ + if (on->priority != hello->priority) + { + on->priority = hello->priority; + neighborchange++; + } + + /* DR check */ + if (on->drouter != hello->drouter) + { + on->prev_drouter = on->drouter; + on->drouter = hello->drouter; + if (on->prev_drouter == on->router_id || on->drouter == on->router_id) + neighborchange++; + } + + /* BDR check */ + if (on->bdrouter != hello->bdrouter) + { + on->prev_bdrouter = on->bdrouter; + on->bdrouter = hello->bdrouter; + if (on->prev_bdrouter == on->router_id || on->bdrouter == on->router_id) + neighborchange++; + } + + /* BackupSeen check */ + if (oi->state == OSPF6_INTERFACE_WAITING) + { + if (hello->bdrouter == on->router_id) + backupseen++; + else if (hello->drouter == on->router_id && hello->bdrouter == htonl (0)) + backupseen++; + } + + /* Execute neighbor events */ + thread_execute (master, hello_received, on, 0); + if (twoway) + thread_execute (master, twoway_received, on, 0); + else + thread_execute (master, oneway_received, on, 0); + + /* Schedule interface events */ + if (backupseen) + thread_add_event (master, backup_seen, oi, 0); + if (neighborchange) + thread_add_event (master, neighbor_change, oi, 0); +} + +static void +ospf6_dbdesc_recv_master (struct ospf6_header *oh, + struct ospf6_neighbor *on) +{ + struct ospf6_dbdesc *dbdesc; + char *p; + + dbdesc = (struct ospf6_dbdesc *) + ((caddr_t) oh + sizeof (struct ospf6_header)); + + if (on->state < OSPF6_NEIGHBOR_INIT) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state less than Init, ignore"); + return; + } + + switch (on->state) + { + case OSPF6_NEIGHBOR_TWOWAY: + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state is 2-Way, ignore"); + return; + + case OSPF6_NEIGHBOR_INIT: + thread_execute (master, twoway_received, on, 0); + if (on->state != OSPF6_NEIGHBOR_EXSTART) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state is not ExStart, ignore"); + return; + } + /* else fall through to ExStart */ + + case OSPF6_NEIGHBOR_EXSTART: + /* if neighbor obeys us as our slave, schedule negotiation_done + and process LSA Headers. Otherwise, ignore this message */ + if (! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT) && + ! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT) && + ntohl (dbdesc->seqnum) == on->dbdesc_seqnum) + { + /* execute NegotiationDone */ + thread_execute (master, negotiation_done, on, 0); + + /* Record neighbor options */ + memcpy (on->options, dbdesc->options, sizeof (on->options)); + } + else + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Negotiation failed"); + return; + } + /* fall through to exchange */ + + case OSPF6_NEIGHBOR_EXCHANGE: + if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc))) + { + /* Duplicated DatabaseDescription is dropped by master */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Duplicated dbdesc discarded by Master, ignore"); + return; + } + + if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Master/Slave bit mismatch"); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Initialize bit mismatch"); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (memcmp (on->options, dbdesc->options, sizeof (on->options))) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Option field mismatch"); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (ntohl (dbdesc->seqnum) != on->dbdesc_seqnum) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Sequence number mismatch (%#lx expected)", + (u_long) on->dbdesc_seqnum); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + break; + + case OSPF6_NEIGHBOR_LOADING: + case OSPF6_NEIGHBOR_FULL: + if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc))) + { + /* Duplicated DatabaseDescription is dropped by master */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Duplicated dbdesc discarded by Master, ignore"); + return; + } + + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Not duplicate dbdesc in state %s", + ospf6_neighbor_state_str[on->state]); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + + default: + assert (0); + break; + } + + /* Process LSA headers */ + for (p = (char *) ((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc)); + p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsa_header)) + { + struct ospf6_lsa *his, *mine; + struct ospf6_lsdb *lsdb = NULL; + + his = ospf6_lsa_create_headeronly ((struct ospf6_lsa_header *) p); + + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("%s", his->name); + + switch (OSPF6_LSA_SCOPE (his->header->type)) + { + case OSPF6_SCOPE_LINKLOCAL: + lsdb = on->ospf6_if->lsdb; + break; + case OSPF6_SCOPE_AREA: + lsdb = on->ospf6_if->area->lsdb; + break; + case OSPF6_SCOPE_AS: + lsdb = on->ospf6_if->area->ospf6->lsdb; + break; + case OSPF6_SCOPE_RESERVED: + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Ignoring LSA of reserved scope"); + ospf6_lsa_delete (his); + continue; + break; + } + + if (ntohs (his->header->type) == OSPF6_LSTYPE_AS_EXTERNAL && + IS_AREA_STUB (on->ospf6_if->area)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("SeqNumMismatch (E-bit mismatch), discard"); + ospf6_lsa_delete (his); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + mine = ospf6_lsdb_lookup (his->header->type, his->header->id, + his->header->adv_router, lsdb); + if (mine == NULL) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Add request (No database copy)"); + ospf6_lsdb_add (his, on->request_list); + } + else if (ospf6_lsa_compare (his, mine) < 0) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Add request (Received MoreRecent)"); + ospf6_lsdb_add (his, on->request_list); + } + else + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Discard (Existing MoreRecent)"); + ospf6_lsa_delete (his); + } + } + + if (p != OSPF6_MESSAGE_END (oh)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Trailing garbage ignored"); + } + + /* Increment sequence number */ + on->dbdesc_seqnum ++; + + /* schedule send lsreq */ + if (on->thread_send_lsreq == NULL) + on->thread_send_lsreq = + thread_add_event (master, ospf6_lsreq_send, on, 0); + + THREAD_OFF (on->thread_send_dbdesc); + + /* More bit check */ + if (! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MBIT) && + ! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT)) + thread_add_event (master, exchange_done, on, 0); + else + on->thread_send_dbdesc = + thread_add_event (master, ospf6_dbdesc_send_newone, on, 0); + + /* save last received dbdesc */ + memcpy (&on->dbdesc_last, dbdesc, sizeof (struct ospf6_dbdesc)); +} + +static void +ospf6_dbdesc_recv_slave (struct ospf6_header *oh, + struct ospf6_neighbor *on) +{ + struct ospf6_dbdesc *dbdesc; + char *p; + + dbdesc = (struct ospf6_dbdesc *) + ((caddr_t) oh + sizeof (struct ospf6_header)); + + if (on->state < OSPF6_NEIGHBOR_INIT) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state less than Init, ignore"); + return; + } + + switch (on->state) + { + case OSPF6_NEIGHBOR_TWOWAY: + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state is 2-Way, ignore"); + return; + + case OSPF6_NEIGHBOR_INIT: + thread_execute (master, twoway_received, on, 0); + if (on->state != OSPF6_NEIGHBOR_EXSTART) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state is not ExStart, ignore"); + return; + } + /* else fall through to ExStart */ + + case OSPF6_NEIGHBOR_EXSTART: + /* If the neighbor is Master, act as Slave. Schedule negotiation_done + and process LSA Headers. Otherwise, ignore this message */ + if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT) && + CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MBIT) && + CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT) && + ntohs (oh->length) == sizeof (struct ospf6_header) + + sizeof (struct ospf6_dbdesc)) + { + /* set the master/slave bit to slave */ + UNSET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); + + /* set the DD sequence number to one specified by master */ + on->dbdesc_seqnum = ntohl (dbdesc->seqnum); + + /* schedule NegotiationDone */ + thread_execute (master, negotiation_done, on, 0); + + /* Record neighbor options */ + memcpy (on->options, dbdesc->options, sizeof (on->options)); + } + else + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Negotiation failed"); + return; + } + break; + + case OSPF6_NEIGHBOR_EXCHANGE: + if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc))) + { + /* Duplicated DatabaseDescription causes slave to retransmit */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Duplicated dbdesc causes retransmit"); + THREAD_OFF (on->thread_send_dbdesc); + on->thread_send_dbdesc = + thread_add_event (master, ospf6_dbdesc_send, on, 0); + return; + } + + if (! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Master/Slave bit mismatch"); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Initialize bit mismatch"); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (memcmp (on->options, dbdesc->options, sizeof (on->options))) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Option field mismatch"); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (ntohl (dbdesc->seqnum) != on->dbdesc_seqnum + 1) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Sequence number mismatch (%#lx expected)", + (u_long) on->dbdesc_seqnum + 1); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + break; + + case OSPF6_NEIGHBOR_LOADING: + case OSPF6_NEIGHBOR_FULL: + if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc))) + { + /* Duplicated DatabaseDescription causes slave to retransmit */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Duplicated dbdesc causes retransmit"); + THREAD_OFF (on->thread_send_dbdesc); + on->thread_send_dbdesc = + thread_add_event (master, ospf6_dbdesc_send, on, 0); + return; + } + + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Not duplicate dbdesc in state %s", + ospf6_neighbor_state_str[on->state]); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + + default: + assert (0); + break; + } + + /* Process LSA headers */ + for (p = (char *) ((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc)); + p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsa_header)) + { + struct ospf6_lsa *his, *mine; + struct ospf6_lsdb *lsdb = NULL; + + his = ospf6_lsa_create_headeronly ((struct ospf6_lsa_header *) p); + + switch (OSPF6_LSA_SCOPE (his->header->type)) + { + case OSPF6_SCOPE_LINKLOCAL: + lsdb = on->ospf6_if->lsdb; + break; + case OSPF6_SCOPE_AREA: + lsdb = on->ospf6_if->area->lsdb; + break; + case OSPF6_SCOPE_AS: + lsdb = on->ospf6_if->area->ospf6->lsdb; + break; + case OSPF6_SCOPE_RESERVED: + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Ignoring LSA of reserved scope"); + ospf6_lsa_delete (his); + continue; + break; + } + + if (OSPF6_LSA_SCOPE (his->header->type) == OSPF6_SCOPE_AS && + IS_AREA_STUB (on->ospf6_if->area)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("E-bit mismatch with LSA Headers"); + ospf6_lsa_delete (his); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + mine = ospf6_lsdb_lookup (his->header->type, his->header->id, + his->header->adv_router, lsdb); + if (mine == NULL || ospf6_lsa_compare (his, mine) < 0) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Add request-list: %s", his->name); + ospf6_lsdb_add (his, on->request_list); + } + else + ospf6_lsa_delete (his); + } + + if (p != OSPF6_MESSAGE_END (oh)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Trailing garbage ignored"); + } + + /* Set sequence number to Master's */ + on->dbdesc_seqnum = ntohl (dbdesc->seqnum); + + /* schedule send lsreq */ + if (on->thread_send_lsreq == NULL) + on->thread_send_lsreq = + thread_add_event (master, ospf6_lsreq_send, on, 0); + + THREAD_OFF (on->thread_send_dbdesc); + on->thread_send_dbdesc = + thread_add_event (master, ospf6_dbdesc_send_newone, on, 0); + + /* save last received dbdesc */ + memcpy (&on->dbdesc_last, dbdesc, sizeof (struct ospf6_dbdesc)); +} + +void +ospf6_dbdesc_recv (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) +{ + struct ospf6_neighbor *on; + struct ospf6_dbdesc *dbdesc; + + if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) + return; + + on = ospf6_neighbor_lookup (oh->router_id, oi); + if (on == NULL) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor not found, ignore"); + return; + } + + dbdesc = (struct ospf6_dbdesc *) + ((caddr_t) oh + sizeof (struct ospf6_header)); + + /* Interface MTU check */ + if (ntohs (dbdesc->ifmtu) != oi->ifmtu) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("I/F MTU mismatch"); + return; + } + + if (dbdesc->reserved1 || dbdesc->reserved2) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Non-0 reserved field in %s's DbDesc, correct", + on->name); + dbdesc->reserved1 = 0; + dbdesc->reserved2 = 0; + } + + if (ntohl (oh->router_id) < ntohl (ospf6->router_id)) + ospf6_dbdesc_recv_master (oh, on); + else if (ntohl (ospf6->router_id) < ntohl (oh->router_id)) + ospf6_dbdesc_recv_slave (oh, on); + else + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Can't decide which is master, ignore"); + } +} + +void +ospf6_lsreq_recv (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) +{ + struct ospf6_neighbor *on; + char *p; + struct ospf6_lsreq_entry *e; + struct ospf6_lsdb *lsdb = NULL; + struct ospf6_lsa *lsa; + + if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) + return; + + on = ospf6_neighbor_lookup (oh->router_id, oi); + if (on == NULL) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor not found, ignore"); + return; + } + + if (on->state != OSPF6_NEIGHBOR_EXCHANGE && + on->state != OSPF6_NEIGHBOR_LOADING && + on->state != OSPF6_NEIGHBOR_FULL) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state less than Exchange, ignore"); + return; + } + + /* Process each request */ + for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header)); + p + sizeof (struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsreq_entry)) + { + e = (struct ospf6_lsreq_entry *) p; + + switch (OSPF6_LSA_SCOPE (e->type)) + { + case OSPF6_SCOPE_LINKLOCAL: + lsdb = on->ospf6_if->lsdb; + break; + case OSPF6_SCOPE_AREA: + lsdb = on->ospf6_if->area->lsdb; + break; + case OSPF6_SCOPE_AS: + lsdb = on->ospf6_if->area->ospf6->lsdb; + break; + default: + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Ignoring LSA of reserved scope"); + continue; + break; + } + + /* Find database copy */ + lsa = ospf6_lsdb_lookup (e->type, e->id, e->adv_router, lsdb); + if (lsa == NULL) + { + char id[16], adv_router[16]; + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + { + inet_ntop (AF_INET, &e->id, id, sizeof (id)); + inet_ntop (AF_INET, &e->adv_router, adv_router, + sizeof (adv_router)); + zlog_info ("Can't find requested [%s Id:%s Adv:%s]", + ospf6_lstype_name (e->type), id, adv_router); + } + thread_add_event (master, bad_lsreq, on, 0); + return; + } + + ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->lsupdate_list); + } + + if (p != OSPF6_MESSAGE_END (oh)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Trailing garbage ignored"); + } + + /* schedule send lsupdate */ + THREAD_OFF (on->thread_send_lsupdate); + on->thread_send_lsupdate = + thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); +} + +void +ospf6_lsupdate_recv (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) +{ + struct ospf6_neighbor *on; + struct ospf6_lsupdate *lsupdate; + unsigned long num; + char *p; + + if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) + return; + + on = ospf6_neighbor_lookup (oh->router_id, oi); + if (on == NULL) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor not found, ignore"); + return; + } + + if (on->state != OSPF6_NEIGHBOR_EXCHANGE && + on->state != OSPF6_NEIGHBOR_LOADING && + on->state != OSPF6_NEIGHBOR_FULL) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state less than Exchange, ignore"); + return; + } + + lsupdate = (struct ospf6_lsupdate *) + ((caddr_t) oh + sizeof (struct ospf6_header)); + + num = ntohl (lsupdate->lsa_number); + + /* Process LSAs */ + for (p = (char *) ((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); + p < OSPF6_MESSAGE_END (oh) && + p + OSPF6_LSA_SIZE (p) <= OSPF6_MESSAGE_END (oh); + p += OSPF6_LSA_SIZE (p)) + { + if (num == 0) + break; + if (OSPF6_LSA_SIZE (p) < sizeof (struct ospf6_lsa_header)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Malformed LSA length, quit processing"); + break; + } + + ospf6_receive_lsa (on, (struct ospf6_lsa_header *) p); + num--; + } + + if (num != 0) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Malformed LSA number or LSA length"); + } + if (p != OSPF6_MESSAGE_END (oh)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Trailing garbage ignored"); + } + + /* RFC2328 Section 10.9: When the neighbor responds to these requests + with the proper Link State Update packet(s), the Link state request + list is truncated and a new Link State Request packet is sent. */ + /* send new Link State Request packet if this LS Update packet + can be recognized as a response to our previous LS Request */ + if (! IN6_IS_ADDR_MULTICAST (dst) && + (on->state == OSPF6_NEIGHBOR_EXCHANGE || + on->state == OSPF6_NEIGHBOR_LOADING)) + { + THREAD_OFF (on->thread_send_lsreq); + on->thread_send_lsreq = + thread_add_event (master, ospf6_lsreq_send, on, 0); + } +} + +void +ospf6_lsack_recv (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) +{ + struct ospf6_neighbor *on; + char *p; + struct ospf6_lsa *his, *mine; + struct ospf6_lsdb *lsdb = NULL; + + assert (oh->type == OSPF6_MESSAGE_TYPE_LSACK); + if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) + return; + + on = ospf6_neighbor_lookup (oh->router_id, oi); + if (on == NULL) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor not found, ignore"); + return; + } + + if (on->state != OSPF6_NEIGHBOR_EXCHANGE && + on->state != OSPF6_NEIGHBOR_LOADING && + on->state != OSPF6_NEIGHBOR_FULL) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state less than Exchange, ignore"); + return; + } + + for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header)); + p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsa_header)) + { + his = ospf6_lsa_create_headeronly ((struct ospf6_lsa_header *) p); + + switch (OSPF6_LSA_SCOPE (his->header->type)) + { + case OSPF6_SCOPE_LINKLOCAL: + lsdb = on->ospf6_if->lsdb; + break; + case OSPF6_SCOPE_AREA: + lsdb = on->ospf6_if->area->lsdb; + break; + case OSPF6_SCOPE_AS: + lsdb = on->ospf6_if->area->ospf6->lsdb; + break; + case OSPF6_SCOPE_RESERVED: + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Ignoring LSA of reserved scope"); + ospf6_lsa_delete (his); + continue; + break; + } + + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("%s acknowledged by %s", his->name, on->name); + + /* Find database copy */ + mine = ospf6_lsdb_lookup (his->header->type, his->header->id, + his->header->adv_router, lsdb); + if (mine == NULL) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("No database copy"); + ospf6_lsa_delete (his); + continue; + } + + /* Check if the LSA is on his retrans-list */ + mine = ospf6_lsdb_lookup (his->header->type, his->header->id, + his->header->adv_router, on->retrans_list); + if (mine == NULL) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Not on %s's retrans-list", on->name); + ospf6_lsa_delete (his); + continue; + } + + if (ospf6_lsa_compare (his, mine) != 0) + { + /* Log this questionable acknowledgement, + and examine the next one. */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Questionable acknowledgement"); + ospf6_lsa_delete (his); + continue; + } + + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Acknowledged, remove from %s's retrans-list", + on->name); + + if (OSPF6_LSA_IS_MAXAGE (mine)) + ospf6_maxage_remove (on->ospf6_if->area->ospf6); + + ospf6_decrement_retrans_count (mine); + ospf6_lsdb_remove (mine, on->retrans_list); + ospf6_lsa_delete (his); + } + + if (p != OSPF6_MESSAGE_END (oh)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Trailing garbage ignored"); + } +} + +char *recvbuf = NULL; +char *sendbuf = NULL; +int iobuflen = 0; + +int +ospf6_iobuf_size (int size) +{ + char *recvnew, *sendnew; + + if (size <= iobuflen) + return iobuflen; + + recvnew = XMALLOC (MTYPE_OSPF6_MESSAGE, size); + sendnew = XMALLOC (MTYPE_OSPF6_MESSAGE, size); + if (recvnew == NULL || sendnew == NULL) + { + if (recvnew) + XFREE (MTYPE_OSPF6_MESSAGE, recvnew); + if (sendnew) + XFREE (MTYPE_OSPF6_MESSAGE, sendnew); + zlog_info ("Could not allocate I/O buffer of size %d.", size); + return iobuflen; + } + + if (recvbuf) + XFREE (MTYPE_OSPF6_MESSAGE, recvbuf); + if (sendbuf) + XFREE (MTYPE_OSPF6_MESSAGE, sendbuf); + recvbuf = recvnew; + sendbuf = sendnew; + iobuflen = size; + + return iobuflen; +} + +int +ospf6_receive (struct thread *thread) +{ + int sockfd, len; + char srcname[64], dstname[64]; + struct in6_addr src, dst; + unsigned int ifindex; + struct iovec iovector[2]; + struct ospf6_interface *oi; + struct ospf6_header *oh; + + /* add next read thread */ + sockfd = THREAD_FD (thread); + thread_add_read (master, ospf6_receive, NULL, sockfd); + + /* initialize */ + memset (recvbuf, 0, iobuflen); + iovector[0].iov_base = recvbuf; + iovector[0].iov_len = iobuflen; + iovector[1].iov_base = NULL; + iovector[1].iov_len = 0; + + /* receive message */ + len = ospf6_recvmsg (&src, &dst, &ifindex, iovector); + if (len > iobuflen) + { + zlog_err ("Excess message read"); + return 0; + } + else if (len < sizeof (struct ospf6_header)) + { + zlog_err ("Deficient message read"); + return 0; + } + + oi = ospf6_interface_lookup_by_ifindex (ifindex); + if (oi == NULL || oi->area == NULL) + { + zlog_info ("Message received on disabled interface"); + return 0; + } + + oh = (struct ospf6_header *) recvbuf; + + /* Log */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + { + inet_ntop (AF_INET6, &src, srcname, sizeof (srcname)); + inet_ntop (AF_INET6, &dst, dstname, sizeof (dstname)); + zlog_info ("%s received on %s", + OSPF6_MESSAGE_TYPE_NAME (oh->type), oi->interface->name); + zlog_info (" src: %s", srcname); + zlog_info (" dst: %s", dstname); + if (len != ntohs (oh->length)) + zlog_info ("Message length does not match actually received: %d", len); + + switch (oh->type) + { + case OSPF6_MESSAGE_TYPE_HELLO: + ospf6_hello_print (oh); + break; + case OSPF6_MESSAGE_TYPE_DBDESC: + ospf6_dbdesc_print (oh); + break; + case OSPF6_MESSAGE_TYPE_LSREQ: + ospf6_lsreq_print (oh); + break; + case OSPF6_MESSAGE_TYPE_LSUPDATE: + ospf6_lsupdate_print (oh); + break; + case OSPF6_MESSAGE_TYPE_LSACK: + ospf6_lsack_print (oh); + break; + default: + zlog_info ("Unknown message"); + break; + } + } + + if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Ignore message on passive interface %s", + oi->interface->name); + return 0; + } + + switch (oh->type) + { + case OSPF6_MESSAGE_TYPE_HELLO: + ospf6_hello_recv (&src, &dst, oi, oh); + break; + + case OSPF6_MESSAGE_TYPE_DBDESC: + ospf6_dbdesc_recv (&src, &dst, oi, oh); + break; + + case OSPF6_MESSAGE_TYPE_LSREQ: + ospf6_lsreq_recv (&src, &dst, oi, oh); + break; + + case OSPF6_MESSAGE_TYPE_LSUPDATE: + ospf6_lsupdate_recv (&src, &dst, oi, oh); + break; + + case OSPF6_MESSAGE_TYPE_LSACK: + ospf6_lsack_recv (&src, &dst, oi, oh); + break; + + default: + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_info ("Unknown message"); + break; + } + + return 0; +} + +void +ospf6_send (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) +{ + int len; + char srcname[64], dstname[64]; + struct iovec iovector[2]; + + /* initialize */ + iovector[0].iov_base = (caddr_t) oh; + iovector[0].iov_len = ntohs (oh->length); + iovector[1].iov_base = NULL; + iovector[1].iov_len = 0; + + /* fill OSPF header */ + oh->version = OSPFV3_VERSION; + /* message type must be set before */ + /* message length must be set before */ + oh->router_id = oi->area->ospf6->router_id; + oh->area_id = oi->area->area_id; + /* checksum is calculated by kernel */ + oh->instance_id = oi->instance_id; + oh->reserved = 0; + + /* Log */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, SEND)) + { + inet_ntop (AF_INET6, dst, dstname, sizeof (dstname)); + if (src) + inet_ntop (AF_INET6, src, srcname, sizeof (srcname)); + else + memset (srcname, 0, sizeof (srcname)); + zlog_info ("%s send on %s", + OSPF6_MESSAGE_TYPE_NAME (oh->type), oi->interface->name); + zlog_info (" src: %s", srcname); + zlog_info (" dst: %s", dstname); + + switch (oh->type) + { + case OSPF6_MESSAGE_TYPE_HELLO: + ospf6_hello_print (oh); + break; + case OSPF6_MESSAGE_TYPE_DBDESC: + ospf6_dbdesc_print (oh); + break; + case OSPF6_MESSAGE_TYPE_LSREQ: + ospf6_lsreq_print (oh); + break; + case OSPF6_MESSAGE_TYPE_LSUPDATE: + ospf6_lsupdate_print (oh); + break; + case OSPF6_MESSAGE_TYPE_LSACK: + ospf6_lsack_print (oh); + break; + default: + zlog_info ("Unknown message"); + assert (0); + break; + } + } + + /* send message */ + len = ospf6_sendmsg (src, dst, &oi->interface->ifindex, iovector); + if (len != ntohs (oh->length)) + zlog_err ("Could not send entire message"); +} + +int +ospf6_hello_send (struct thread *thread) +{ + struct ospf6_interface *oi; + struct ospf6_header *oh; + struct ospf6_hello *hello; + char *p; + listnode node; + struct ospf6_neighbor *on; + + oi = (struct ospf6_interface *) THREAD_ARG (thread); + oi->thread_send_hello = (struct thread *) NULL; + + if (oi->state <= OSPF6_INTERFACE_DOWN) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_HELLO, SEND)) + zlog_info ("Unable to send Hello on down interface %s", + oi->interface->name); + return 0; + } + + /* set next thread */ + oi->thread_send_hello = thread_add_timer (master, ospf6_hello_send, + oi, oi->hello_interval); + + memset (sendbuf, 0, iobuflen); + oh = (struct ospf6_header *) sendbuf; + hello = (struct ospf6_hello *)((caddr_t) oh + sizeof (struct ospf6_header)); + + hello->interface_id = htonl (oi->interface->ifindex); + hello->priority = oi->priority; + hello->options[0] = oi->area->options[0]; + hello->options[1] = oi->area->options[1]; + hello->options[2] = oi->area->options[2]; + hello->hello_interval = htons (oi->hello_interval); + hello->dead_interval = htons (oi->dead_interval); + hello->drouter = oi->drouter; + hello->bdrouter = oi->bdrouter; + + p = (char *)((caddr_t) hello + sizeof (struct ospf6_hello)); + + for (node = listhead (oi->neighbor_list); node; nextnode (node)) + { + on = (struct ospf6_neighbor *) getdata (node); + + if (on->state < OSPF6_NEIGHBOR_INIT) + continue; + + if (p - sendbuf + sizeof (u_int32_t) > oi->ifmtu) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_HELLO, SEND)) + zlog_info ("sending Hello message: exceeds I/F MTU"); + break; + } + + memcpy (p, &on->router_id, sizeof (u_int32_t)); + p += sizeof (u_int32_t); + } + + oh->type = OSPF6_MESSAGE_TYPE_HELLO; + oh->length = htons (p - sendbuf); + + ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); + return 0; +} + +int +ospf6_dbdesc_send (struct thread *thread) +{ + struct ospf6_neighbor *on; + struct ospf6_header *oh; + struct ospf6_dbdesc *dbdesc; + char *p; + struct ospf6_lsa *lsa; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + on->thread_send_dbdesc = (struct thread *) NULL; + + if (on->state < OSPF6_NEIGHBOR_EXSTART) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_DBDESC, SEND)) + zlog_info ("Quit to send DbDesc to neighbor %s state %s", + on->name, ospf6_neighbor_state_str[on->state]); + return 0; + } + + /* set next thread if master */ + if (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT)) + on->thread_send_dbdesc = + thread_add_timer (master, ospf6_dbdesc_send, on, + on->ospf6_if->rxmt_interval); + + memset (sendbuf, 0, iobuflen); + oh = (struct ospf6_header *) sendbuf; + dbdesc = (struct ospf6_dbdesc *)((caddr_t) oh + + sizeof (struct ospf6_header)); + + /* if this is initial one, initialize sequence number for DbDesc */ + if (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT)) + { + struct timeval tv; + if (gettimeofday (&tv, (struct timezone *) NULL) < 0) + tv.tv_sec = 1; + on->dbdesc_seqnum = tv.tv_sec; + } + + dbdesc->options[0] = on->ospf6_if->area->options[0]; + dbdesc->options[1] = on->ospf6_if->area->options[1]; + dbdesc->options[2] = on->ospf6_if->area->options[2]; + dbdesc->ifmtu = htons (on->ospf6_if->ifmtu); + dbdesc->bits = on->dbdesc_bits; + dbdesc->seqnum = htonl (on->dbdesc_seqnum); + + /* if this is not initial one, set LSA headers in dbdesc */ + p = (char *)((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc)); + if (! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT)) + { + for (lsa = ospf6_lsdb_head (on->dbdesc_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); + + /* MTU check */ + if (p - sendbuf + sizeof (struct ospf6_lsa_header) > + on->ospf6_if->ifmtu) + { + ospf6_lsa_unlock (lsa); + break; + } + memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); + p += sizeof (struct ospf6_lsa_header); + } + } + + oh->type = OSPF6_MESSAGE_TYPE_DBDESC; + oh->length = htons (p - sendbuf); + + ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, + on->ospf6_if, oh); + return 0; +} + +int +ospf6_dbdesc_send_newone (struct thread *thread) +{ + struct ospf6_neighbor *on; + struct ospf6_lsa *lsa; + unsigned int size = 0; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + ospf6_lsdb_remove_all (on->dbdesc_list); + + /* move LSAs from summary_list to dbdesc_list (within neighbor structure) + so that ospf6_send_dbdesc () can send those LSAs */ + size = sizeof (struct ospf6_lsa_header) + sizeof (struct ospf6_dbdesc); + for (lsa = ospf6_lsdb_head (on->summary_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + if (size + sizeof (struct ospf6_lsa_header) > on->ospf6_if->ifmtu) + { + ospf6_lsa_unlock (lsa); + break; + } + + ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->dbdesc_list); + ospf6_lsdb_remove (lsa, on->summary_list); + size += sizeof (struct ospf6_lsa_header); + } + + if (on->summary_list->count == 0) + UNSET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); + + /* If slave, More bit check must be done here */ + if (! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT) && /* Slave */ + ! CHECK_FLAG (on->dbdesc_last.bits, OSPF6_DBDESC_MBIT) && + ! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT)) + thread_add_event (master, exchange_done, on, 0); + + thread_execute (master, ospf6_dbdesc_send, on, 0); + return 0; +} + +int +ospf6_lsreq_send (struct thread *thread) +{ + struct ospf6_neighbor *on; + struct ospf6_header *oh; + struct ospf6_lsreq_entry *e; + char *p; + struct ospf6_lsa *lsa; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + on->thread_send_lsreq = (struct thread *) NULL; + + /* LSReq will be sent only in ExStart or Loading */ + if (on->state != OSPF6_NEIGHBOR_EXCHANGE && + on->state != OSPF6_NEIGHBOR_LOADING) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSREQ, SEND)) + zlog_info ("Quit to send LSReq to neighbor %s state %s", + on->name, ospf6_neighbor_state_str[on->state]); + return 0; + } + + /* schedule loading_done if request list is empty */ + if (on->request_list->count == 0) + { + thread_add_event (master, loading_done, on, 0); + return 0; + } + + /* set next thread */ + on->thread_send_lsreq = + thread_add_timer (master, ospf6_lsreq_send, on, + on->ospf6_if->rxmt_interval); + + memset (sendbuf, 0, iobuflen); + oh = (struct ospf6_header *) sendbuf; + + /* set Request entries in lsreq */ + p = (char *)((caddr_t) oh + sizeof (struct ospf6_header)); + for (lsa = ospf6_lsdb_head (on->request_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + /* MTU check */ + if (p - sendbuf + sizeof (struct ospf6_lsreq_entry) > on->ospf6_if->ifmtu) + { + ospf6_lsa_unlock (lsa); + break; + } + + e = (struct ospf6_lsreq_entry *) p; + e->type = lsa->header->type; + e->id = lsa->header->id; + e->adv_router = lsa->header->adv_router; + p += sizeof (struct ospf6_lsreq_entry); + } + + oh->type = OSPF6_MESSAGE_TYPE_LSREQ; + oh->length = htons (p - sendbuf); + + ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, + on->ospf6_if, oh); + return 0; +} + +int +ospf6_lsupdate_send_neighbor (struct thread *thread) +{ + struct ospf6_neighbor *on; + struct ospf6_header *oh; + struct ospf6_lsupdate *lsupdate; + char *p; + int num; + struct ospf6_lsa *lsa; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + on->thread_send_lsupdate = (struct thread *) NULL; + + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) + zlog_info ("LSUpdate to neighbor %s", on->name); + + if (on->state < OSPF6_NEIGHBOR_EXCHANGE) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) + zlog_info ("Quit to send (neighbor state %s)", + ospf6_neighbor_state_str[on->state]); + return 0; + } + + /* if we have nothing to send, return */ + if (on->lsupdate_list->count == 0 && + on->retrans_list->count == 0) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) + zlog_info ("Quit to send (nothing to send)"); + return 0; + } + + memset (sendbuf, 0, iobuflen); + oh = (struct ospf6_header *) sendbuf; + lsupdate = (struct ospf6_lsupdate *) + ((caddr_t) oh + sizeof (struct ospf6_header)); + + p = (char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); + num = 0; + + /* lsupdate_list lists those LSA which doesn't need to be + retransmitted. remove those from the list */ + for (lsa = ospf6_lsdb_head (on->lsupdate_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + /* MTU check */ + if (p - sendbuf + OSPF6_LSA_SIZE (lsa->header) > on->ospf6_if->ifmtu) + { + ospf6_lsa_unlock (lsa); + break; + } + + ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); + memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); + p += OSPF6_LSA_SIZE (lsa->header); + num++; + + assert (lsa->lock == 2); + ospf6_lsdb_remove (lsa, on->lsupdate_list); + } + + for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + /* MTU check */ + if (p - sendbuf + OSPF6_LSA_SIZE (lsa->header) > on->ospf6_if->ifmtu) + { + ospf6_lsa_unlock (lsa); + break; + } + + ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); + memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); + p += OSPF6_LSA_SIZE (lsa->header); + num++; + } + + lsupdate->lsa_number = htonl (num); + + oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; + oh->length = htons (p - sendbuf); + + ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, + on->ospf6_if, oh); + + if (on->lsupdate_list->count != 0 || + on->retrans_list->count != 0) + { + if (on->lsupdate_list->count != 0) + on->thread_send_lsupdate = + thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); + else + on->thread_send_lsupdate = + thread_add_timer (master, ospf6_lsupdate_send_neighbor, on, + on->ospf6_if->rxmt_interval); + } + + return 0; +} + +int +ospf6_lsupdate_send_interface (struct thread *thread) +{ + struct ospf6_interface *oi; + struct ospf6_header *oh; + struct ospf6_lsupdate *lsupdate; + char *p; + int num; + struct ospf6_lsa *lsa; + + oi = (struct ospf6_interface *) THREAD_ARG (thread); + oi->thread_send_lsupdate = (struct thread *) NULL; + + if (oi->state <= OSPF6_INTERFACE_WAITING) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) + zlog_info ("Quit to send LSUpdate to interface %s state %s", + oi->interface->name, ospf6_interface_state_str[oi->state]); + return 0; + } + + /* if we have nothing to send, return */ + if (oi->lsupdate_list->count == 0) + return 0; + + memset (sendbuf, 0, iobuflen); + oh = (struct ospf6_header *) sendbuf; + lsupdate = (struct ospf6_lsupdate *)((caddr_t) oh + + sizeof (struct ospf6_header)); + + p = (char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); + num = 0; + + for (lsa = ospf6_lsdb_head (oi->lsupdate_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + /* MTU check */ + if (p - sendbuf + OSPF6_LSA_SIZE (lsa->header) > oi->ifmtu) + { + ospf6_lsa_unlock (lsa); + break; + } + + ospf6_lsa_age_update_to_send (lsa, oi->transdelay); + memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); + p += OSPF6_LSA_SIZE (lsa->header); + num++; + + assert (lsa->lock == 2); + ospf6_lsdb_remove (lsa, oi->lsupdate_list); + } + + lsupdate->lsa_number = htonl (num); + + oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; + oh->length = htons (p - sendbuf); + + if (oi->state == OSPF6_INTERFACE_DR || + oi->state == OSPF6_INTERFACE_BDR) + ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); + else + ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh); + + if (oi->lsupdate_list->count > 0) + { + oi->thread_send_lsupdate = + thread_add_event (master, ospf6_lsupdate_send_interface, oi, 0); + } + + return 0; +} + +int +ospf6_lsack_send_neighbor (struct thread *thread) +{ + struct ospf6_neighbor *on; + struct ospf6_header *oh; + char *p; + struct ospf6_lsa *lsa; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + on->thread_send_lsack = (struct thread *) NULL; + + if (on->state < OSPF6_NEIGHBOR_EXCHANGE) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSACK, SEND)) + zlog_info ("Quit to send LSAck to neighbor %s state %s", + on->name, ospf6_neighbor_state_str[on->state]); + return 0; + } + + /* if we have nothing to send, return */ + if (on->lsack_list->count == 0) + return 0; + + memset (sendbuf, 0, iobuflen); + oh = (struct ospf6_header *) sendbuf; + + p = (char *)((caddr_t) oh + sizeof (struct ospf6_header)); + + for (lsa = ospf6_lsdb_head (on->lsack_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + /* MTU check */ + if (p - sendbuf + sizeof (struct ospf6_lsa_header) > on->ospf6_if->ifmtu) + { + /* if we run out of packet size/space here, + better to try again soon. */ + THREAD_OFF (on->thread_send_lsack); + on->thread_send_lsack = + thread_add_event (master, ospf6_lsack_send_neighbor, on, 0); + + ospf6_lsa_unlock (lsa); + break; + } + + ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); + memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); + p += sizeof (struct ospf6_lsa_header); + + assert (lsa->lock == 2); + ospf6_lsdb_remove (lsa, on->lsack_list); + } + + oh->type = OSPF6_MESSAGE_TYPE_LSACK; + oh->length = htons (p - sendbuf); + + ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, + on->ospf6_if, oh); + return 0; +} + +int +ospf6_lsack_send_interface (struct thread *thread) +{ + struct ospf6_interface *oi; + struct ospf6_header *oh; + char *p; + struct ospf6_lsa *lsa; + + oi = (struct ospf6_interface *) THREAD_ARG (thread); + oi->thread_send_lsack = (struct thread *) NULL; + + if (oi->state <= OSPF6_INTERFACE_WAITING) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSACK, SEND)) + zlog_info ("Quit to send LSAck to interface %s state %s", + oi->interface->name, ospf6_interface_state_str[oi->state]); + return 0; + } + + /* if we have nothing to send, return */ + if (oi->lsack_list->count == 0) + return 0; + + memset (sendbuf, 0, iobuflen); + oh = (struct ospf6_header *) sendbuf; + + p = (char *)((caddr_t) oh + sizeof (struct ospf6_header)); + + for (lsa = ospf6_lsdb_head (oi->lsack_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + /* MTU check */ + if (p - sendbuf + sizeof (struct ospf6_lsa_header) > oi->ifmtu) + { + /* if we run out of packet size/space here, + better to try again soon. */ + THREAD_OFF (oi->thread_send_lsack); + oi->thread_send_lsack = + thread_add_event (master, ospf6_lsack_send_interface, oi, 0); + + ospf6_lsa_unlock (lsa); + break; + } + + ospf6_lsa_age_update_to_send (lsa, oi->transdelay); + memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); + p += sizeof (struct ospf6_lsa_header); + + assert (lsa->lock == 2); + ospf6_lsdb_remove (lsa, oi->lsack_list); + } + + oh->type = OSPF6_MESSAGE_TYPE_LSACK; + oh->length = htons (p - sendbuf); + + if (oi->state == OSPF6_INTERFACE_DR || + oi->state == OSPF6_INTERFACE_BDR) + ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); + else + ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh); + + if (oi->thread_send_lsack == NULL && oi->lsack_list->count > 0) + { + oi->thread_send_lsack = + thread_add_event (master, ospf6_lsack_send_interface, oi, 0); + } + + return 0; +} + + +/* Commands */ +DEFUN (debug_ospf6_message, + debug_ospf6_message_cmd, + "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)", + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 message\n" + "Debug Unknown message\n" + "Debug Hello message\n" + "Debug Database Description message\n" + "Debug Link State Request message\n" + "Debug Link State Update message\n" + "Debug Link State Acknowledgement message\n" + "Debug All message\n" + ) +{ + unsigned char level = 0; + int type = 0; + int i; + + assert (argc > 0); + + /* check type */ + if (! strncmp (argv[0], "u", 1)) + type = OSPF6_MESSAGE_TYPE_UNKNOWN; + else if (! strncmp (argv[0], "h", 1)) + type = OSPF6_MESSAGE_TYPE_HELLO; + else if (! strncmp (argv[0], "d", 1)) + type = OSPF6_MESSAGE_TYPE_DBDESC; + else if (! strncmp (argv[0], "lsr", 3)) + type = OSPF6_MESSAGE_TYPE_LSREQ; + else if (! strncmp (argv[0], "lsu", 3)) + type = OSPF6_MESSAGE_TYPE_LSUPDATE; + else if (! strncmp (argv[0], "lsa", 3)) + type = OSPF6_MESSAGE_TYPE_LSACK; + else if (! strncmp (argv[0], "a", 1)) + type = OSPF6_MESSAGE_TYPE_ALL; + + if (argc == 1) + level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV; + else if (! strncmp (argv[1], "s", 1)) + level = OSPF6_DEBUG_MESSAGE_SEND; + else if (! strncmp (argv[1], "r", 1)) + level = OSPF6_DEBUG_MESSAGE_RECV; + + if (type == OSPF6_MESSAGE_TYPE_ALL) + { + for (i = 0; i < 6; i++) + OSPF6_DEBUG_MESSAGE_ON (i, level); + } + else + OSPF6_DEBUG_MESSAGE_ON (type, level); + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf6_message, + debug_ospf6_message_sendrecv_cmd, + "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)", + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 message\n" + "Debug Unknown message\n" + "Debug Hello message\n" + "Debug Database Description message\n" + "Debug Link State Request message\n" + "Debug Link State Update message\n" + "Debug Link State Acknowledgement message\n" + "Debug All message\n" + "Debug only sending message\n" + "Debug only receiving message\n" + ); + + +DEFUN (no_debug_ospf6_message, + no_debug_ospf6_message_cmd, + "no debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 message\n" + "Debug Unknown message\n" + "Debug Hello message\n" + "Debug Database Description message\n" + "Debug Link State Request message\n" + "Debug Link State Update message\n" + "Debug Link State Acknowledgement message\n" + "Debug All message\n" + ) +{ + unsigned char level = 0; + int type = 0; + int i; + + assert (argc > 0); + + /* check type */ + if (! strncmp (argv[0], "u", 1)) + type = OSPF6_MESSAGE_TYPE_UNKNOWN; + else if (! strncmp (argv[0], "h", 1)) + type = OSPF6_MESSAGE_TYPE_HELLO; + else if (! strncmp (argv[0], "d", 1)) + type = OSPF6_MESSAGE_TYPE_DBDESC; + else if (! strncmp (argv[0], "lsr", 3)) + type = OSPF6_MESSAGE_TYPE_LSREQ; + else if (! strncmp (argv[0], "lsu", 3)) + type = OSPF6_MESSAGE_TYPE_LSUPDATE; + else if (! strncmp (argv[0], "lsa", 3)) + type = OSPF6_MESSAGE_TYPE_LSACK; + else if (! strncmp (argv[0], "a", 1)) + type = OSPF6_MESSAGE_TYPE_ALL; + + if (argc == 1) + level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV; + else if (! strncmp (argv[1], "s", 1)) + level = OSPF6_DEBUG_MESSAGE_SEND; + else if (! strncmp (argv[1], "r", 1)) + level = OSPF6_DEBUG_MESSAGE_RECV; + + if (type == OSPF6_MESSAGE_TYPE_ALL) + { + for (i = 0; i < 6; i++) + OSPF6_DEBUG_MESSAGE_OFF (i, level); + } + else + OSPF6_DEBUG_MESSAGE_OFF (type, level); + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf6_message, + no_debug_ospf6_message_sendrecv_cmd, + "no debug ospf6 message " + "(unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 message\n" + "Debug Unknown message\n" + "Debug Hello message\n" + "Debug Database Description message\n" + "Debug Link State Request message\n" + "Debug Link State Update message\n" + "Debug Link State Acknowledgement message\n" + "Debug All message\n" + "Debug only sending message\n" + "Debug only receiving message\n" + ); + +int +config_write_ospf6_debug_message (struct vty *vty) +{ + char *type_str[] = {"unknown", "hello", "dbdesc", + "lsreq", "lsupdate", "lsack"}; + unsigned char s = 0, r = 0; + int i; + + for (i = 0; i < 6; i++) + { + if (IS_OSPF6_DEBUG_MESSAGE (i, SEND)) + s |= 1 << i; + if (IS_OSPF6_DEBUG_MESSAGE (i, RECV)) + r |= 1 << i; + } + + if (s == 0x3f && r == 0x3f) + { + vty_out (vty, "debug ospf6 message all%s", VNL); + return 0; + } + + if (s == 0x3f && r == 0) + { + vty_out (vty, "debug ospf6 message all send%s", VNL); + return 0; + } + else if (s == 0 && r == 0x3f) + { + vty_out (vty, "debug ospf6 message all recv%s", VNL); + return 0; + } + + /* Unknown message is logged by default */ + if (! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, SEND) && + ! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + vty_out (vty, "no debug ospf6 message unknown%s", VNL); + else if (! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, SEND)) + vty_out (vty, "no debug ospf6 message unknown send%s", VNL); + else if (! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + vty_out (vty, "no debug ospf6 message unknown recv%s", VNL); + + for (i = 1; i < 6; i++) + { + if (IS_OSPF6_DEBUG_MESSAGE (i, SEND) && + IS_OSPF6_DEBUG_MESSAGE (i, RECV)) + vty_out (vty, "debug ospf6 message %s%s", type_str[i], VNL); + else if (IS_OSPF6_DEBUG_MESSAGE (i, SEND)) + vty_out (vty, "debug ospf6 message %s send%s", type_str[i], + VNL); + else if (IS_OSPF6_DEBUG_MESSAGE (i, RECV)) + vty_out (vty, "debug ospf6 message %s recv%s", type_str[i], + VNL); + } + + return 0; +} + +void +install_element_ospf6_debug_message () +{ + install_element (ENABLE_NODE, &debug_ospf6_message_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_message_cmd); + install_element (ENABLE_NODE, &debug_ospf6_message_sendrecv_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_message_sendrecv_cmd); + install_element (CONFIG_NODE, &debug_ospf6_message_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_message_cmd); + install_element (CONFIG_NODE, &debug_ospf6_message_sendrecv_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_message_sendrecv_cmd); +} + + diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h new file mode 100644 index 0000000..186fc74 --- /dev/null +++ b/ospf6d/ospf6_message.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 1999-2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_MESSAGE_H +#define OSPF6_MESSAGE_H + +#define OSPF6_MESSAGE_BUFSIZ 4096 + +/* Debug option */ +extern unsigned char conf_debug_ospf6_message[]; +#define OSPF6_DEBUG_MESSAGE_SEND 0x01 +#define OSPF6_DEBUG_MESSAGE_RECV 0x02 +#define OSPF6_DEBUG_MESSAGE_ON(type, level) \ + (conf_debug_ospf6_message[type] |= (level)) +#define OSPF6_DEBUG_MESSAGE_OFF(type, level) \ + (conf_debug_ospf6_message[type] &= ~(level)) +#define IS_OSPF6_DEBUG_MESSAGE(t, e) \ + (conf_debug_ospf6_message[t] & OSPF6_DEBUG_MESSAGE_ ## e) + +/* Type */ +#define OSPF6_MESSAGE_TYPE_UNKNOWN 0x0 +#define OSPF6_MESSAGE_TYPE_HELLO 0x1 /* Discover/maintain neighbors */ +#define OSPF6_MESSAGE_TYPE_DBDESC 0x2 /* Summarize database contents */ +#define OSPF6_MESSAGE_TYPE_LSREQ 0x3 /* Database download request */ +#define OSPF6_MESSAGE_TYPE_LSUPDATE 0x4 /* Database update */ +#define OSPF6_MESSAGE_TYPE_LSACK 0x5 /* Flooding acknowledgment */ +#define OSPF6_MESSAGE_TYPE_ALL 0x6 /* For debug option */ + +#define OSPF6_MESSAGE_TYPE_CANONICAL(T) \ + ((T) > OSPF6_MESSAGE_TYPE_LSACK ? OSPF6_MESSAGE_TYPE_UNKNOWN : (T)) + +extern char *ospf6_message_type_str[]; +#define OSPF6_MESSAGE_TYPE_NAME(T) \ + (ospf6_message_type_str[ OSPF6_MESSAGE_TYPE_CANONICAL (T) ]) + +/* OSPFv3 packet header */ +struct ospf6_header +{ + u_char version; + u_char type; + u_int16_t length; + u_int32_t router_id; + u_int32_t area_id; + u_int16_t checksum; + u_char instance_id; + u_char reserved; +}; + +#define OSPF6_MESSAGE_END(H) ((caddr_t) (H) + ntohs ((H)->length)) + +/* Hello */ +struct ospf6_hello +{ + u_int32_t interface_id; + u_char priority; + u_char options[3]; + u_int16_t hello_interval; + u_int16_t dead_interval; + u_int32_t drouter; + u_int32_t bdrouter; + /* Followed by Router-IDs */ +}; + +/* Database Description */ +struct ospf6_dbdesc +{ + u_char reserved1; + u_char options[3]; + u_int16_t ifmtu; + u_char reserved2; + u_char bits; + u_int32_t seqnum; + /* Followed by LSA Headers */ +}; + +#define OSPF6_DBDESC_MSBIT (0x01) /* master/slave bit */ +#define OSPF6_DBDESC_MBIT (0x02) /* more bit */ +#define OSPF6_DBDESC_IBIT (0x04) /* initial bit */ + +/* Link State Request */ +/* It is just a sequence of entries below */ +struct ospf6_lsreq_entry +{ + u_int16_t reserved; /* Must Be Zero */ + u_int16_t type; /* LS type */ + u_int32_t id; /* Link State ID */ + u_int32_t adv_router; /* Advertising Router */ +}; + +/* Link State Update */ +struct ospf6_lsupdate +{ + u_int32_t lsa_number; + /* Followed by LSAs */ +}; + +/* Link State Acknowledgement */ +/* It is just a sequence of LSA Headers */ + +/* Function definition */ +void ospf6_hello_print (struct ospf6_header *); +void ospf6_dbdesc_print (struct ospf6_header *); +void ospf6_lsreq_print (struct ospf6_header *); +void ospf6_lsupdate_print (struct ospf6_header *); +void ospf6_lsack_print (struct ospf6_header *); + +int ospf6_iobuf_size (int size); +int ospf6_receive (struct thread *thread); + +int ospf6_hello_send (struct thread *thread); +int ospf6_dbdesc_send (struct thread *thread); +int ospf6_dbdesc_send_newone (struct thread *thread); +int ospf6_lsreq_send (struct thread *thread); +int ospf6_lsupdate_send_interface (struct thread *thread); +int ospf6_lsupdate_send_neighbor (struct thread *thread); +int ospf6_lsack_send_interface (struct thread *thread); +int ospf6_lsack_send_neighbor (struct thread *thread); + +int config_write_ospf6_debug_message (struct vty *); +void install_element_ospf6_debug_message (); + +#endif /* OSPF6_MESSAGE_H */ + diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c new file mode 100644 index 0000000..ad4261f --- /dev/null +++ b/ospf6d/ospf6_neighbor.c @@ -0,0 +1,973 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "memory.h" +#include "thread.h" +#include "linklist.h" +#include "vty.h" +#include "command.h" + +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_message.h" +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" +#include "ospf6_intra.h" +#include "ospf6_flood.h" +#include "ospf6d.h" + +unsigned char conf_debug_ospf6_neighbor = 0; + +char *ospf6_neighbor_state_str[] = +{ "None", "Down", "Attempt", "Init", "Twoway", "ExStart", "ExChange", + "Loading", "Full", NULL }; + +int +ospf6_neighbor_cmp (void *va, void *vb) +{ + struct ospf6_neighbor *ona = (struct ospf6_neighbor *) va; + struct ospf6_neighbor *onb = (struct ospf6_neighbor *) vb; + return (ntohl (ona->router_id) < ntohl (onb->router_id) ? -1 : 1); +} + +struct ospf6_neighbor * +ospf6_neighbor_lookup (u_int32_t router_id, + struct ospf6_interface *oi) +{ + listnode n; + struct ospf6_neighbor *on; + + for (n = listhead (oi->neighbor_list); n; nextnode (n)) + { + on = (struct ospf6_neighbor *) getdata (n); + if (on->router_id == router_id) + return on; + } + return (struct ospf6_neighbor *) NULL; +} + +/* create ospf6_neighbor */ +struct ospf6_neighbor * +ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *oi) +{ + struct ospf6_neighbor *on; + char buf[16]; + + on = (struct ospf6_neighbor *) + XMALLOC (MTYPE_OSPF6_NEIGHBOR, sizeof (struct ospf6_neighbor)); + if (on == NULL) + { + zlog_warn ("neighbor: malloc failed"); + return NULL; + } + + memset (on, 0, sizeof (struct ospf6_neighbor)); + inet_ntop (AF_INET, &router_id, buf, sizeof (buf)); + snprintf (on->name, sizeof (on->name), "%s%%%s", + buf, oi->interface->name); + on->ospf6_if = oi; + on->state = OSPF6_NEIGHBOR_DOWN; + gettimeofday (&on->last_changed, (struct timezone *) NULL); + on->router_id = router_id; + + on->summary_list = ospf6_lsdb_create (on); + on->request_list = ospf6_lsdb_create (on); + on->retrans_list = ospf6_lsdb_create (on); + + on->dbdesc_list = ospf6_lsdb_create (on); + on->lsreq_list = ospf6_lsdb_create (on); + on->lsupdate_list = ospf6_lsdb_create (on); + on->lsack_list = ospf6_lsdb_create (on); + + listnode_add_sort (oi->neighbor_list, on); + return on; +} + +void +ospf6_neighbor_delete (struct ospf6_neighbor *on) +{ + struct ospf6_lsa *lsa; + + ospf6_lsdb_remove_all (on->summary_list); + ospf6_lsdb_remove_all (on->request_list); + for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + ospf6_decrement_retrans_count (lsa); + ospf6_lsdb_remove (lsa, on->retrans_list); + } + + ospf6_lsdb_remove_all (on->dbdesc_list); + ospf6_lsdb_remove_all (on->lsreq_list); + ospf6_lsdb_remove_all (on->lsupdate_list); + ospf6_lsdb_remove_all (on->lsack_list); + + ospf6_lsdb_delete (on->summary_list); + ospf6_lsdb_delete (on->request_list); + ospf6_lsdb_delete (on->retrans_list); + + ospf6_lsdb_delete (on->dbdesc_list); + ospf6_lsdb_delete (on->lsreq_list); + ospf6_lsdb_delete (on->lsupdate_list); + ospf6_lsdb_delete (on->lsack_list); + + THREAD_OFF (on->inactivity_timer); + + THREAD_OFF (on->thread_send_dbdesc); + THREAD_OFF (on->thread_send_lsreq); + THREAD_OFF (on->thread_send_lsupdate); + THREAD_OFF (on->thread_send_lsack); + + XFREE (MTYPE_OSPF6_NEIGHBOR, on); +} + +static void +ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on) +{ + u_char prev_state; + + prev_state = on->state; + on->state = next_state; + + if (prev_state == next_state) + return; + + gettimeofday (&on->last_changed, (struct timezone *) NULL); + + /* log */ + if (IS_OSPF6_DEBUG_NEIGHBOR (STATE)) + { + zlog_info ("Neighbor state change %s: [%s]->[%s]", on->name, + ospf6_neighbor_state_str[prev_state], + ospf6_neighbor_state_str[next_state]); + } + + if (prev_state == OSPF6_NEIGHBOR_FULL || next_state == OSPF6_NEIGHBOR_FULL) + { + OSPF6_ROUTER_LSA_SCHEDULE (on->ospf6_if->area); + if (on->ospf6_if->state == OSPF6_INTERFACE_DR) + { + OSPF6_NETWORK_LSA_SCHEDULE (on->ospf6_if); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (on->ospf6_if); + } + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (on->ospf6_if->area); + } + +#ifdef XXX + if (prev_state == NBS_FULL || next_state == NBS_FULL) + nbs_full_change (on->ospf6_interface); + + /* check for LSAs that already reached MaxAge */ + if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE || + prev_state == OSPF6_NEIGHBOR_LOADING) && + (next_state != OSPF6_NEIGHBOR_EXCHANGE && + next_state != OSPF6_NEIGHBOR_LOADING)) + { + ospf6_maxage_remover (); + } +#endif /*XXX*/ + +} + +/* RFC2328 section 10.4 */ +int +need_adjacency (struct ospf6_neighbor *on) +{ + if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT || + on->ospf6_if->state == OSPF6_INTERFACE_DR || + on->ospf6_if->state == OSPF6_INTERFACE_BDR) + return 1; + + if (on->ospf6_if->drouter == on->router_id || + on->ospf6_if->bdrouter == on->router_id) + return 1; + + return 0; +} + +int +hello_received (struct thread *thread) +{ + struct ospf6_neighbor *on; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (on); + + if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) + zlog_info ("Neighbor Event %s: *HelloReceived*", on->name); + + /* reset Inactivity Timer */ + THREAD_OFF (on->inactivity_timer); + on->inactivity_timer = thread_add_timer (master, inactivity_timer, on, + on->ospf6_if->dead_interval); + + if (on->state <= OSPF6_NEIGHBOR_DOWN) + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_INIT, on); + + return 0; +} + +int +twoway_received (struct thread *thread) +{ + struct ospf6_neighbor *on; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (on); + + if (on->state > OSPF6_NEIGHBOR_INIT) + return 0; + + if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) + zlog_info ("Neighbor Event %s: *2Way-Received*", on->name); + + thread_add_event (master, neighbor_change, on->ospf6_if, 0); + + if (! need_adjacency (on)) + { + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_TWOWAY, on); + return 0; + } + + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on); + SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); + SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); + SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); + + THREAD_OFF (on->thread_send_dbdesc); + on->thread_send_dbdesc = + thread_add_event (master, ospf6_dbdesc_send, on, 0); + + return 0; +} + +int +negotiation_done (struct thread *thread) +{ + struct ospf6_neighbor *on; + struct ospf6_lsa *lsa; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (on); + + if (on->state != OSPF6_NEIGHBOR_EXSTART) + return 0; + + if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) + zlog_info ("Neighbor Event %s: *NegotiationDone*", on->name); + + /* clear ls-list */ + ospf6_lsdb_remove_all (on->summary_list); + ospf6_lsdb_remove_all (on->request_list); + for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + ospf6_decrement_retrans_count (lsa); + ospf6_lsdb_remove (lsa, on->retrans_list); + } + + /* Interface scoped LSAs */ + for (lsa = ospf6_lsdb_head (on->ospf6_if->lsdb); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + if (OSPF6_LSA_IS_MAXAGE (lsa)) + { + ospf6_increment_retrans_count (lsa); + ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list); + } + else + ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->summary_list); + } + + /* Area scoped LSAs */ + for (lsa = ospf6_lsdb_head (on->ospf6_if->area->lsdb); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + if (OSPF6_LSA_IS_MAXAGE (lsa)) + { + ospf6_increment_retrans_count (lsa); + ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list); + } + else + ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->summary_list); + } + + /* AS scoped LSAs */ + for (lsa = ospf6_lsdb_head (on->ospf6_if->area->ospf6->lsdb); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + if (OSPF6_LSA_IS_MAXAGE (lsa)) + { + ospf6_increment_retrans_count (lsa); + ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list); + } + else + ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->summary_list); + } + + UNSET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXCHANGE, on); + + return 0; +} + +int +exchange_done (struct thread *thread) +{ + struct ospf6_neighbor *on; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (on); + + if (on->state != OSPF6_NEIGHBOR_EXCHANGE) + return 0; + + if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) + zlog_info ("Neighbor Event %s: *ExchangeDone*", on->name); + + THREAD_OFF (on->thread_send_dbdesc); + ospf6_lsdb_remove_all (on->dbdesc_list); + +/* XXX + thread_add_timer (master, ospf6_neighbor_last_dbdesc_release, on, + on->ospf6_if->dead_interval); +*/ + + if (on->request_list->count == 0) + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_FULL, on); + else + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_LOADING, on); + + return 0; +} + +int +loading_done (struct thread *thread) +{ + struct ospf6_neighbor *on; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (on); + + if (on->state != OSPF6_NEIGHBOR_LOADING) + return 0; + + if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) + zlog_info ("Neighbor Event %s: *LoadingDone*", on->name); + + assert (on->request_list->count == 0); + + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_FULL, on); + + return 0; +} + +int +adj_ok (struct thread *thread) +{ + struct ospf6_neighbor *on; + struct ospf6_lsa *lsa; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (on); + + if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) + zlog_info ("Neighbor Event %s: *AdjOK?*", on->name); + + if (on->state == OSPF6_NEIGHBOR_TWOWAY && need_adjacency (on)) + { + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on); + SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); + SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); + SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); + + THREAD_OFF (on->thread_send_dbdesc); + on->thread_send_dbdesc = + thread_add_event (master, ospf6_dbdesc_send, on, 0); + + } + else if (on->state >= OSPF6_NEIGHBOR_EXSTART && + ! need_adjacency (on)) + { + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_TWOWAY, on); + ospf6_lsdb_remove_all (on->summary_list); + ospf6_lsdb_remove_all (on->request_list); + for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + ospf6_decrement_retrans_count (lsa); + ospf6_lsdb_remove (lsa, on->retrans_list); + } + } + + return 0; +} + +int +seqnumber_mismatch (struct thread *thread) +{ + struct ospf6_neighbor *on; + struct ospf6_lsa *lsa; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (on); + + if (on->state < OSPF6_NEIGHBOR_EXCHANGE) + return 0; + + if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) + zlog_info ("Neighbor Event %s: *SeqNumberMismatch*", on->name); + + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on); + SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); + SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); + SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); + + ospf6_lsdb_remove_all (on->summary_list); + ospf6_lsdb_remove_all (on->request_list); + for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + ospf6_decrement_retrans_count (lsa); + ospf6_lsdb_remove (lsa, on->retrans_list); + } + + THREAD_OFF (on->thread_send_dbdesc); + on->thread_send_dbdesc = + thread_add_event (master, ospf6_dbdesc_send, on, 0); + + return 0; +} + +int +bad_lsreq (struct thread *thread) +{ + struct ospf6_neighbor *on; + struct ospf6_lsa *lsa; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (on); + + if (on->state < OSPF6_NEIGHBOR_EXCHANGE) + return 0; + + if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) + zlog_info ("Neighbor Event %s: *BadLSReq*", on->name); + + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on); + SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); + SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); + SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); + + ospf6_lsdb_remove_all (on->summary_list); + ospf6_lsdb_remove_all (on->request_list); + for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + ospf6_decrement_retrans_count (lsa); + ospf6_lsdb_remove (lsa, on->retrans_list); + } + + THREAD_OFF (on->thread_send_dbdesc); + on->thread_send_dbdesc = + thread_add_event (master, ospf6_dbdesc_send, on, 0); + + return 0; +} + +int +oneway_received (struct thread *thread) +{ + struct ospf6_neighbor *on; + struct ospf6_lsa *lsa; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (on); + + if (on->state < OSPF6_NEIGHBOR_TWOWAY) + return 0; + + if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) + zlog_info ("Neighbor Event %s: *1Way-Received*", on->name); + + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_INIT, on); + thread_add_event (master, neighbor_change, on->ospf6_if, 0); + + ospf6_lsdb_remove_all (on->summary_list); + ospf6_lsdb_remove_all (on->request_list); + for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + ospf6_decrement_retrans_count (lsa); + ospf6_lsdb_remove (lsa, on->retrans_list); + } + + THREAD_OFF (on->thread_send_dbdesc); + THREAD_OFF (on->thread_send_lsreq); + THREAD_OFF (on->thread_send_lsupdate); + THREAD_OFF (on->thread_send_lsack); + + return 0; +} + +int +inactivity_timer (struct thread *thread) +{ + struct ospf6_neighbor *on; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + assert (on); + + if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) + zlog_info ("Neighbor Event %s: *InactivityTimer*", on->name); + + on->inactivity_timer = NULL; + on->drouter = on->prev_drouter = 0; + on->bdrouter = on->prev_bdrouter = 0; + + ospf6_neighbor_state_change (OSPF6_NEIGHBOR_DOWN, on); + thread_add_event (master, neighbor_change, on->ospf6_if, 0); + + listnode_delete (on->ospf6_if->neighbor_list, on); + ospf6_neighbor_delete (on); + + return 0; +} + + + +/* vty functions */ +/* show neighbor structure */ +void +ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *on) +{ + char router_id[16]; + char duration[16]; + struct timeval now, res; + char nstate[16]; + char deadtime[16]; + long h, m, s; + + /* Router-ID (Name) */ + inet_ntop (AF_INET, &on->router_id, router_id, sizeof (router_id)); +#ifdef HAVE_GETNAMEINFO + { + } +#endif /*HAVE_GETNAMEINFO*/ + + gettimeofday (&now, NULL); + + /* Dead time */ + h = m = s = 0; + if (on->inactivity_timer) + { + s = on->inactivity_timer->u.sands.tv_sec - now.tv_sec; + h = s / 3600; + s -= h * 3600; + m = s / 60; + s -= m * 60; + } + snprintf (deadtime, sizeof (deadtime), "%02ld:%02ld:%02ld", h, m, s); + + /* Neighbor State */ + if (if_is_pointopoint (on->ospf6_if->interface)) + snprintf (nstate, sizeof (nstate), "PointToPoint"); + else + { + if (on->router_id == on->drouter) + snprintf (nstate, sizeof (nstate), "DR"); + else if (on->router_id == on->bdrouter) + snprintf (nstate, sizeof (nstate), "BDR"); + else + snprintf (nstate, sizeof (nstate), "DROther"); + } + + /* Duration */ + timersub (&now, &on->last_changed, &res); + timerstring (&res, duration, sizeof (duration)); + + /* + vty_out (vty, "%-15s %3d %11s %6s/%-12s %11s %s[%s]%s", + "Neighbor ID", "Pri", "DeadTime", "State", "", "Duration", + "I/F", "State", VNL); + */ + + vty_out (vty, "%-15s %3d %11s %6s/%-12s %11s %s[%s]%s", + router_id, on->priority, deadtime, + ospf6_neighbor_state_str[on->state], nstate, duration, + on->ospf6_if->interface->name, + ospf6_interface_state_str[on->ospf6_if->state], VNL); +} + +void +ospf6_neighbor_show_drchoice (struct vty *vty, struct ospf6_neighbor *on) +{ + char router_id[16]; + char drouter[16], bdrouter[16]; + char duration[16]; + struct timeval now, res; + +/* + vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s", + "RouterID", "State", "Duration", "DR", "BDR", "I/F", + "State", VNL); +*/ + + inet_ntop (AF_INET, &on->router_id, router_id, sizeof (router_id)); + inet_ntop (AF_INET, &on->drouter, drouter, sizeof (drouter)); + inet_ntop (AF_INET, &on->bdrouter, bdrouter, sizeof (bdrouter)); + + gettimeofday (&now, NULL); + timersub (&now, &on->last_changed, &res); + timerstring (&res, duration, sizeof (duration)); + + vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s", + router_id, ospf6_neighbor_state_str[on->state], + duration, drouter, bdrouter, on->ospf6_if->interface->name, + ospf6_interface_state_str[on->ospf6_if->state], + VNL); +} + +void +ospf6_neighbor_show_detail (struct vty *vty, struct ospf6_neighbor *on) +{ + char drouter[16], bdrouter[16]; + char linklocal_addr[64], duration[32]; + struct timeval now, res; + struct ospf6_lsa *lsa; + + inet_ntop (AF_INET6, &on->linklocal_addr, linklocal_addr, + sizeof (linklocal_addr)); + inet_ntop (AF_INET, &on->drouter, drouter, sizeof (drouter)); + inet_ntop (AF_INET, &on->bdrouter, bdrouter, sizeof (bdrouter)); + + gettimeofday (&now, NULL); + timersub (&now, &on->last_changed, &res); + timerstring (&res, duration, sizeof (duration)); + + vty_out (vty, " Neighbor %s%s", on->name, + VNL); + vty_out (vty, " Area %s via interface %s (ifindex %d)%s", + on->ospf6_if->area->name, + on->ospf6_if->interface->name, + on->ospf6_if->interface->ifindex, + VNL); + vty_out (vty, " His IfIndex: %d Link-local address: %s%s", + on->ifindex, linklocal_addr, + VNL); + vty_out (vty, " State %s for a duration of %s%s", + ospf6_neighbor_state_str[on->state], duration, + VNL); + vty_out (vty, " His choice of DR/BDR %s/%s, Priority %d%s", + drouter, bdrouter, on->priority, + VNL); + vty_out (vty, " DbDesc status: %s%s%s SeqNum: %#lx%s", + (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT) ? "Initial " : ""), + (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT) ? "More " : ""), + (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT) ? + "Master" : "Slave"), (u_long) ntohl (on->dbdesc_seqnum), + VNL); + + vty_out (vty, " Summary-List: %d LSAs%s", on->summary_list->count, + VNL); + for (lsa = ospf6_lsdb_head (on->summary_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + vty_out (vty, " %s%s", lsa->name, VNL); + + vty_out (vty, " Request-List: %d LSAs%s", on->request_list->count, + VNL); + for (lsa = ospf6_lsdb_head (on->request_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + vty_out (vty, " %s%s", lsa->name, VNL); + + vty_out (vty, " Retrans-List: %d LSAs%s", on->retrans_list->count, + VNL); + for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + vty_out (vty, " %s%s", lsa->name, VNL); + + timerclear (&res); + if (on->thread_send_dbdesc) + timersub (&on->thread_send_dbdesc->u.sands, &now, &res); + timerstring (&res, duration, sizeof (duration)); + vty_out (vty, " %d Pending LSAs for DbDesc in Time %s [thread %s]%s", + on->dbdesc_list->count, duration, + (on->thread_send_dbdesc ? "on" : "off"), + VNL); + for (lsa = ospf6_lsdb_head (on->dbdesc_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + vty_out (vty, " %s%s", lsa->name, VNL); + + timerclear (&res); + if (on->thread_send_lsreq) + timersub (&on->thread_send_lsreq->u.sands, &now, &res); + timerstring (&res, duration, sizeof (duration)); + vty_out (vty, " %d Pending LSAs for LSReq in Time %s [thread %s]%s", + on->lsreq_list->count, duration, + (on->thread_send_lsreq ? "on" : "off"), + VNL); + for (lsa = ospf6_lsdb_head (on->lsreq_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + vty_out (vty, " %s%s", lsa->name, VNL); + + timerclear (&res); + if (on->thread_send_lsupdate) + timersub (&on->thread_send_lsupdate->u.sands, &now, &res); + timerstring (&res, duration, sizeof (duration)); + vty_out (vty, " %d Pending LSAs for LSUpdate in Time %s [thread %s]%s", + on->lsupdate_list->count, duration, + (on->thread_send_lsupdate ? "on" : "off"), + VNL); + for (lsa = ospf6_lsdb_head (on->lsupdate_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + vty_out (vty, " %s%s", lsa->name, VNL); + + timerclear (&res); + if (on->thread_send_lsack) + timersub (&on->thread_send_lsack->u.sands, &now, &res); + timerstring (&res, duration, sizeof (duration)); + vty_out (vty, " %d Pending LSAs for LSAck in Time %s [thread %s]%s", + on->lsack_list->count, duration, + (on->thread_send_lsack ? "on" : "off"), + VNL); + for (lsa = ospf6_lsdb_head (on->lsack_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + vty_out (vty, " %s%s", lsa->name, VNL); + +} + +DEFUN (show_ipv6_ospf6_neighbor, + show_ipv6_ospf6_neighbor_cmd, + "show ipv6 ospf6 neighbor", + SHOW_STR + IP6_STR + OSPF6_STR + "Neighbor list\n" + ) +{ + struct ospf6_neighbor *on; + struct ospf6_interface *oi; + struct ospf6_area *oa; + listnode i, j, k; + void (*showfunc) (struct vty *, struct ospf6_neighbor *); + + OSPF6_CMD_CHECK_RUNNING (); + showfunc = ospf6_neighbor_show; + + if (argc) + { + if (! strncmp (argv[0], "de", 2)) + showfunc = ospf6_neighbor_show_detail; + else if (! strncmp (argv[0], "dr", 2)) + showfunc = ospf6_neighbor_show_drchoice; + } + + if (showfunc == ospf6_neighbor_show) + vty_out (vty, "%-15s %3s %11s %6s/%-12s %11s %s[%s]%s", + "Neighbor ID", "Pri", "DeadTime", "State", "IfState", "Duration", + "I/F", "State", VNL); + else if (showfunc == ospf6_neighbor_show_drchoice) + vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s", + "RouterID", "State", "Duration", "DR", "BDR", "I/F", + "State", VNL); + + for (i = listhead (ospf6->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + for (k = listhead (oi->neighbor_list); k; nextnode (k)) + { + on = (struct ospf6_neighbor *) getdata (k); + (*showfunc) (vty, on); + } + } + } + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_neighbor, + show_ipv6_ospf6_neighbor_detail_cmd, + "show ipv6 ospf6 neighbor (detail|drchoice)", + SHOW_STR + IP6_STR + OSPF6_STR + "Neighbor list\n" + "Display details\n" + "Display DR choices\n" + ); + +DEFUN (show_ipv6_ospf6_neighbor_one, + show_ipv6_ospf6_neighbor_one_cmd, + "show ipv6 ospf6 neighbor A.B.C.D", + SHOW_STR + IP6_STR + OSPF6_STR + "Neighbor list\n" + "Specify Router-ID as IPv4 address notation\n" + ) +{ + struct ospf6_neighbor *on; + struct ospf6_interface *oi; + struct ospf6_area *oa; + listnode i, j, k; + void (*showfunc) (struct vty *, struct ospf6_neighbor *); + u_int32_t router_id; + + OSPF6_CMD_CHECK_RUNNING (); + showfunc = ospf6_neighbor_show_detail; + + if ((inet_pton (AF_INET, argv[0], &router_id)) != 1) + { + vty_out (vty, "Router-ID is not parsable: %s%s", argv[0], + VNL); + return CMD_SUCCESS; + } + + for (i = listhead (ospf6->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + for (k = listhead (oi->neighbor_list); k; nextnode (k)) + { + on = (struct ospf6_neighbor *) getdata (k); + if (on->router_id == router_id) + (*showfunc) (vty, on); + } + } + } + return CMD_SUCCESS; +} + +void +ospf6_neighbor_init () +{ + install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_detail_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_detail_cmd); +} + +DEFUN (debug_ospf6_neighbor, + debug_ospf6_neighbor_cmd, + "debug ospf6 neighbor", + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 Neighbor\n" + ) +{ + unsigned char level = 0; + if (argc) + { + if (! strncmp (argv[0], "s", 1)) + level = OSPF6_DEBUG_NEIGHBOR_STATE; + if (! strncmp (argv[0], "e", 1)) + level = OSPF6_DEBUG_NEIGHBOR_EVENT; + } + else + level = OSPF6_DEBUG_NEIGHBOR_STATE | OSPF6_DEBUG_NEIGHBOR_EVENT; + + OSPF6_DEBUG_NEIGHBOR_ON (level); + return CMD_SUCCESS; +} + +ALIAS (debug_ospf6_neighbor, + debug_ospf6_neighbor_detail_cmd, + "debug ospf6 neighbor (state|event)", + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 Neighbor\n" + "Debug OSPFv3 Neighbor State Change\n" + "Debug OSPFv3 Neighbor Event\n" + ); + +DEFUN (no_debug_ospf6_neighbor, + no_debug_ospf6_neighbor_cmd, + "no debug ospf6 neighbor", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 Neighbor\n" + ) +{ + unsigned char level = 0; + if (argc) + { + if (! strncmp (argv[0], "s", 1)) + level = OSPF6_DEBUG_NEIGHBOR_STATE; + if (! strncmp (argv[0], "e", 1)) + level = OSPF6_DEBUG_NEIGHBOR_EVENT; + } + else + level = OSPF6_DEBUG_NEIGHBOR_STATE | OSPF6_DEBUG_NEIGHBOR_EVENT; + + OSPF6_DEBUG_NEIGHBOR_OFF (level); + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf6_neighbor, + no_debug_ospf6_neighbor_detail_cmd, + "no debug ospf6 neighbor (state|event)", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 Neighbor\n" + "Debug OSPFv3 Neighbor State Change\n" + "Debug OSPFv3 Neighbor Event\n" + ); + +int +config_write_ospf6_debug_neighbor (struct vty *vty) +{ + if (IS_OSPF6_DEBUG_NEIGHBOR (STATE) && + IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) + vty_out (vty, "debug ospf6 neighbor%s", VNL); + else if (IS_OSPF6_DEBUG_NEIGHBOR (STATE)) + vty_out (vty, "debug ospf6 neighbor state%s", VNL); + else if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) + vty_out (vty, "debug ospf6 neighbor event%s", VNL); + return 0; +} + +void +install_element_ospf6_debug_neighbor () +{ + install_element (ENABLE_NODE, &debug_ospf6_neighbor_cmd); + install_element (ENABLE_NODE, &debug_ospf6_neighbor_detail_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_detail_cmd); + install_element (CONFIG_NODE, &debug_ospf6_neighbor_cmd); + install_element (CONFIG_NODE, &debug_ospf6_neighbor_detail_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_detail_cmd); +} + + + diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h new file mode 100644 index 0000000..441ab81 --- /dev/null +++ b/ospf6d/ospf6_neighbor.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_NEIGHBOR_H +#define OSPF6_NEIGHBOR_H + +/* Debug option */ +extern unsigned char conf_debug_ospf6_neighbor; +#define OSPF6_DEBUG_NEIGHBOR_STATE 0x01 +#define OSPF6_DEBUG_NEIGHBOR_EVENT 0x02 +#define OSPF6_DEBUG_NEIGHBOR_ON(level) \ + (conf_debug_ospf6_neighbor |= (level)) +#define OSPF6_DEBUG_NEIGHBOR_OFF(level) \ + (conf_debug_ospf6_neighbor &= ~(level)) +#define IS_OSPF6_DEBUG_NEIGHBOR(level) \ + (conf_debug_ospf6_neighbor & OSPF6_DEBUG_NEIGHBOR_ ## level) + +/* Neighbor structure */ +struct ospf6_neighbor +{ + /* Neighbor Router ID String */ + char name[32]; + + /* OSPFv3 Interface this neighbor belongs to */ + struct ospf6_interface *ospf6_if; + + /* Neighbor state */ + u_char state; + + /* timestamp of last changing state */ + struct timeval last_changed; + + /* Neighbor Router ID */ + u_int32_t router_id; + + /* Neighbor Interface ID */ + u_int32_t ifindex; + + /* Router Priority of this neighbor */ + u_char priority; + + u_int32_t drouter; + u_int32_t bdrouter; + u_int32_t prev_drouter; + u_int32_t prev_bdrouter; + + /* Options field (Capability) */ + char options[3]; + + /* IPaddr of I/F on our side link */ + struct in6_addr linklocal_addr; + + /* For Database Exchange */ + u_char dbdesc_bits; + u_int32_t dbdesc_seqnum; + /* Last received Database Description packet */ + struct ospf6_dbdesc dbdesc_last; + + /* LS-list */ + struct ospf6_lsdb *summary_list; + struct ospf6_lsdb *request_list; + struct ospf6_lsdb *retrans_list; + + /* LSA list for message transmission */ + struct ospf6_lsdb *dbdesc_list; + struct ospf6_lsdb *lsreq_list; + struct ospf6_lsdb *lsupdate_list; + struct ospf6_lsdb *lsack_list; + + /* Inactivity timer */ + struct thread *inactivity_timer; + + /* Thread for sending message */ + struct thread *thread_send_dbdesc; + struct thread *thread_send_lsreq; + struct thread *thread_send_lsupdate; + struct thread *thread_send_lsack; +}; + +/* Neighbor state */ +#define OSPF6_NEIGHBOR_DOWN 1 +#define OSPF6_NEIGHBOR_ATTEMPT 2 +#define OSPF6_NEIGHBOR_INIT 3 +#define OSPF6_NEIGHBOR_TWOWAY 4 +#define OSPF6_NEIGHBOR_EXSTART 5 +#define OSPF6_NEIGHBOR_EXCHANGE 6 +#define OSPF6_NEIGHBOR_LOADING 7 +#define OSPF6_NEIGHBOR_FULL 8 + +extern char *ospf6_neighbor_state_str[]; + + +/* Function Prototypes */ +int ospf6_neighbor_cmp (void *va, void *vb); +void ospf6_neighbor_dbex_init (struct ospf6_neighbor *on); + +struct ospf6_neighbor *ospf6_neighbor_lookup (u_int32_t, + struct ospf6_interface *); +struct ospf6_neighbor *ospf6_neighbor_create (u_int32_t, + struct ospf6_interface *); +void ospf6_neighbor_delete (struct ospf6_neighbor *); + +/* Neighbor event */ +int hello_received (struct thread *); +int twoway_received (struct thread *); +int negotiation_done (struct thread *); +int exchange_done (struct thread *); +int loading_done (struct thread *); +int adj_ok (struct thread *); +int seqnumber_mismatch (struct thread *); +int bad_lsreq (struct thread *); +int oneway_received (struct thread *); +int inactivity_timer (struct thread *); + +void ospf6_neighbor_init (); +int config_write_ospf6_debug_neighbor (struct vty *vty); +void install_element_ospf6_debug_neighbor (); + +#endif /* OSPF6_NEIGHBOR_H */ + diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c new file mode 100644 index 0000000..e7e754f --- /dev/null +++ b/ospf6d/ospf6_network.c @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "memory.h" +#include "sockunion.h" + +#include "ospf6_proto.h" +#include "ospf6_network.h" + +int ospf6_sock; +struct in6_addr allspfrouters6; +struct in6_addr alldrouters6; + +/* setsockopt ReUseAddr to on */ +void +ospf6_set_reuseaddr () +{ + u_int on = 0; + if (setsockopt (ospf6_sock, SOL_SOCKET, SO_REUSEADDR, &on, + sizeof (u_int)) < 0) + zlog_warn ("Network: set SO_REUSEADDR failed: %s", strerror (errno)); +} + +/* setsockopt MulticastLoop to off */ +void +ospf6_reset_mcastloop () +{ + u_int off = 0; + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + &off, sizeof (u_int)) < 0) + zlog_warn ("Network: reset IPV6_MULTICAST_LOOP failed: %s", + strerror (errno)); +} + +void +ospf6_set_pktinfo () +{ + u_int on = 1; +#ifdef IPV6_RECVPKTINFO /*2292bis-01*/ + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, + &on, sizeof (u_int)) < 0) + zlog_warn ("Network: set IPV6_RECVPKTINFO failed: %s", strerror (errno)); +#else /*RFC2292*/ + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_PKTINFO, + &on, sizeof (u_int)) < 0) + zlog_warn ("Network: set IPV6_PKTINFO failed: %s", strerror (errno)); +#endif +} + +void +ospf6_set_checksum () +{ + int offset = 12; +#ifndef DISABLE_IPV6_CHECKSUM + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_CHECKSUM, + &offset, sizeof (offset)) < 0) + zlog_warn ("Network: set IPV6_CHECKSUM failed: %s", strerror (errno)); +#else + zlog_warn ("Network: Don't set IPV6_CHECKSUM"); +#endif /* DISABLE_IPV6_CHECKSUM */ +} + +/* Make ospf6d's server socket. */ +int +ospf6_serv_sock () +{ + ospf6_sock = socket (AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP); + if (ospf6_sock < 0) + { + zlog_warn ("Network: can't create OSPF6 socket."); + return -1; + } + + /* set socket options */ +#if 1 + sockopt_reuseaddr (ospf6_sock); +#else + ospf6_set_reuseaddr (); +#endif /*1*/ + ospf6_reset_mcastloop (); + ospf6_set_pktinfo (); + ospf6_set_checksum (); + + /* setup global in6_addr, allspf6 and alldr6 for later use */ + inet_pton (AF_INET6, ALLSPFROUTERS6, &allspfrouters6); + inet_pton (AF_INET6, ALLDROUTERS6, &alldrouters6); + + return 0; +} + +void +ospf6_join_allspfrouters (u_int ifindex) +{ + struct ipv6_mreq mreq6; + int retval; + + assert (ifindex); + mreq6.ipv6mr_interface = ifindex; + memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6, + sizeof (struct in6_addr)); + + retval = setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq6, sizeof (mreq6)); + + if (retval < 0) + zlog_err ("Network: Join AllSPFRouters on ifindex %d failed: %s", + ifindex, strerror (errno)); +#if 0 + else + zlog_info ("Network: Join AllSPFRouters on ifindex %d", ifindex); +#endif +} + +void +ospf6_leave_allspfrouters (u_int ifindex) +{ + struct ipv6_mreq mreq6; + + assert (ifindex); + mreq6.ipv6mr_interface = ifindex; + memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6, + sizeof (struct in6_addr)); + + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + &mreq6, sizeof (mreq6)) < 0) + zlog_warn ("Network: Leave AllSPFRouters on ifindex %d Failed: %s", + ifindex, strerror (errno)); +#if 0 + else + zlog_info ("Network: Leave AllSPFRouters on ifindex %d", ifindex); +#endif +} + +void +ospf6_join_alldrouters (u_int ifindex) +{ + struct ipv6_mreq mreq6; + + assert (ifindex); + mreq6.ipv6mr_interface = ifindex; + memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6, + sizeof (struct in6_addr)); + + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq6, sizeof (mreq6)) < 0) + zlog_warn ("Network: Join AllDRouters on ifindex %d Failed: %s", + ifindex, strerror (errno)); +#if 0 + else + zlog_info ("Network: Join AllDRouters on ifindex %d", ifindex); +#endif +} + +void +ospf6_leave_alldrouters (u_int ifindex) +{ + struct ipv6_mreq mreq6; + + assert (ifindex); + mreq6.ipv6mr_interface = ifindex; + memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6, + sizeof (struct in6_addr)); + + if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + &mreq6, sizeof (mreq6)) < 0) + zlog_warn ("Network: Leave AllDRouters on ifindex %d Failed", ifindex); +#if 0 + else + zlog_info ("Network: Leave AllDRouters on ifindex %d", ifindex); +#endif +} + +int +iov_count (struct iovec *iov) +{ + int i; + for (i = 0; iov[i].iov_base; i++) + ; + return i; +} + +int +iov_totallen (struct iovec *iov) +{ + int i; + int totallen = 0; + for (i = 0; iov[i].iov_base; i++) + totallen += iov[i].iov_len; + return totallen; +} + +int +ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst, + unsigned int *ifindex, struct iovec *message) +{ + int retval; + struct msghdr smsghdr; + struct cmsghdr *scmsgp; + u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; + struct in6_pktinfo *pktinfo; + struct sockaddr_in6 dst_sin6; + + assert (dst); + assert (*ifindex); + + scmsgp = (struct cmsghdr *)cmsgbuf; + pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); + memset (&dst_sin6, 0, sizeof (struct sockaddr_in6)); + + /* source address */ + pktinfo->ipi6_ifindex = *ifindex; + if (src) + memcpy (&pktinfo->ipi6_addr, src, sizeof (struct in6_addr)); + else + memset (&pktinfo->ipi6_addr, 0, sizeof (struct in6_addr)); + + /* destination address */ + dst_sin6.sin6_family = AF_INET6; +#ifdef SIN6_LEN + dst_sin6.sin6_len = sizeof (struct sockaddr_in6); +#endif /*SIN6_LEN*/ + memcpy (&dst_sin6.sin6_addr, dst, sizeof (struct in6_addr)); +#ifdef HAVE_SIN6_SCOPE_ID + dst_sin6.sin6_scope_id = *ifindex; +#endif + + /* send control msg */ + scmsgp->cmsg_level = IPPROTO_IPV6; + scmsgp->cmsg_type = IPV6_PKTINFO; + scmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo)); + /* scmsgp = CMSG_NXTHDR (&smsghdr, scmsgp); */ + + /* send msg hdr */ + smsghdr.msg_iov = message; + smsghdr.msg_iovlen = iov_count (message); + smsghdr.msg_name = (caddr_t) &dst_sin6; + smsghdr.msg_namelen = sizeof (struct sockaddr_in6); + smsghdr.msg_control = (caddr_t) cmsgbuf; + smsghdr.msg_controllen = sizeof (cmsgbuf); + + retval = sendmsg (ospf6_sock, &smsghdr, 0); + if (retval != iov_totallen (message)) + zlog_warn ("sendmsg failed: ifindex: %d: %s (%d)", + *ifindex, strerror (errno), errno); + + return retval; +} + +int +ospf6_recvmsg (struct in6_addr *src, struct in6_addr *dst, + unsigned int *ifindex, struct iovec *message) +{ + int retval; + struct msghdr rmsghdr; + struct cmsghdr *rcmsgp; + u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; + struct in6_pktinfo *pktinfo; + struct sockaddr_in6 src_sin6; + + rcmsgp = (struct cmsghdr *)cmsgbuf; + pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp)); + memset (&src_sin6, 0, sizeof (struct sockaddr_in6)); + + /* receive control msg */ + rcmsgp->cmsg_level = IPPROTO_IPV6; + rcmsgp->cmsg_type = IPV6_PKTINFO; + rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo)); + /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */ + + /* receive msg hdr */ + rmsghdr.msg_iov = message; + rmsghdr.msg_iovlen = iov_count (message); + rmsghdr.msg_name = (caddr_t) &src_sin6; + rmsghdr.msg_namelen = sizeof (struct sockaddr_in6); + rmsghdr.msg_control = (caddr_t) cmsgbuf; + rmsghdr.msg_controllen = sizeof (cmsgbuf); + + retval = recvmsg (ospf6_sock, &rmsghdr, 0); + if (retval < 0) + zlog_warn ("recvmsg failed: %s", strerror (errno)); + else if (retval == iov_totallen (message)) + zlog_warn ("recvmsg read full buffer size: %d", retval); + + /* source address */ + assert (src); + memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr)); + + /* destination address */ + if (ifindex) + *ifindex = pktinfo->ipi6_ifindex; + if (dst) + memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr)); + + return retval; +} + + diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h new file mode 100644 index 0000000..9a4d795 --- /dev/null +++ b/ospf6d/ospf6_network.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_NETWORK_H +#define OSPF6_NETWORK_H + + + +extern int ospf6_sock; +extern struct in6_addr allspfrouters6; +extern struct in6_addr alldrouters6; + +/* Function Prototypes */ +void ospf6_set_reuseaddr (); +void ospf6_reset_mcastloop (); +void ospf6_set_pktinfo (); +void ospf6_set_checksum (); + +int ospf6_serv_sock (); + +void ospf6_join_allspfrouters (u_int); +void ospf6_leave_allspfrouters (u_int); +void ospf6_join_alldrouters (u_int); +void ospf6_leave_alldrouters (u_int); + +int ospf6_sendmsg (struct in6_addr *, struct in6_addr *, + unsigned int *, struct iovec *); +int ospf6_recvmsg (struct in6_addr *, struct in6_addr *, + unsigned int *, struct iovec *); + +#endif /* OSPF6_NETWORK_H */ + diff --git a/ospf6d/ospf6_proto.c b/ospf6d/ospf6_proto.c new file mode 100644 index 0000000..584382a --- /dev/null +++ b/ospf6d/ospf6_proto.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "log.h" + +#include "ospf6_proto.h" + +void +ospf6_prefix_apply_mask (struct ospf6_prefix *op) +{ + u_char *pnt, mask; + int index, offset; + + pnt = (u_char *)((caddr_t) op + sizeof (struct ospf6_prefix)); + index = op->prefix_length / 8; + offset = op->prefix_length % 8; + mask = 0xff << (8 - offset); + + if (index > 16) + { + zlog_warn ("Prefix length too long: %d", op->prefix_length); + return; + } + + if (index == 16) + return; + + pnt[index] &= mask; + index ++; + + while (index < OSPF6_PREFIX_SPACE (op->prefix_length)) + pnt[index++] = 0; +} + +void +ospf6_prefix_options_printbuf (u_int8_t prefix_options, char *buf, int size) +{ + snprintf (buf, size, "xxx"); +} + +void +ospf6_capability_printbuf (char capability, char *buf, int size) +{ + char w, v, e, b; + w = (capability & OSPF6_ROUTER_BIT_W ? 'W' : '-'); + v = (capability & OSPF6_ROUTER_BIT_V ? 'V' : '-'); + e = (capability & OSPF6_ROUTER_BIT_E ? 'E' : '-'); + b = (capability & OSPF6_ROUTER_BIT_B ? 'B' : '-'); + snprintf (buf, size, "----%c%c%c%c", w, v, e, b); +} + +void +ospf6_options_printbuf (u_char *options, char *buf, int size) +{ + char *dc, *r, *n, *mc, *e, *v6; + dc = (OSPF6_OPT_ISSET (options, OSPF6_OPT_DC) ? "DC" : "--"); + r = (OSPF6_OPT_ISSET (options, OSPF6_OPT_R) ? "R" : "-" ); + n = (OSPF6_OPT_ISSET (options, OSPF6_OPT_N) ? "N" : "-" ); + mc = (OSPF6_OPT_ISSET (options, OSPF6_OPT_MC) ? "MC" : "--"); + e = (OSPF6_OPT_ISSET (options, OSPF6_OPT_E) ? "E" : "-" ); + v6 = (OSPF6_OPT_ISSET (options, OSPF6_OPT_V6) ? "V6" : "--"); + snprintf (buf, size, "%s|%s|%s|%s|%s|%s", dc, r, n, mc, e, v6); +} + + diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h new file mode 100644 index 0000000..9fe821d --- /dev/null +++ b/ospf6d/ospf6_proto.h @@ -0,0 +1,122 @@ +/* + * Common protocol data and data structures. + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_PROTO_H +#define OSPF6_PROTO_H + +/* OSPF protocol version */ +#define OSPFV3_VERSION 3 + +/* OSPF protocol number. */ +#ifndef IPPROTO_OSPFIGP +#define IPPROTO_OSPFIGP 89 +#endif + +/* TOS field normaly null */ +#define DEFAULT_TOS_VALUE 0x0 + +/* Architectural Constants */ +#define LS_REFRESH_TIME 1800 /* 30 min */ +#define MIN_LS_INTERVAL 5 +#define MIN_LS_ARRIVAL 1 +#define MAXAGE 3600 /* 1 hour */ +#define CHECK_AGE 300 /* 5 min */ +#define MAX_AGE_DIFF 900 /* 15 min */ +#define LS_INFINITY 0xffffff /* 24-bit binary value */ +#define INITIAL_SEQUENCE_NUMBER 0x80000001 /* signed 32-bit integer */ +#define MAX_SEQUENCE_NUMBER 0x7fffffff /* signed 32-bit integer */ + +#define ALLSPFROUTERS6 "ff02::5" +#define ALLDROUTERS6 "ff02::6" + +/* Configurable Constants */ + +#define DEFAULT_HELLO_INTERVAL 10 +#define DEFAULT_ROUTER_DEAD_INTERVAL 40 + +#define OSPF6_ROUTER_BIT_W (1 << 3) +#define OSPF6_ROUTER_BIT_V (1 << 2) +#define OSPF6_ROUTER_BIT_E (1 << 1) +#define OSPF6_ROUTER_BIT_B (1 << 0) + +/* OSPF options */ +/* present in HELLO, DD, LSA */ +#define OSPF6_OPT_SET(x,opt) ((x)[2] |= (opt)) +#define OSPF6_OPT_ISSET(x,opt) ((x)[2] & (opt)) +#define OSPF6_OPT_CLEAR(x,opt) ((x)[2] &= ~(opt)) +#define OSPF6_OPT_CLEAR_ALL(x) ((x)[0] = (x)[1] = (x)[2] = 0) + +#define OSPF6_OPT_DC (1 << 5) /* Demand Circuit handling Capability */ +#define OSPF6_OPT_R (1 << 4) /* Forwarding Capability (Any Protocol) */ +#define OSPF6_OPT_N (1 << 3) /* Handling Type-7 LSA Capability */ +#define OSPF6_OPT_MC (1 << 2) /* Multicasting Capability */ +#define OSPF6_OPT_E (1 << 1) /* AS External Capability */ +#define OSPF6_OPT_V6 (1 << 0) /* IPv6 forwarding Capability */ + +/* OSPF6 Prefix */ +struct ospf6_prefix +{ + u_int8_t prefix_length; + u_int8_t prefix_options; + union { + u_int16_t _prefix_metric; + u_int16_t _prefix_referenced_lstype; + } u; +#define prefix_metric u._prefix_metric +#define prefix_refer_lstype u._prefix_referenced_lstype + /* followed by one address_prefix */ +}; + +#define OSPF6_PREFIX_OPTION_NU (1 << 0) /* No Unicast */ +#define OSPF6_PREFIX_OPTION_LA (1 << 1) /* Local Address */ +#define OSPF6_PREFIX_OPTION_MC (1 << 2) /* MultiCast */ +#define OSPF6_PREFIX_OPTION_P (1 << 3) /* Propagate (NSSA) */ + +/* caddr_t OSPF6_PREFIX_BODY (struct ospf6_prefix *); */ +#define OSPF6_PREFIX_BODY(x) ((caddr_t)(x) + sizeof (struct ospf6_prefix)) + +/* size_t OSPF6_PREFIX_SPACE (int prefixlength); */ +#define OSPF6_PREFIX_SPACE(x) ((((x) + 31) / 32) * 4) + +/* size_t OSPF6_PREFIX_SIZE (struct ospf6_prefix *); */ +#define OSPF6_PREFIX_SIZE(x) \ + (OSPF6_PREFIX_SPACE ((x)->prefix_length) + sizeof (struct ospf6_prefix)) + +/* struct ospf6_prefix *OSPF6_PREFIX_NEXT (struct ospf6_prefix *); */ +#define OSPF6_PREFIX_NEXT(x) \ + ((struct ospf6_prefix *)((caddr_t)(x) + OSPF6_PREFIX_SIZE (x))) + +#define ospf6_prefix_in6_addr(in6, op) \ +do { \ + memset (in6, 0, sizeof (struct in6_addr)); \ + memcpy (in6, (caddr_t) (op) + sizeof (struct ospf6_prefix), \ + OSPF6_PREFIX_SPACE ((op)->prefix_length)); \ +} while (0) + +void ospf6_prefix_apply_mask (struct ospf6_prefix *op); +void ospf6_prefix_options_printbuf (u_int8_t prefix_options, + char *buf, int size); +void ospf6_capability_printbuf (char capability, char *buf, int size); +void ospf6_options_printbuf (u_char *options, char *buf, int size); + +#endif /* OSPF6_PROTO_H */ + diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c new file mode 100644 index 0000000..7a5a394 --- /dev/null +++ b/ospf6d/ospf6_route.c @@ -0,0 +1,1240 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "memory.h" +#include "prefix.h" +#include "table.h" +#include "vty.h" +#include "command.h" + +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_route.h" +#include "ospf6d.h" + +unsigned char conf_debug_ospf6_route = 0; + +void +ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id, + struct prefix *prefix) +{ + memset (prefix, 0, sizeof (struct prefix)); + prefix->family = AF_INET6; + prefix->prefixlen = 64; + memcpy (&prefix->u.prefix6.s6_addr[0], &adv_router, 4); + memcpy (&prefix->u.prefix6.s6_addr[4], &id, 4); +} + +void +ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size) +{ + u_int32_t adv_router, id; + char adv_router_str[16], id_str[16]; + memcpy (&adv_router, &prefix->u.prefix6.s6_addr[0], 4); + memcpy (&id, &prefix->u.prefix6.s6_addr[4], 4); + inet_ntop (AF_INET, &adv_router, adv_router_str, sizeof (adv_router_str)); + inet_ntop (AF_INET, &id, id_str, sizeof (id_str)); + if (ntohl (id)) + snprintf (buf, size, "%s Net-ID: %s", adv_router_str, id_str); + else + snprintf (buf, size, "%s", adv_router_str); +} + +/* Global strings for logging */ +char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] = +{ "Unknown", "Router", "Network", "Discard", "Linkstate", "AddressRange", }; + +char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] = +{ "?", "R", "N", "D", "L", "A", }; + +char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] = +{ "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2", }; + +char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] = +{ "??", "IA", "IE", "E1", "E2", }; + + +struct ospf6_route * +ospf6_route_create () +{ + struct ospf6_route *route; + route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route)); + return route; +} + +void +ospf6_route_delete (struct ospf6_route *route) +{ + XFREE (MTYPE_OSPF6_ROUTE, route); +} + +struct ospf6_route * +ospf6_route_copy (struct ospf6_route *route) +{ + struct ospf6_route *new; + + new = ospf6_route_create (); + memcpy (new, route, sizeof (struct ospf6_route)); + new->rnode = NULL; + new->prev = NULL; + new->next = NULL; + new->lock = 0; + return new; +} + +void +ospf6_route_lock (struct ospf6_route *route) +{ + route->lock++; +} + +void +ospf6_route_unlock (struct ospf6_route *route) +{ + assert (route->lock > 0); + route->lock--; + if (route->lock == 0) + ospf6_route_delete (route); +} + +/* Route compare function. If ra is more preferred, it returns + less than 0. If rb is more preferred returns greater than 0. + Otherwise (neither one is preferred), returns 0 */ +static int +ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb) +{ + assert (ospf6_route_is_same (ra, rb)); + assert (OSPF6_PATH_TYPE_NONE < ra->path.type && + ra->path.type < OSPF6_PATH_TYPE_MAX); + assert (OSPF6_PATH_TYPE_NONE < rb->path.type && + rb->path.type < OSPF6_PATH_TYPE_MAX); + + if (ra->type != rb->type) + return (ra->type - rb->type); + + if (ra->path.area_id != rb->path.area_id) + return (ntohl (ra->path.area_id) - ntohl (rb->path.area_id)); + + if (ra->path.type != rb->path.type) + return (ra->path.type - rb->path.type); + + if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2) + { + if (ra->path.cost_e2 != rb->path.cost_e2) + return (ra->path.cost_e2 - rb->path.cost_e2); + } + else + { + if (ra->path.cost != rb->path.cost) + return (ra->path.cost - rb->path.cost); + } + + return 0; +} + +struct ospf6_route * +ospf6_route_lookup (struct prefix *prefix, + struct ospf6_route_table *table) +{ + struct route_node *node; + struct ospf6_route *route; + + node = route_node_lookup (table->table, prefix); + if (node == NULL) + return NULL; + + route = (struct ospf6_route *) node->info; + return route; +} + +struct ospf6_route * +ospf6_route_lookup_identical (struct ospf6_route *route, + struct ospf6_route_table *table) +{ + struct ospf6_route *target; + + for (target = ospf6_route_lookup (&route->prefix, table); + target; target = target->next) + { + if (ospf6_route_is_identical (target, route)) + return target; + } + return NULL; +} + +struct ospf6_route * +ospf6_route_lookup_bestmatch (struct prefix *prefix, + struct ospf6_route_table *table) +{ + struct route_node *node; + struct ospf6_route *route; + + node = route_node_match (table->table, prefix); + if (node == NULL) + return NULL; + route_unlock_node (node); + + route = (struct ospf6_route *) node->info; + return route; +} + +#ifndef NDEBUG +static void +_route_count_assert (struct ospf6_route_table *table) +{ + struct ospf6_route *debug; + char buf[64]; + int num = 0; + for (debug = ospf6_route_head (table); debug; + debug = ospf6_route_next (debug)) + num++; + + if (num == table->count) + return; + + zlog_info ("PANIC !! table[%p]->count = %d, real = %d", + table, table->count, num); + for (debug = ospf6_route_head (table); debug; + debug = ospf6_route_next (debug)) + { + prefix2str (&debug->prefix, buf, sizeof (buf)); + zlog_info ("%p %p %s", debug->prev, debug->next, buf); + } + zlog_info ("DUMP END"); + + assert (num == table->count); +} +#define ospf6_route_count_assert(t) (_route_count_assert (t)) +#else +#define ospf6_route_count_assert(t) ((void) 0) +#endif /*NDEBUG*/ + +struct ospf6_route * +ospf6_route_add (struct ospf6_route *route, + struct ospf6_route_table *table) +{ + struct route_node *node, *nextnode, *prevnode; + struct ospf6_route *current = NULL; + struct ospf6_route *prev = NULL, *old = NULL, *next = NULL; + char buf[64]; + struct timeval now; + + assert (route->rnode == NULL); + assert (route->lock == 0); + assert (route->next == NULL); + assert (route->prev == NULL); + + if (route->type == OSPF6_DEST_TYPE_LINKSTATE) + ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf)); + else + prefix2str (&route->prefix, buf, sizeof (buf)); + + if (IS_OSPF6_DEBUG_ROUTE (TABLE)) + zlog_info ("route add %s", buf); + + gettimeofday (&now, NULL); + + node = route_node_get (table->table, &route->prefix); + route->rnode = node; + + /* find place to insert */ + for (current = node->info; current; current = current->next) + { + if (! ospf6_route_is_same (current, route)) + next = current; + else if (current->type != route->type) + prev = current; + else if (ospf6_route_is_same_origin (current, route)) + old = current; + else if (ospf6_route_cmp (current, route) > 0) + next = current; + else + prev = current; + + if (old || next) + break; + } + + if (old) + { + /* if route does not actually change, return unchanged */ + if (ospf6_route_is_identical (old, route)) + { + if (IS_OSPF6_DEBUG_ROUTE (TABLE)) + zlog_info (" identical route found, ignore"); + + ospf6_route_delete (route); + SET_FLAG (old->flag, OSPF6_ROUTE_ADD); + ospf6_route_count_assert (table); + + return old; + } + + if (IS_OSPF6_DEBUG_ROUTE (TABLE)) + zlog_info (" old route found, replace"); + + /* replace old one if exists */ + if (node->info == old) + { + node->info = route; + SET_FLAG (route->flag, OSPF6_ROUTE_BEST); + } + + if (old->prev) + old->prev->next = route; + route->prev = old->prev; + if (old->next) + old->next->prev = route; + route->next = old->next; + + route->installed = old->installed; + route->changed = now; + + ospf6_route_unlock (old); /* will be deleted later */ + ospf6_route_lock (route); + + SET_FLAG (route->flag, OSPF6_ROUTE_CHANGE); + ospf6_route_count_assert (table); + + if (table->hook_add) + (*table->hook_add) (route); + + return route; + } + + /* insert if previous or next node found */ + if (prev || next) + { + if (IS_OSPF6_DEBUG_ROUTE (TABLE)) + zlog_info (" another path found, insert"); + + if (prev == NULL) + prev = next->prev; + if (next == NULL) + next = prev->next; + + if (prev) + prev->next = route; + route->prev = prev; + if (next) + next->prev = route; + route->next = next; + + if (node->info == next) + { + assert (next->rnode == node); + node->info = route; + UNSET_FLAG (next->flag, OSPF6_ROUTE_BEST); + SET_FLAG (route->flag, OSPF6_ROUTE_BEST); + } + + route->installed = now; + route->changed = now; + + ospf6_route_lock (route); + table->count++; + ospf6_route_count_assert (table); + + SET_FLAG (route->flag, OSPF6_ROUTE_ADD); + if (table->hook_add) + (*table->hook_add) (route); + + return route; + } + + /* Else, this is the brand new route regarding to the prefix */ + if (IS_OSPF6_DEBUG_ROUTE (TABLE)) + zlog_info (" brand new route, add"); + + assert (node->info == NULL); + node->info = route; + SET_FLAG (route->flag, OSPF6_ROUTE_BEST); + ospf6_route_lock (route); + route->installed = now; + route->changed = now; + + /* lookup real existing next route */ + nextnode = node; + route_lock_node (nextnode); + do { + nextnode = route_next (nextnode); + } while (nextnode && nextnode->info == NULL); + + /* set next link */ + if (nextnode == NULL) + route->next = NULL; + else + { + route_unlock_node (nextnode); + + next = nextnode->info; + route->next = next; + next->prev = route; + } + + /* lookup real existing prev route */ + prevnode = node; + route_lock_node (prevnode); + do { + prevnode = route_prev (prevnode); + } while (prevnode && prevnode->info == NULL); + + /* set prev link */ + if (prevnode == NULL) + route->prev = NULL; + else + { + route_unlock_node (prevnode); + + prev = prevnode->info; + while (prev->next && ospf6_route_is_same (prev, prev->next)) + prev = prev->next; + route->prev = prev; + prev->next = route; + } + + table->count++; + ospf6_route_count_assert (table); + + SET_FLAG (route->flag, OSPF6_ROUTE_ADD); + if (table->hook_add) + (*table->hook_add) (route); + + return route; +} + +void +ospf6_route_remove (struct ospf6_route *route, + struct ospf6_route_table *table) +{ + struct route_node *node; + struct ospf6_route *current; + char buf[64]; + + if (route->type == OSPF6_DEST_TYPE_LINKSTATE) + ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf)); + else + prefix2str (&route->prefix, buf, sizeof (buf)); + + if (IS_OSPF6_DEBUG_ROUTE (TABLE)) + zlog_info ("route remove: %s", buf); + + node = route_node_lookup (table->table, &route->prefix); + assert (node); + + /* find the route to remove, making sure that the route pointer + is from the route table. */ + current = node->info; + while (current && ospf6_route_is_same (current, route)) + { + if (current == route) + break; + current = current->next; + } + assert (current == route); + + /* adjust doubly linked list */ + if (route->prev) + route->prev->next = route->next; + if (route->next) + route->next->prev = route->prev; + + if (node->info == route) + { + if (route->next && ospf6_route_is_same (route->next, route)) + { + node->info = route->next; + SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST); + } + else + node->info = NULL; /* should unlock route_node here ? */ + } + + table->count--; + ospf6_route_count_assert (table); + + SET_FLAG (route->flag, OSPF6_ROUTE_WAS_REMOVED); + + if (table->hook_remove) + (*table->hook_remove) (route); + + ospf6_route_unlock (route); +} + +struct ospf6_route * +ospf6_route_head (struct ospf6_route_table *table) +{ + struct route_node *node; + struct ospf6_route *route; + + node = route_top (table->table); + if (node == NULL) + return NULL; + + /* skip to the real existing entry */ + while (node && node->info == NULL) + node = route_next (node); + if (node == NULL) + return NULL; + + route_unlock_node (node); + assert (node->info); + + route = (struct ospf6_route *) node->info; + assert (route->prev == NULL); + ospf6_route_lock (route); + return route; +} + +struct ospf6_route * +ospf6_route_next (struct ospf6_route *route) +{ + struct ospf6_route *next = route->next; + + ospf6_route_unlock (route); + if (next) + ospf6_route_lock (next); + + return next; +} + +struct ospf6_route * +ospf6_route_best_next (struct ospf6_route *route) +{ + struct route_node *rnode; + struct ospf6_route *next; + + rnode = route->rnode; + route_lock_node (rnode); + rnode = route_next (rnode); + while (rnode && rnode->info == NULL) + rnode = route_next (rnode); + if (rnode == NULL) + return NULL; + route_unlock_node (rnode); + + assert (rnode->info); + next = (struct ospf6_route *) rnode->info; + ospf6_route_unlock (route); + ospf6_route_lock (next); + return next; +} + +/* Macro version of check_bit (). */ +#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1) + +struct ospf6_route * +ospf6_route_match_head (struct prefix *prefix, + struct ospf6_route_table *table) +{ + struct route_node *node; + struct ospf6_route *route; + + /* Walk down tree. */ + node = table->table->top; + while (node && node->p.prefixlen < prefix->prefixlen && + prefix_match (&node->p, prefix)) + node = node->link[CHECK_BIT(&prefix->u.prefix, node->p.prefixlen)]; + + if (node) + route_lock_node (node); + while (node && node->info == NULL) + node = route_next (node); + if (node == NULL) + return NULL; + route_unlock_node (node); + + if (! prefix_match (prefix, &node->p)) + return NULL; + + route = node->info; + ospf6_route_lock (route); + return route; +} + +struct ospf6_route * +ospf6_route_match_next (struct prefix *prefix, + struct ospf6_route *route) +{ + struct ospf6_route *next; + + next = ospf6_route_next (route); + if (next && ! prefix_match (prefix, &next->prefix)) + { + ospf6_route_unlock (next); + next = NULL; + } + + return next; +} + +void +ospf6_route_remove_all (struct ospf6_route_table *table) +{ + struct ospf6_route *route; + for (route = ospf6_route_head (table); route; + route = ospf6_route_next (route)) + ospf6_route_remove (route, table); +} + +struct ospf6_route_table * +ospf6_route_table_create () +{ + struct ospf6_route_table *new; + new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table)); + new->table = route_table_init (); + return new; +} + +void +ospf6_route_table_delete (struct ospf6_route_table *table) +{ + ospf6_route_remove_all (table); + route_table_finish (table->table); + XFREE (MTYPE_OSPF6_ROUTE, table); +} + + + +/* VTY commands */ +void +ospf6_route_show (struct vty *vty, struct ospf6_route *route) +{ + int i; + char destination[64], nexthop[64]; + char duration[16], ifname[IFNAMSIZ]; + struct timeval now, res; + + gettimeofday (&now, (struct timezone *) NULL); + timersub (&now, &route->changed, &res); + timerstring (&res, duration, sizeof (duration)); + + /* destination */ + if (route->type == OSPF6_DEST_TYPE_LINKSTATE) + ospf6_linkstate_prefix2str (&route->prefix, destination, + sizeof (destination)); + else if (route->type == OSPF6_DEST_TYPE_ROUTER) + inet_ntop (route->prefix.family, &route->prefix.u.prefix, + destination, sizeof (destination)); + else + prefix2str (&route->prefix, destination, sizeof (destination)); + + /* nexthop */ + inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop, + sizeof (nexthop)); + if (! if_indextoname (route->nexthop[0].ifindex, ifname)) + snprintf (ifname, sizeof (ifname), "%d", route->nexthop[0].ifindex); + + vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s", + (ospf6_route_is_best (route) ? '*' : ' '), + OSPF6_DEST_TYPE_SUBSTR (route->type), + OSPF6_PATH_TYPE_SUBSTR (route->path.type), + destination, nexthop, ifname, duration, VNL); + + for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) && + i < OSPF6_MULTI_PATH_LIMIT; i++) + { + /* nexthop */ + inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, + sizeof (nexthop)); + if (! if_indextoname (route->nexthop[i].ifindex, ifname)) + snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex); + + vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s", + ' ', "", "", "", nexthop, ifname, "", VNL); + } +} + +void +ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route) +{ + char destination[64], nexthop[64], ifname[IFNAMSIZ]; + char area_id[16], id[16], adv_router[16], capa[16], options[16]; + struct timeval now, res; + char duration[16]; + int i; + + gettimeofday (&now, (struct timezone *) NULL); + + /* destination */ + if (route->type == OSPF6_DEST_TYPE_LINKSTATE) + ospf6_linkstate_prefix2str (&route->prefix, destination, + sizeof (destination)); + else if (route->type == OSPF6_DEST_TYPE_ROUTER) + inet_ntop (route->prefix.family, &route->prefix.u.prefix, + destination, sizeof (destination)); + else + prefix2str (&route->prefix, destination, sizeof (destination)); + vty_out (vty, "Destination: %s%s", destination, VNL); + + /* destination type */ + vty_out (vty, "Destination type: %s%s", + OSPF6_DEST_TYPE_NAME (route->type), + VNL); + + /* Time */ + timersub (&now, &route->installed, &res); + timerstring (&res, duration, sizeof (duration)); + vty_out (vty, "Installed Time: %s ago%s", duration, VNL); + + timersub (&now, &route->changed, &res); + timerstring (&res, duration, sizeof (duration)); + vty_out (vty, " Changed Time: %s ago%s", duration, VNL); + + /* Debugging info */ + vty_out (vty, "Lock: %d Flags: %s%s%s%s%s", route->lock, + (CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"), + (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"), + (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"), + (CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"), + VNL); + vty_out (vty, "Memory: prev: %p this: %p next: %p%s", + route->prev, route, route->next, VNL); + + /* Path section */ + + /* Area-ID */ + inet_ntop (AF_INET, &route->path.area_id, area_id, sizeof (area_id)); + vty_out (vty, "Associated Area: %s%s", area_id, VNL); + + /* Path type */ + vty_out (vty, "Path Type: %s%s", + OSPF6_PATH_TYPE_NAME (route->path.type), VNL); + + /* LS Origin */ + inet_ntop (AF_INET, &route->path.origin.id, id, sizeof (id)); + inet_ntop (AF_INET, &route->path.origin.adv_router, adv_router, + sizeof (adv_router)); + vty_out (vty, "LS Origin: %s Id: %s Adv: %s%s", + ospf6_lstype_name (route->path.origin.type), + id, adv_router, VNL); + + /* Options */ + ospf6_options_printbuf (route->path.options, options, sizeof (options)); + vty_out (vty, "Options: %s%s", options, VNL); + + /* Router Bits */ + ospf6_capability_printbuf (route->path.router_bits, capa, sizeof (capa)); + vty_out (vty, "Router Bits: %s%s", capa, VNL); + + /* Prefix Options */ + vty_out (vty, "Prefix Options: xxx%s", VNL); + + /* Metrics */ + vty_out (vty, "Metric Type: %d%s", route->path.metric_type, + VNL); + vty_out (vty, "Metric: %d (%d)%s", + route->path.cost, route->path.cost_e2, VNL); + + /* Nexthops */ + vty_out (vty, "Nexthop:%s", VNL); + for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) && + i < OSPF6_MULTI_PATH_LIMIT; i++) + { + /* nexthop */ + inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, + sizeof (nexthop)); + if (! if_indextoname (route->nexthop[i].ifindex, ifname)) + snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex); + vty_out (vty, " %s %s%s", nexthop, ifname, VNL); + } + vty_out (vty, "%s", VNL); +} + +void +ospf6_route_show_table_summary (struct vty *vty, + struct ospf6_route_table *table) +{ + struct ospf6_route *route, *prev = NULL; + int i, pathtype[OSPF6_PATH_TYPE_MAX]; + int number = 0; + int nhinval = 0, ecmp = 0; + int alternative = 0, destination = 0; + + for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++) + pathtype[i] = 0; + + for (route = ospf6_route_head (table); route; + route = ospf6_route_next (route)) + { + if (prev == NULL || ! ospf6_route_is_same (prev, route)) + destination++; + else + alternative++; + if (! ospf6_nexthop_is_set (&route->nexthop[0])) + nhinval++; + else if (ospf6_nexthop_is_set (&route->nexthop[1])) + ecmp++; + pathtype[route->path.type]++; + number++; + + prev = route; + } + + assert (number == table->count); + + vty_out (vty, "Number of OSPFv3 routes: %d%s", number, VNL); + vty_out (vty, "Number of Destination: %d%s", destination, VNL); + vty_out (vty, "Number of Alternative routes: %d%s", alternative, VNL); + vty_out (vty, "Number of Equal Cost Multi Path: %d%s", ecmp, VNL); + for (i = OSPF6_PATH_TYPE_INTRA; i <= OSPF6_PATH_TYPE_EXTERNAL2; i++) + { + vty_out (vty, "Number of %s routes: %d%s", + OSPF6_PATH_TYPE_NAME (i), pathtype[i], VNL); + } +} + +void +ospf6_route_show_table_prefix (struct vty *vty, + struct prefix *prefix, + struct ospf6_route_table *table) +{ + struct ospf6_route *route; + + route = ospf6_route_lookup (prefix, table); + if (route == NULL) + return; + + ospf6_route_lock (route); + while (route && ospf6_route_is_prefix (prefix, route)) + { + /* Specifying a prefix will always display details */ + ospf6_route_show_detail (vty, route); + route = ospf6_route_next (route); + } + if (route) + ospf6_route_unlock (route); +} + +void +ospf6_route_show_table_address (struct vty *vty, + struct prefix *prefix, + struct ospf6_route_table *table) +{ + struct ospf6_route *route; + + route = ospf6_route_lookup_bestmatch (prefix, table); + if (route == NULL) + return; + + prefix = &route->prefix; + ospf6_route_lock (route); + while (route && ospf6_route_is_prefix (prefix, route)) + { + /* Specifying a prefix will always display details */ + ospf6_route_show_detail (vty, route); + route = ospf6_route_next (route); + } + if (route) + ospf6_route_unlock (route); +} + +void +ospf6_route_show_table_match (struct vty *vty, int detail, + struct prefix *prefix, + struct ospf6_route_table *table) +{ + struct ospf6_route *route; + assert (prefix->family); + + route = ospf6_route_match_head (prefix, table); + while (route) + { + if (detail) + ospf6_route_show_detail (vty, route); + else + ospf6_route_show (vty, route); + route = ospf6_route_match_next (prefix, route); + } +} + +void +ospf6_route_show_table_type (struct vty *vty, int detail, u_char type, + struct ospf6_route_table *table) +{ + struct ospf6_route *route; + + route = ospf6_route_head (table); + while (route) + { + if (route->path.type == type) + { + if (detail) + ospf6_route_show_detail (vty, route); + else + ospf6_route_show (vty, route); + } + route = ospf6_route_next (route); + } +} + +void +ospf6_route_show_table (struct vty *vty, int detail, + struct ospf6_route_table *table) +{ + struct ospf6_route *route; + + route = ospf6_route_head (table); + while (route) + { + if (detail) + ospf6_route_show_detail (vty, route); + else + ospf6_route_show (vty, route); + route = ospf6_route_next (route); + } +} + +int +ospf6_route_table_show (struct vty *vty, int argc, char **argv, + struct ospf6_route_table *table) +{ + int summary = 0; + int match = 0; + int detail = 0; + int slash = 0; + int isprefix = 0; + int i, ret; + struct prefix prefix; + u_char type = 0; + + memset (&prefix, 0, sizeof (struct prefix)); + + for (i = 0; i < argc; i++) + { + if (! strcmp (argv[i], "summary")) + { + summary++; + continue; + } + + if (! strcmp (argv[i], "intra-area")) + { + type = OSPF6_PATH_TYPE_INTRA; + continue; + } + + if (! strcmp (argv[i], "inter-area")) + { + type = OSPF6_PATH_TYPE_INTER; + continue; + } + + if (! strcmp (argv[i], "external-1")) + { + type = OSPF6_PATH_TYPE_EXTERNAL1; + continue; + } + + if (! strcmp (argv[i], "external-2")) + { + type = OSPF6_PATH_TYPE_EXTERNAL2; + continue; + } + + if (! strcmp (argv[i], "detail")) + { + detail++; + continue; + } + + if (! strcmp (argv[i], "match")) + { + match++; + continue; + } + + ret = str2prefix (argv[i], &prefix); + if (ret == 1 && prefix.family == AF_INET6) + { + isprefix++; + if (strchr (argv[i], '/')) + slash++; + continue; + } + + vty_out (vty, "Malformed argument: %s%s", argv[i], VNL); + return CMD_SUCCESS; + } + + /* Give summary of this route table */ + if (summary) + { + ospf6_route_show_table_summary (vty, table); + return CMD_SUCCESS; + } + + /* Give exact prefix-match route */ + if (isprefix && ! match) + { + /* If exact address, give best matching route */ + if (! slash) + ospf6_route_show_table_address (vty, &prefix, table); + else + ospf6_route_show_table_prefix (vty, &prefix, table); + + return CMD_SUCCESS; + } + + if (match) + ospf6_route_show_table_match (vty, detail, &prefix, table); + else if (type) + ospf6_route_show_table_type (vty, detail, type, table); + else + ospf6_route_show_table (vty, detail, table); + + return CMD_SUCCESS; +} + +void +ospf6_linkstate_show_header (struct vty *vty) +{ + vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %s%s", + "Type", "Router-ID", "Net-ID", "Rtr-Bits", "Options", "Cost", VNL); +} + +void +ospf6_linkstate_show (struct vty *vty, struct ospf6_route *route) +{ + u_int32_t router, id; + char routername[16], idname[16], rbits[16], options[16]; + + router = ospf6_linkstate_prefix_adv_router (&route->prefix); + inet_ntop (AF_INET, &router, routername, sizeof (routername)); + id = ospf6_linkstate_prefix_id (&route->prefix); + inet_ntop (AF_INET, &id, idname, sizeof (idname)); + + ospf6_capability_printbuf (route->path.router_bits, rbits, sizeof (rbits)); + ospf6_options_printbuf (route->path.options, options, sizeof (options)); + + if (ntohl (id)) + vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %lu%s", + "Network", routername, idname, rbits, options, + (unsigned long) route->path.cost, VNL); + else + vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %lu%s", + "Router", routername, idname, rbits, options, + (unsigned long) route->path.cost, VNL); +} + + +void +ospf6_linkstate_show_table_exact (struct vty *vty, + struct prefix *prefix, + struct ospf6_route_table *table) +{ + struct ospf6_route *route; + + route = ospf6_route_lookup (prefix, table); + if (route == NULL) + return; + + ospf6_route_lock (route); + while (route && ospf6_route_is_prefix (prefix, route)) + { + /* Specifying a prefix will always display details */ + ospf6_route_show_detail (vty, route); + route = ospf6_route_next (route); + } + if (route) + ospf6_route_unlock (route); +} + +void +ospf6_linkstate_show_table (struct vty *vty, int detail, + struct ospf6_route_table *table) +{ + struct ospf6_route *route; + + if (! detail) + ospf6_linkstate_show_header (vty); + + route = ospf6_route_head (table); + while (route) + { + if (detail) + ospf6_route_show_detail (vty, route); + else + ospf6_linkstate_show (vty, route); + route = ospf6_route_next (route); + } +} + +int +ospf6_linkstate_table_show (struct vty *vty, int argc, char **argv, + struct ospf6_route_table *table) +{ + int detail = 0; + int is_id = 0; + int is_router = 0; + int i, ret; + struct prefix router, id, prefix; + + memset (&router, 0, sizeof (struct prefix)); + memset (&id, 0, sizeof (struct prefix)); + memset (&prefix, 0, sizeof (struct prefix)); + + for (i = 0; i < argc; i++) + { + if (! strcmp (argv[i], "detail")) + { + detail++; + continue; + } + + if (! is_router) + { + ret = str2prefix (argv[i], &router); + if (ret == 1 && router.family == AF_INET) + { + is_router++; + continue; + } + vty_out (vty, "Malformed argument: %s%s", argv[i], VNL); + return CMD_SUCCESS; + } + + if (! is_id) + { + ret = str2prefix (argv[i], &id); + if (ret == 1 && id.family == AF_INET) + { + is_id++; + continue; + } + vty_out (vty, "Malformed argument: %s%s", argv[i], VNL); + return CMD_SUCCESS; + } + + vty_out (vty, "Malformed argument: %s%s", argv[i], VNL); + return CMD_SUCCESS; + } + + if (is_router) + ospf6_linkstate_prefix (router.u.prefix4.s_addr, + id.u.prefix4.s_addr, &prefix); + + if (prefix.family) + ospf6_linkstate_show_table_exact (vty, &prefix, table); + else + ospf6_linkstate_show_table (vty, detail, table); + + return CMD_SUCCESS; +} + + +void +ospf6_brouter_show_header (struct vty *vty) +{ + vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s", + "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area", VNL); +} + +void +ospf6_brouter_show (struct vty *vty, struct ospf6_route *route) +{ + u_int32_t adv_router; + char adv[16], rbits[16], options[16], area[16]; + + adv_router = ospf6_linkstate_prefix_adv_router (&route->prefix); + inet_ntop (AF_INET, &adv_router, adv, sizeof (adv)); + ospf6_capability_printbuf (route->path.router_bits, rbits, sizeof (rbits)); + ospf6_options_printbuf (route->path.options, options, sizeof (options)); + inet_ntop (AF_INET, &route->path.area_id, area, sizeof (area)); + + /* vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s", + "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area", VNL); */ + vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s", + adv, rbits, options, OSPF6_PATH_TYPE_NAME (route->path.type), + area, VNL); +} + +DEFUN (debug_ospf6_route, + debug_ospf6_route_cmd, + "debug ospf6 route (table|intra-area|inter-area)", + DEBUG_STR + OSPF6_STR + "Debug route table calculation\n" + "Debug detail\n" + "Debug intra-area route calculation\n" + "Debug inter-area route calculation\n" + ) +{ + unsigned char level = 0; + + if (! strncmp (argv[0], "table", 5)) + level = OSPF6_DEBUG_ROUTE_TABLE; + else if (! strncmp (argv[0], "intra", 5)) + level = OSPF6_DEBUG_ROUTE_INTRA; + else if (! strncmp (argv[0], "inter", 5)) + level = OSPF6_DEBUG_ROUTE_INTER; + OSPF6_DEBUG_ROUTE_ON (level); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf6_route, + no_debug_ospf6_route_cmd, + "no debug ospf6 route (table|intra-area|inter-area)", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug route table calculation\n" + "Debug intra-area route calculation\n") +{ + unsigned char level = 0; + + if (! strncmp (argv[0], "table", 5)) + level = OSPF6_DEBUG_ROUTE_TABLE; + else if (! strncmp (argv[0], "intra", 5)) + level = OSPF6_DEBUG_ROUTE_INTRA; + else if (! strncmp (argv[0], "inter", 5)) + level = OSPF6_DEBUG_ROUTE_INTER; + OSPF6_DEBUG_ROUTE_OFF (level); + return CMD_SUCCESS; +} + +int +config_write_ospf6_debug_route (struct vty *vty) +{ + if (IS_OSPF6_DEBUG_ROUTE (TABLE)) + vty_out (vty, "debug ospf6 route table%s", VNL); + if (IS_OSPF6_DEBUG_ROUTE (INTRA)) + vty_out (vty, "debug ospf6 route intra-area%s", VNL); + if (IS_OSPF6_DEBUG_ROUTE (INTER)) + vty_out (vty, "debug ospf6 route inter-area%s", VNL); + return 0; +} + +void +install_element_ospf6_debug_route () +{ + install_element (ENABLE_NODE, &debug_ospf6_route_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd); + install_element (CONFIG_NODE, &debug_ospf6_route_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd); +} + + + diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h new file mode 100644 index 0000000..d9456a1 --- /dev/null +++ b/ospf6d/ospf6_route.h @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_ROUTE_H +#define OSPF6_ROUTE_H + +#define OSPF6_MULTI_PATH_LIMIT 4 + +/* Debug option */ +extern unsigned char conf_debug_ospf6_route; +#define OSPF6_DEBUG_ROUTE_TABLE 0x01 +#define OSPF6_DEBUG_ROUTE_INTRA 0x02 +#define OSPF6_DEBUG_ROUTE_INTER 0x04 +#define OSPF6_DEBUG_ROUTE_ON(level) \ + (conf_debug_ospf6_route |= (level)) +#define OSPF6_DEBUG_ROUTE_OFF(level) \ + (conf_debug_ospf6_route &= ~(level)) +#define IS_OSPF6_DEBUG_ROUTE(e) \ + (conf_debug_ospf6_route & OSPF6_DEBUG_ROUTE_ ## e) + +/* Nexthop */ +struct ospf6_nexthop +{ + /* Interface index */ + unsigned int ifindex; + + /* IP address, if any */ + struct in6_addr address; +}; + +#define ospf6_nexthop_is_set(x) \ + ((x)->ifindex || ! IN6_IS_ADDR_UNSPECIFIED (&(x)->address)) +#define ospf6_nexthop_is_same(a,b) \ + ((a)->ifindex == (b)->ifindex && \ + IN6_ARE_ADDR_EQUAL (&(a)->address, &(b)->address)) +#define ospf6_nexthop_clear(x) \ + do { \ + (x)->ifindex = 0; \ + memset (&(x)->address, 0, sizeof (struct in6_addr)); \ + } while (0) +#define ospf6_nexthop_copy(a, b) \ + do { \ + (a)->ifindex = (b)->ifindex; \ + memcpy (&(a)->address, &(b)->address, \ + sizeof (struct in6_addr)); \ + } while (0) + +/* Path */ +struct ospf6_ls_origin +{ + u_int16_t type; + u_int32_t id; + u_int32_t adv_router; +}; + +struct ospf6_path +{ + /* Link State Origin */ + struct ospf6_ls_origin origin; + + /* Router bits */ + u_char router_bits; + + /* Optional Capabilities */ + u_char options[3]; + + /* Prefix Options */ + u_char prefix_options; + + /* Associated Area */ + u_int32_t area_id; + + /* Path-type */ + u_char type; + u_char subtype; /* only used for redistribute i.e ZEBRA_ROUTE_XXX */ + + /* Cost */ + u_int8_t metric_type; + u_int32_t cost; + u_int32_t cost_e2; +}; + +#define OSPF6_PATH_TYPE_NONE 0 +#define OSPF6_PATH_TYPE_INTRA 1 +#define OSPF6_PATH_TYPE_INTER 2 +#define OSPF6_PATH_TYPE_EXTERNAL1 3 +#define OSPF6_PATH_TYPE_EXTERNAL2 4 +#define OSPF6_PATH_TYPE_REDISTRIBUTE 5 +#define OSPF6_PATH_TYPE_MAX 6 + +#include "prefix.h" +#include "table.h" + +struct ospf6_route +{ + struct route_node *rnode; + + struct ospf6_route *prev; + struct ospf6_route *next; + + unsigned int lock; + + /* Destination Type */ + u_char type; + + /* Destination ID */ + struct prefix prefix; + + /* Time */ + struct timeval installed; + struct timeval changed; + + /* flag */ + u_char flag; + + /* path */ + struct ospf6_path path; + + /* nexthop */ + struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT]; + + /* route option */ + void *route_option; + + /* link state id for advertising */ + u_int32_t linkstate_id; +}; + +#define OSPF6_DEST_TYPE_NONE 0 +#define OSPF6_DEST_TYPE_ROUTER 1 +#define OSPF6_DEST_TYPE_NETWORK 2 +#define OSPF6_DEST_TYPE_DISCARD 3 +#define OSPF6_DEST_TYPE_LINKSTATE 4 +#define OSPF6_DEST_TYPE_RANGE 5 +#define OSPF6_DEST_TYPE_MAX 6 + +#define OSPF6_ROUTE_CHANGE 0x01 +#define OSPF6_ROUTE_ADD 0x02 +#define OSPF6_ROUTE_REMOVE 0x04 +#define OSPF6_ROUTE_BEST 0x08 +#define OSPF6_ROUTE_ACTIVE_SUMMARY 0x10 +#define OSPF6_ROUTE_DO_NOT_ADVERTISE 0x20 +#define OSPF6_ROUTE_WAS_REMOVED 0x40 + +struct ospf6_route_table +{ + /* patricia tree */ + struct route_table *table; + + u_int32_t count; + + /* hooks */ + void (*hook_add) (struct ospf6_route *); + void (*hook_change) (struct ospf6_route *); + void (*hook_remove) (struct ospf6_route *); +}; + +extern char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX]; +extern char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX]; +#define OSPF6_DEST_TYPE_NAME(x) \ + (0 < (x) && (x) < OSPF6_DEST_TYPE_MAX ? \ + ospf6_dest_type_str[(x)] : ospf6_dest_type_str[0]) +#define OSPF6_DEST_TYPE_SUBSTR(x) \ + (0 < (x) && (x) < OSPF6_DEST_TYPE_MAX ? \ + ospf6_dest_type_substr[(x)] : ospf6_dest_type_substr[0]) + +extern char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX]; +extern char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX]; +#define OSPF6_PATH_TYPE_NAME(x) \ + (0 < (x) && (x) < OSPF6_PATH_TYPE_MAX ? \ + ospf6_path_type_str[(x)] : ospf6_path_type_str[0]) +#define OSPF6_PATH_TYPE_SUBSTR(x) \ + (0 < (x) && (x) < OSPF6_PATH_TYPE_MAX ? \ + ospf6_path_type_substr[(x)] : ospf6_path_type_substr[0]) + +#define OSPF6_ROUTE_ADDRESS_STR "Display the route bestmatches the address\n" +#define OSPF6_ROUTE_PREFIX_STR "Display the route\n" +#define OSPF6_ROUTE_MATCH_STR "Display the route matches the prefix\n" + +#define ospf6_route_is_prefix(p, r) \ + (memcmp (p, &(r)->prefix, sizeof (struct prefix)) == 0) +#define ospf6_route_is_same(ra, rb) \ + (prefix_same (&(ra)->prefix, &(rb)->prefix)) +#define ospf6_route_is_same_origin(ra, rb) \ + ((ra)->path.area_id == (rb)->path.area_id && \ + memcmp (&(ra)->path.origin, &(rb)->path.origin, \ + sizeof (struct ospf6_ls_origin)) == 0) +#define ospf6_route_is_identical(ra, rb) \ + ((ra)->type == (rb)->type && \ + memcmp (&(ra)->prefix, &(rb)->prefix, sizeof (struct prefix)) == 0 && \ + memcmp (&(ra)->path, &(rb)->path, sizeof (struct ospf6_path)) == 0 && \ + memcmp (&(ra)->nexthop, &(rb)->nexthop, \ + sizeof (struct ospf6_nexthop) * OSPF6_MULTI_PATH_LIMIT) == 0) +#define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST)) + +#define ospf6_linkstate_prefix_adv_router(x) \ + (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[0])) +#define ospf6_linkstate_prefix_id(x) \ + (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[4])) + +#define ADV_ROUTER_IN_PREFIX(x) \ + (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[0])) +#define ID_IN_PREFIX(x) \ + (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[4])) + +/* Function prototype */ +void ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id, + struct prefix *prefix); +void ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size); + +struct ospf6_route *ospf6_route_create (); +void ospf6_route_delete (struct ospf6_route *); +struct ospf6_route *ospf6_route_copy (struct ospf6_route *route); + +void ospf6_route_lock (struct ospf6_route *route); +void ospf6_route_unlock (struct ospf6_route *route); + +struct ospf6_route * +ospf6_route_lookup (struct prefix *prefix, + struct ospf6_route_table *table); +struct ospf6_route * +ospf6_route_lookup_identical (struct ospf6_route *route, + struct ospf6_route_table *table); +struct ospf6_route * +ospf6_route_lookup_bestmatch (struct prefix *prefix, + struct ospf6_route_table *table); + +struct ospf6_route * +ospf6_route_add (struct ospf6_route *route, struct ospf6_route_table *table); +void +ospf6_route_remove (struct ospf6_route *route, struct ospf6_route_table *table); + +struct ospf6_route *ospf6_route_head (struct ospf6_route_table *table); +struct ospf6_route *ospf6_route_next (struct ospf6_route *route); +struct ospf6_route *ospf6_route_best_next (struct ospf6_route *route); + +struct ospf6_route *ospf6_route_match_head (struct prefix *prefix, + struct ospf6_route_table *table); +struct ospf6_route *ospf6_route_match_next (struct prefix *prefix, + struct ospf6_route *route); + +void ospf6_route_remove_all (struct ospf6_route_table *); +struct ospf6_route_table *ospf6_route_table_create (); +void ospf6_route_table_delete (struct ospf6_route_table *); +void ospf6_route_dump (struct ospf6_route_table *table); + + +void ospf6_route_show (struct vty *vty, struct ospf6_route *route); +void ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route); + +int ospf6_route_table_show (struct vty *, int, char **, + struct ospf6_route_table *); +int ospf6_linkstate_table_show (struct vty *vty, int argc, char **argv, + struct ospf6_route_table *table); + +void ospf6_brouter_show_header (struct vty *vty); +void ospf6_brouter_show (struct vty *vty, struct ospf6_route *route); + +int config_write_ospf6_debug_route (struct vty *vty); +void install_element_ospf6_debug_route (); +void ospf6_route_init (); + +#endif /* OSPF6_ROUTE_H */ + diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c new file mode 100644 index 0000000..d5f7850 --- /dev/null +++ b/ospf6d/ospf6_snmp.c @@ -0,0 +1,538 @@ +/* OSPFv3 SNMP support + * Copyright (C) 2004 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#ifdef HAVE_SNMP + +#ifdef HAVE_NETSNMP +#include +#endif /*HAVE_NETSNMP*/ + +#include +#include +#include + +#include "log.h" +#include "vty.h" +#include "linklist.h" +#include "smux.h" + +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_route.h" +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_message.h" +#include "ospf6_neighbor.h" +#include "ospf6d.h" + +/* OSPFv3-MIB */ +#define OSPFv3MIB 1,3,6,1,3,102 + +/* Zebra enterprise ospf6d MIB */ +#define OSPF6DOID 1,3,6,1,4,1,3317,1,2,6 + +/* OSPFv3 MIB General Group values. */ +#define OSPFv3ROUTERID 1 +#define OSPFv3ADMINSTAT 2 +#define OSPFv3VERSIONNUMBER 3 +#define OSPFv3AREABDRRTRSTATUS 4 +#define OSPFv3ASBDRRTRSTATUS 5 +#define OSPFv3ASSCOPELSACOUNT 6 +#define OSPFv3ASSCOPELSACHECKSUMSUM 7 +#define OSPFv3ORIGINATENEWLSAS 8 +#define OSPFv3RXNEWLSAS 9 +#define OSPFv3EXTLSACOUNT 10 +#define OSPFv3EXTAREALSDBLIMIT 11 +#define OSPFv3MULTICASTEXTENSIONS 12 +#define OSPFv3EXITOVERFLOWINTERVAL 13 +#define OSPFv3DEMANDEXTENSIONS 14 +#define OSPFv3TRAFFICENGINEERINGSUPPORT 15 +#define OSPFv3REFERENCEBANDWIDTH 16 +#define OSPFv3RESTARTSUPPORT 17 +#define OSPFv3RESTARTINTERVAL 18 +#define OSPFv3RESTARTSTATUS 19 +#define OSPFv3RESTARTAGE 20 +#define OSPFv3RESTARTEXITREASON 21 + +/* OSPFv3 MIB Area Table values. */ +#define OSPFv3AREAID 1 +#define OSPFv3IMPORTASEXTERN 2 +#define OSPFv3AREASPFRUNS 3 +#define OSPFv3AREABDRRTRCOUNT 4 +#define OSPFv3AREAASBDRRTRCOUNT 5 +#define OSPFv3AREASCOPELSACOUNT 6 +#define OSPFv3AREASCOPELSACKSUMSUM 7 +#define OSPFv3AREASUMMARY 8 +#define OSPFv3AREASTATUS 9 +#define OSPFv3STUBMETRIC 10 +#define OSPFv3AREANSSATRANSLATORROLE 11 +#define OSPFv3AREANSSATRANSLATORSTATE 12 +#define OSPFv3AREANSSATRANSLATORSTABILITYINTERVAL 13 +#define OSPFv3AREANSSATRANSLATOREVENTS 14 +#define OSPFv3AREASTUBMETRICTYPE 15 + +/* OSPFv3 MIB Area Lsdb Table values. */ +#define OSPFv3AREALSDBAREAID 1 +#define OSPFv3AREALSDBTYPE 2 +#define OSPFv3AREALSDBROUTERID 3 +#define OSPFv3AREALSDBLSID 4 +#define OSPFv3AREALSDBSEQUENCE 5 +#define OSPFv3AREALSDBAGE 6 +#define OSPFv3AREALSDBCHECKSUM 7 +#define OSPFv3AREALSDBADVERTISEMENT 8 +#define OSPFv3AREALSDBTYPEKNOWN 9 + +/* SYNTAX Status from OSPF-MIB. */ +#define OSPF_STATUS_ENABLED 1 +#define OSPF_STATUS_DISABLED 2 + +/* SNMP value hack. */ +#define COUNTER ASN_COUNTER +#define INTEGER ASN_INTEGER +#define GAUGE ASN_GAUGE +#define TIMETICKS ASN_TIMETICKS +#define IPADDRESS ASN_IPADDRESS +#define STRING ASN_OCTET_STR + +/* For return values e.g. SNMP_INTEGER macro */ +SNMP_LOCAL_VARIABLES + +static struct in_addr tmp; +#define INT32_INADDR(x) \ + (tmp.s_addr = (x), tmp) + +/* OSPFv3-MIB instances. */ +oid ospfv3_oid [] = { OSPFv3MIB }; +oid ospf6d_oid [] = { OSPF6DOID }; + +/* empty ID 0.0.0.0 e.g. empty router-id */ +static struct in_addr ospf6_empty_id = {0}; + +/* Hook functions. */ +static u_char *ospfv3GeneralGroup (); +static u_char *ospfv3AreaEntry (); +static u_char *ospfv3AreaLsdbEntry (); + +struct variable ospfv3_variables[] = +{ + /* OSPF general variables */ + {OSPFv3ROUTERID, IPADDRESS, RWRITE, ospfv3GeneralGroup, + 3, {1, 1, 1}}, + {OSPFv3ADMINSTAT, INTEGER, RWRITE, ospfv3GeneralGroup, + 3, {1, 1, 2}}, + {OSPFv3VERSIONNUMBER, INTEGER, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 3}}, + {OSPFv3AREABDRRTRSTATUS, INTEGER, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 4}}, + {OSPFv3ASBDRRTRSTATUS, INTEGER, RWRITE, ospfv3GeneralGroup, + 3, {1, 1, 5}}, + {OSPFv3ASSCOPELSACOUNT, GAUGE, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 6}}, + {OSPFv3ASSCOPELSACHECKSUMSUM, INTEGER, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 7}}, + {OSPFv3ORIGINATENEWLSAS, COUNTER, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 8}}, + {OSPFv3RXNEWLSAS, COUNTER, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 9}}, + {OSPFv3EXTLSACOUNT, GAUGE, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 10}}, + {OSPFv3EXTAREALSDBLIMIT, INTEGER, RWRITE, ospfv3GeneralGroup, + 3, {1, 1, 11}}, + {OSPFv3MULTICASTEXTENSIONS, INTEGER, RWRITE, ospfv3GeneralGroup, + 3, {1, 1, 12}}, + {OSPFv3EXITOVERFLOWINTERVAL, INTEGER, RWRITE, ospfv3GeneralGroup, + 3, {1, 1, 13}}, + {OSPFv3DEMANDEXTENSIONS, INTEGER, RWRITE, ospfv3GeneralGroup, + 3, {1, 1, 14}}, + {OSPFv3TRAFFICENGINEERINGSUPPORT, INTEGER, RWRITE, ospfv3GeneralGroup, + 3, {1, 1, 15}}, + {OSPFv3REFERENCEBANDWIDTH, INTEGER, RWRITE, ospfv3GeneralGroup, + 3, {1, 1, 16}}, + {OSPFv3RESTARTSUPPORT, INTEGER, RWRITE, ospfv3GeneralGroup, + 3, {1, 1, 17}}, + {OSPFv3RESTARTINTERVAL, INTEGER, RWRITE, ospfv3GeneralGroup, + 3, {1, 1, 18}}, + {OSPFv3RESTARTSTATUS, INTEGER, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 19}}, + {OSPFv3RESTARTAGE, INTEGER, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 20}}, + {OSPFv3RESTARTEXITREASON, INTEGER, RONLY, ospfv3GeneralGroup, + 3, {1, 1, 21}}, + + /* OSPFv3 Area Data Structure */ + {OSPFv3AREAID, IPADDRESS, RONLY, ospfv3AreaEntry, + 4, {1, 2, 1, 1}}, + {OSPFv3IMPORTASEXTERN, INTEGER, RWRITE, ospfv3AreaEntry, + 4, {1, 2, 1, 2}}, + {OSPFv3AREASPFRUNS, COUNTER, RONLY, ospfv3AreaEntry, + 4, {1, 2, 1, 3}}, + {OSPFv3AREABDRRTRCOUNT, GAUGE, RONLY, ospfv3AreaEntry, + 4, {1, 2, 1, 4}}, + {OSPFv3AREAASBDRRTRCOUNT, GAUGE, RONLY, ospfv3AreaEntry, + 4, {1, 2, 1, 5}}, + {OSPFv3AREASCOPELSACOUNT, GAUGE, RONLY, ospfv3AreaEntry, + 4, {1, 2, 1, 6}}, + {OSPFv3AREASCOPELSACKSUMSUM, INTEGER, RONLY, ospfv3AreaEntry, + 4, {1, 2, 1, 7}}, + {OSPFv3AREASUMMARY, INTEGER, RWRITE, ospfv3AreaEntry, + 4, {1, 2, 1, 8}}, + {OSPFv3AREASTATUS, INTEGER, RWRITE, ospfv3AreaEntry, + 4, {1, 2, 1, 9}}, + {OSPFv3STUBMETRIC, INTEGER, RWRITE, ospfv3AreaEntry, + 4, {1, 2, 1, 10}}, + {OSPFv3AREANSSATRANSLATORROLE, INTEGER, RWRITE, ospfv3AreaEntry, + 4, {1, 2, 1, 11}}, + {OSPFv3AREANSSATRANSLATORSTATE, INTEGER, RONLY, ospfv3AreaEntry, + 4, {1, 2, 1, 12}}, + {OSPFv3AREANSSATRANSLATORSTABILITYINTERVAL, INTEGER, RWRITE, ospfv3AreaEntry, + 4, {1, 2, 1, 13}}, + {OSPFv3AREANSSATRANSLATOREVENTS, COUNTER, RONLY, ospfv3AreaEntry, + 4, {1, 2, 1, 14}}, + {OSPFv3AREASTUBMETRICTYPE, INTEGER, RWRITE, ospfv3AreaEntry, + 4, {1, 2, 1, 15}}, + + {OSPFv3AREALSDBAREAID, IPADDRESS, RONLY, ospfv3AreaLsdbEntry, + 4, {1, 4, 1, 1}}, + {OSPFv3AREALSDBTYPE, GAUGE, RONLY, ospfv3AreaLsdbEntry, + 4, {1, 4, 1, 2}}, + {OSPFv3AREALSDBROUTERID, IPADDRESS, RONLY, ospfv3AreaLsdbEntry, + 4, {1, 4, 1, 3}}, + {OSPFv3AREALSDBLSID, IPADDRESS, RONLY, ospfv3AreaLsdbEntry, + 4, {1, 4, 1, 4}}, + {OSPFv3AREALSDBSEQUENCE, INTEGER, RONLY, ospfv3AreaLsdbEntry, + 4, {1, 4, 1, 5}}, + {OSPFv3AREALSDBAGE, INTEGER, RONLY, ospfv3AreaLsdbEntry, + 4, {1, 4, 1, 6}}, + {OSPFv3AREALSDBCHECKSUM, INTEGER, RONLY, ospfv3AreaLsdbEntry, + 4, {1, 4, 1, 7}}, + {OSPFv3AREALSDBADVERTISEMENT, STRING, RONLY, ospfv3AreaLsdbEntry, + 4, {1, 4, 1, 8}}, + {OSPFv3AREALSDBTYPEKNOWN, INTEGER, RONLY, ospfv3AreaLsdbEntry, + 4, {1, 4, 1, 9}}, + +}; + +static u_char * +ospfv3GeneralGroup (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + /* Check whether the instance identifier is valid */ + if (smux_header_generic (v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFv3ROUTERID: /* 1*/ + /* Router-ID of this OSPF instance. */ + if (ospf6) + return SNMP_IPADDRESS (INT32_INADDR (ospf6->router_id)); + else + return SNMP_IPADDRESS (ospf6_empty_id); + break; + case OSPFv3ADMINSTAT: /* 2*/ + break; + case OSPFv3VERSIONNUMBER: /* 3*/ + break; + case OSPFv3AREABDRRTRSTATUS: /* 4*/ + break; + case OSPFv3ASBDRRTRSTATUS: /* 5*/ + break; + case OSPFv3ASSCOPELSACOUNT: /* 6*/ + break; + case OSPFv3ASSCOPELSACHECKSUMSUM: /* 7*/ + break; + case OSPFv3ORIGINATENEWLSAS: /* 8*/ + break; + case OSPFv3RXNEWLSAS: /* 9*/ + break; + case OSPFv3EXTLSACOUNT: /*10*/ + break; + case OSPFv3EXTAREALSDBLIMIT: /*11*/ + break; + case OSPFv3MULTICASTEXTENSIONS: /*12*/ + break; + case OSPFv3EXITOVERFLOWINTERVAL: /*13*/ + break; + case OSPFv3DEMANDEXTENSIONS: /*14*/ + break; + case OSPFv3TRAFFICENGINEERINGSUPPORT: /*15*/ + break; + case OSPFv3REFERENCEBANDWIDTH: /*16*/ + break; + case OSPFv3RESTARTSUPPORT: /*17*/ + break; + case OSPFv3RESTARTINTERVAL: /*18*/ + break; + case OSPFv3RESTARTSTATUS: /*19*/ + break; + case OSPFv3RESTARTAGE: /*20*/ + break; + case OSPFv3RESTARTEXITREASON: /*21*/ + break; + default: + return NULL; + } + return NULL; +} + +static u_char * +ospfv3AreaEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + struct ospf6_area *oa, *area = NULL; + u_int32_t area_id = 0; + listnode node; + int len; + + if (ospf6 == NULL) + return NULL; + + len = *length - v->namelen; + len = (len >= sizeof (u_int32_t) ? sizeof (u_int32_t) : 0); + if (exact && len != sizeof (u_int32_t)) + return NULL; + if (len) + oid2in_addr (name + v->namelen, len, (struct in_addr *) &area_id); + + zlog_info ("SNMP access by area: %s, exact=%d len=%d length=%d", + inet_ntoa (* (struct in_addr *) &area_id), + exact, len, *length); + + for (node = listhead (ospf6->area_list); node; nextnode (node)) + { + oa = (struct ospf6_area *) getdata (node); + if (area == NULL) + { + if (len == 0) /* return first area entry */ + area = oa; + else if (exact && ntohl (oa->area_id) == ntohl (area_id)) + area = oa; + else if (ntohl (oa->area_id) > ntohl (area_id)) + area = oa; + } + } + + if (area == NULL) + return NULL; + + *length = v->namelen + sizeof (u_int32_t); + oid_copy_addr (name + v->namelen, (struct in_addr *) &area->area_id, + sizeof (u_int32_t)); + + zlog_info ("SNMP found area: %s, exact=%d len=%d length=%d", + inet_ntoa (* (struct in_addr *) &area->area_id), + exact, len, *length); + + switch (v->magic) + { + case OSPFv3AREAID: /* 1*/ + return SNMP_IPADDRESS (INT32_INADDR (area->area_id)); + break; + case OSPFv3IMPORTASEXTERN: /* 2*/ + return SNMP_INTEGER (ospf6->external_table->count); + break; + default: + return NULL; + break; + } + return NULL; +} + +static u_char * +ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + struct ospf6_lsa *lsa = NULL; + struct in_addr area_id; + u_int16_t type; + struct in_addr id; + struct in_addr adv_router; + int len; + oid *offset; + int offsetlen; + char a[16], b[16], c[16]; + struct ospf6_area *oa; + listnode node; + + memset (&area_id, 0, sizeof (struct in_addr)); + type = 0; + memset (&id, 0, sizeof (struct in_addr)); + memset (&adv_router, 0, sizeof (struct in_addr)); + + /* Check OSPFv3 instance. */ + if (ospf6 == NULL) + return NULL; + + /* Get variable length. */ + offset = name + v->namelen; + offsetlen = *length - v->namelen; + +#define OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET \ + (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE) + + if (exact && offsetlen != OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET) + return NULL; + + /* Parse area-id */ + len = (offsetlen < IN_ADDR_SIZE ? offsetlen : IN_ADDR_SIZE); + if (len) + oid2in_addr (offset, len, &area_id); + offset += len; + offsetlen -= len; + + /* Parse type */ + len = (offsetlen < 1 ? offsetlen : 1); + if (len) + type = htons (*offset); + offset += len; + offsetlen -= len; + + /* Parse Router-ID */ + len = (offsetlen < IN_ADDR_SIZE ? offsetlen : IN_ADDR_SIZE); + if (len) + oid2in_addr (offset, len, &adv_router); + offset += len; + offsetlen -= len; + + /* Parse LS-ID */ + len = (offsetlen < IN_ADDR_SIZE ? offsetlen : IN_ADDR_SIZE); + if (len) + oid2in_addr (offset, len, &id); + offset += len; + offsetlen -= len; + + inet_ntop (AF_INET, &area_id, a, sizeof (a)); + inet_ntop (AF_INET, &adv_router, b, sizeof (b)); + inet_ntop (AF_INET, &id, c, sizeof (c)); + zlog_info ("SNMP access by lsdb: area=%s exact=%d length=%d magic=%d" + " type=%#x adv_router=%s id=%s", + a, exact, *length, v->magic, ntohs (type), b, c); + + if (exact) + { + oa = ospf6_area_lookup (area_id.s_addr, ospf6); + lsa = ospf6_lsdb_lookup (type, id.s_addr, adv_router.s_addr, oa->lsdb); + } + else + { + for (node = listhead (ospf6->area_list); node; nextnode (node)) + { + oa = (struct ospf6_area *) getdata (node); + + if (lsa) + continue; + if (ntohl (oa->area_id) < ntohl (area_id.s_addr)) + continue; + + lsa = ospf6_lsdb_lookup_next (type, id.s_addr, adv_router.s_addr, + oa->lsdb); + if (! lsa) + { + type = 0; + memset (&id, 0, sizeof (struct in_addr)); + memset (&adv_router, 0, sizeof (struct in_addr)); + } + } + } + + if (! lsa) + { + zlog_info ("SNMP respond: No LSA to return"); + return NULL; + } + oa = OSPF6_AREA (lsa->lsdb->data); + + zlog_info ("SNMP respond: area: %s lsa: %s", oa->name, lsa->name); + + /* Add Index (AreaId, Type, RouterId, Lsid) */ + *length = v->namelen + OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET; + offset = name + v->namelen; + oid_copy_addr (offset, (struct in_addr *) &oa->area_id, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + *offset = ntohs (lsa->header->type); + offset++; + oid_copy_addr (offset, (struct in_addr *) &lsa->header->adv_router, + IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + oid_copy_addr (offset, (struct in_addr *) &lsa->header->id, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFv3AREALSDBAREAID: /* 1 */ + area_id.s_addr = OSPF6_AREA (lsa->lsdb->data)->area_id; + return SNMP_IPADDRESS (area_id); + break; + case OSPFv3AREALSDBTYPE: /* 2 */ + return SNMP_INTEGER (ntohs (lsa->header->type)); + break; + case OSPFv3AREALSDBROUTERID: /* 3 */ + adv_router.s_addr = lsa->header->adv_router; + return SNMP_IPADDRESS (adv_router); + break; + case OSPFv3AREALSDBLSID: /* 4 */ + id.s_addr = lsa->header->id; + return SNMP_IPADDRESS (id); + break; + case OSPFv3AREALSDBSEQUENCE: /* 5 */ + return SNMP_INTEGER (lsa->header->seqnum); + break; + case OSPFv3AREALSDBAGE: /* 6 */ + ospf6_lsa_age_current (lsa); + return SNMP_INTEGER (lsa->header->age); + break; + case OSPFv3AREALSDBCHECKSUM: /* 7 */ + return SNMP_INTEGER (lsa->header->checksum); + break; + case OSPFv3AREALSDBADVERTISEMENT: /* 8 */ + *var_len = ntohs (lsa->header->length); + return (u_char *) lsa->header; + break; + case OSPFv3AREALSDBTYPEKNOWN: /* 9 */ + return SNMP_INTEGER (OSPF6_LSA_IS_KNOWN (lsa->header->type) ? + SNMP_TRUE : SNMP_FALSE); + break; + default: + return NULL; + break; + } + return NULL; +} + + +/* Register OSPFv3-MIB. */ +void +ospf6_snmp_init () +{ + smux_init (ospf6d_oid, sizeof (ospf6d_oid) / sizeof (oid)); + REGISTER_MIB ("OSPFv3MIB", ospfv3_variables, variable, ospfv3_oid); + smux_start (); +} + +#endif /* HAVE_SNMP */ + diff --git a/ospf6d/ospf6_snmp.h b/ospf6d/ospf6_snmp.h new file mode 100644 index 0000000..89c8c47 --- /dev/null +++ b/ospf6d/ospf6_snmp.h @@ -0,0 +1,29 @@ +/* OSPFv3 SNMP support + * Copyright (C) 2004 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_SNMP_H +#define OSPF6_SNMP_H + +void ospf6_snmp_init (); + +#endif /*OSPF6_SNMP_H*/ + + diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c new file mode 100644 index 0000000..e0371af --- /dev/null +++ b/ospf6d/ospf6_spf.c @@ -0,0 +1,714 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* Shortest Path First calculation for OSPFv3 */ + +#include + +#include "log.h" +#include "memory.h" +#include "command.h" +#include "vty.h" +#include "prefix.h" +#include "pqueue.h" +#include "linklist.h" +#include "thread.h" + +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_route.h" +#include "ospf6_area.h" +#include "ospf6_spf.h" +#include "ospf6_intra.h" +#include "ospf6_interface.h" +#include "ospf6d.h" + +unsigned char conf_debug_ospf6_spf = 0; + +int +ospf6_vertex_cmp (void *a, void *b) +{ + struct ospf6_vertex *va = (struct ospf6_vertex *) a; + struct ospf6_vertex *vb = (struct ospf6_vertex *) b; + + /* ascending order */ + return (va->cost - vb->cost); +} + +int +ospf6_vertex_id_cmp (void *a, void *b) +{ + struct ospf6_vertex *va = (struct ospf6_vertex *) a; + struct ospf6_vertex *vb = (struct ospf6_vertex *) b; + int ret = 0; + + ret = ntohl (ospf6_linkstate_prefix_adv_router (&va->vertex_id)) - + ntohl (ospf6_linkstate_prefix_adv_router (&vb->vertex_id)); + if (ret) + return ret; + + ret = ntohl (ospf6_linkstate_prefix_id (&va->vertex_id)) - + ntohl (ospf6_linkstate_prefix_id (&vb->vertex_id)); + return ret; +} + +struct ospf6_vertex * +ospf6_vertex_create (struct ospf6_lsa *lsa) +{ + struct ospf6_vertex *v; + int i; + + v = (struct ospf6_vertex *) + XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex)); + + /* type */ + if (ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER) + v->type = OSPF6_VERTEX_TYPE_ROUTER; + else if (ntohs (lsa->header->type) == OSPF6_LSTYPE_NETWORK) + v->type = OSPF6_VERTEX_TYPE_NETWORK; + else + assert (0); + + /* vertex_id */ + ospf6_linkstate_prefix (lsa->header->adv_router, lsa->header->id, + &v->vertex_id); + + /* name */ + ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name)); + + /* Associated LSA */ + v->lsa = lsa; + + /* capability bits + options */ + v->capability = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header)); + v->options[0] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 1); + v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2); + v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3); + + for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) + ospf6_nexthop_clear (&v->nexthop[i]); + + v->parent = NULL; + v->child_list = list_new (); + v->child_list->cmp = ospf6_vertex_id_cmp; + + return v; +} + +void +ospf6_vertex_delete (struct ospf6_vertex *v) +{ + list_delete (v->child_list); + XFREE (MTYPE_OSPF6_VERTEX, v); +} + +struct ospf6_lsa * +ospf6_lsdesc_lsa (caddr_t lsdesc, struct ospf6_vertex *v) +{ + struct ospf6_lsa *lsa; + u_int16_t type = 0; + u_int32_t id = 0, adv_router = 0; + + if (VERTEX_IS_TYPE (NETWORK, v)) + { + type = htons (OSPF6_LSTYPE_ROUTER); + id = htonl (0); + adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc); + } + else + { + if (ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc)) + { + type = htons (OSPF6_LSTYPE_ROUTER); + id = htonl (0); + adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc); + } + else if (ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, lsdesc)) + { + type = htons (OSPF6_LSTYPE_NETWORK); + id = htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)); + adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc); + } + } + + lsa = ospf6_lsdb_lookup (type, id, adv_router, v->area->lsdb); + + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + { + char ibuf[16], abuf[16]; + inet_ntop (AF_INET, &id, ibuf, sizeof (ibuf)); + inet_ntop (AF_INET, &adv_router, abuf, sizeof (abuf)); + if (lsa) + zlog_info (" Link to: %s", lsa->name); + else + zlog_info (" Link to: [%s Id:%s Adv:%s] No LSA", + ospf6_lstype_name (type), ibuf, abuf); + } + + return lsa; +} + +char * +ospf6_lsdesc_backlink (struct ospf6_lsa *lsa, + caddr_t lsdesc, struct ospf6_vertex *v) +{ + caddr_t backlink, found = NULL; + int size; + + size = (OSPF6_LSA_IS_TYPE (ROUTER, lsa) ? + sizeof (struct ospf6_router_lsdesc) : + sizeof (struct ospf6_network_lsdesc)); + for (backlink = OSPF6_LSA_HEADER_END (lsa->header) + 4; + backlink + size <= OSPF6_LSA_END (lsa->header); backlink += size) + { + assert (! (OSPF6_LSA_IS_TYPE (NETWORK, lsa) && + VERTEX_IS_TYPE (NETWORK, v))); + + if (OSPF6_LSA_IS_TYPE (NETWORK, lsa) && + NETWORK_LSDESC_GET_NBR_ROUTERID (backlink) + == v->lsa->header->adv_router) + found = backlink; + else if (VERTEX_IS_TYPE (NETWORK, v) && + ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, backlink) && + ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) + == v->lsa->header->adv_router && + ROUTER_LSDESC_GET_NBR_IFID (backlink) + == ntohl (v->lsa->header->id)) + found = backlink; + else + { + if (! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, backlink) || + ! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc)) + continue; + if (ROUTER_LSDESC_GET_NBR_IFID (backlink) != + ROUTER_LSDESC_GET_IFID (lsdesc) || + ROUTER_LSDESC_GET_NBR_IFID (lsdesc) != + ROUTER_LSDESC_GET_IFID (backlink)) + continue; + if (ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) != + v->lsa->header->adv_router || + ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc) != + lsa->header->adv_router) + continue; + found = backlink; + } + } + + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + zlog_info (" Backlink %s", (found ? "OK" : "FAIL")); + + return found; +} + +void +ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v, + caddr_t lsdesc) +{ + int i, ifindex; + struct ospf6_interface *oi; + u_int16_t type; + u_int32_t adv_router; + struct ospf6_lsa *lsa; + struct ospf6_link_lsa *link_lsa; + char buf[64]; + + assert (VERTEX_IS_TYPE (ROUTER, w)); + ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex : + ROUTER_LSDESC_GET_IFID (lsdesc)); + oi = ospf6_interface_lookup_by_ifindex (ifindex); + if (oi == NULL) + { + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + zlog_warn ("Can't find interface in SPF: ifindex %d", ifindex); + return; + } + + type = htons (OSPF6_LSTYPE_LINK); + adv_router = (VERTEX_IS_TYPE (NETWORK, v) ? + NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc) : + ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc)); + + i = 0; + for (lsa = ospf6_lsdb_type_router_head (type, adv_router, oi->lsdb); lsa; + lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa)) + { + if (VERTEX_IS_TYPE (ROUTER, v) && + htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id) + continue; + + link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header); + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + { + inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf)); + zlog_info (" nexthop %s from %s", buf, lsa->name); + } + + if (i < OSPF6_MULTI_PATH_LIMIT) + { + memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr, + sizeof (struct in6_addr)); + w->nexthop[i].ifindex = ifindex; + i++; + } + } + + if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS)) + zlog_info ("No nexthop for %s found", w->name); +} + +int +ospf6_spf_install (struct ospf6_vertex *v, + struct ospf6_route_table *result_table) +{ + struct ospf6_route *route; + int i, j; + struct ospf6_vertex *prev, *w; + listnode node; + + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + zlog_info ("SPF install %s hops %d cost %d", + v->name, v->hops, v->cost); + + route = ospf6_route_lookup (&v->vertex_id, result_table); + if (route && route->path.cost < v->cost) + { + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + zlog_info (" already installed with lower cost (%d), ignore", + route->path.cost); + ospf6_vertex_delete (v); + return -1; + } + else if (route && route->path.cost == v->cost) + { + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + zlog_info (" another path found, merge"); + + for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && + i < OSPF6_MULTI_PATH_LIMIT; i++) + { + for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++) + { + if (ospf6_nexthop_is_set (&route->nexthop[j])) + { + if (ospf6_nexthop_is_same (&route->nexthop[j], + &v->nexthop[i])) + break; + else + continue; + } + ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]); + break; + } + } + + prev = (struct ospf6_vertex *) route->route_option; + if (prev->hops > v->hops) + { + LIST_LOOP (prev->child_list, w, node) + { + assert (w->parent == prev); + w->parent = v; + listnode_add_sort (v->child_list, w); + } + listnode_delete (prev->parent->child_list, prev); + listnode_add_sort (v->parent->child_list, v); + + ospf6_vertex_delete (prev); + route->route_option = v; + } + else + ospf6_vertex_delete (v); + + return -1; + } + + /* There should be no case where candidate being installed (variable + "v") is closer than the one in the SPF tree (variable "route"). + In the case something has gone wrong with the behavior of + Priority-Queue. */ + + /* the case where the route exists already is handled and returned + up to here. */ + assert (route == NULL); + + route = ospf6_route_create (); + memcpy (&route->prefix, &v->vertex_id, sizeof (struct prefix)); + route->type = OSPF6_DEST_TYPE_LINKSTATE; + route->path.type = OSPF6_PATH_TYPE_INTRA; + route->path.origin.type = v->lsa->header->type; + route->path.origin.id = v->lsa->header->id; + route->path.origin.adv_router = v->lsa->header->adv_router; + route->path.metric_type = 1; + route->path.cost = v->cost; + route->path.cost_e2 = v->hops; + route->path.router_bits = v->capability; + route->path.options[0] = v->options[0]; + route->path.options[1] = v->options[1]; + route->path.options[2] = v->options[2]; + + for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && + i < OSPF6_MULTI_PATH_LIMIT; i++) + ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]); + + if (v->parent) + listnode_add_sort (v->parent->child_list, v); + route->route_option = v; + + ospf6_route_add (route, result_table); + return 0; +} + +void +ospf6_spf_table_finish (struct ospf6_route_table *result_table) +{ + struct ospf6_route *route; + struct ospf6_vertex *v; + for (route = ospf6_route_head (result_table); route; + route = ospf6_route_next (route)) + { + v = (struct ospf6_vertex *) route->route_option; + ospf6_vertex_delete (v); + ospf6_route_remove (route, result_table); + } +} + +/* RFC2328 16.1. Calculating the shortest-path tree for an area */ +/* RFC2740 3.8.1. Calculating the shortest path tree for an area */ +void +ospf6_spf_calculation (u_int32_t router_id, + struct ospf6_route_table *result_table, + struct ospf6_area *oa) +{ + struct pqueue *candidate_list; + struct ospf6_vertex *root, *v, *w; + int i; + int size; + caddr_t lsdesc; + struct ospf6_lsa *lsa; + + /* initialize */ + candidate_list = pqueue_create (); + candidate_list->cmp = ospf6_vertex_cmp; + + ospf6_spf_table_finish (result_table); + + /* Install the calculating router itself as the root of the SPF tree */ + /* construct root vertex */ + lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0), + router_id, oa->lsdb); + if (lsa == NULL) + return; + root = ospf6_vertex_create (lsa); + root->area = oa; + root->cost = 0; + root->hops = 0; + root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */ + inet_pton (AF_INET6, "::1", &root->nexthop[0].address); + + /* Actually insert root to the candidate-list as the only candidate */ + pqueue_enqueue (root, candidate_list); + + /* Iterate until candidate-list becomes empty */ + while (candidate_list->size) + { + /* get closest candidate from priority queue */ + v = pqueue_dequeue (candidate_list); + + /* installing may result in merging or rejecting of the vertex */ + if (ospf6_spf_install (v, result_table) < 0) + continue; + + /* For each LS description in the just-added vertex V's LSA */ + size = (VERTEX_IS_TYPE (ROUTER, v) ? + sizeof (struct ospf6_router_lsdesc) : + sizeof (struct ospf6_network_lsdesc)); + for (lsdesc = OSPF6_LSA_HEADER_END (v->lsa->header) + 4; + lsdesc + size <= OSPF6_LSA_END (v->lsa->header); lsdesc += size) + { + lsa = ospf6_lsdesc_lsa (lsdesc, v); + if (lsa == NULL) + continue; + + if (! ospf6_lsdesc_backlink (lsa, lsdesc, v)) + continue; + + w = ospf6_vertex_create (lsa); + w->area = oa; + w->parent = v; + if (VERTEX_IS_TYPE (ROUTER, v)) + { + w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc); + w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1); + } + else /* NETWORK */ + { + w->cost = v->cost; + w->hops = v->hops + 1; + } + + /* nexthop calculation */ + if (w->hops == 0) + w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc); + else if (w->hops == 1 && v->hops == 0) + ospf6_nexthop_calc (w, v, lsdesc); + else + { + for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && + i < OSPF6_MULTI_PATH_LIMIT; i++) + ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]); + } + + /* add new candidate to the candidate_list */ + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + zlog_info (" New candidate: %s hops %d cost %d", + w->name, w->hops, w->cost); + pqueue_enqueue (w, candidate_list); + } + } + + pqueue_delete (candidate_list); +} + +void +ospf6_spf_log_database (struct ospf6_area *oa) +{ + char *p, *end, buffer[256]; + listnode node; + struct ospf6_interface *oi; + + p = buffer; + end = buffer + sizeof (buffer); + + snprintf (p, end - p, "SPF on DB (#LSAs):"); + p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end); + snprintf (p, end - p, " Area %s: %d", oa->name, oa->lsdb->count); + p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end); + + for (node = listhead (oa->if_list); node; nextnode (node)) + { + oi = (struct ospf6_interface *) getdata (node); + snprintf (p, end - p, " I/F %s: %d", + oi->interface->name, oi->lsdb->count); + p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end); + } + + zlog_info ("%s", buffer); +} + +int +ospf6_spf_calculation_thread (struct thread *t) +{ + struct ospf6_area *oa; + struct timeval start, end, runtime; + + oa = (struct ospf6_area *) THREAD_ARG (t); + oa->thread_spf_calculation = NULL; + + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + zlog_info ("SPF calculation for Area %s", oa->name); + if (IS_OSPF6_DEBUG_SPF (DATABASE)) + ospf6_spf_log_database (oa); + + /* execute SPF calculation */ + gettimeofday (&start, (struct timezone *) NULL); + ospf6_spf_calculation (oa->ospf6->router_id, oa->spf_table, oa); + gettimeofday (&end, (struct timezone *) NULL); + timersub (&end, &start, &runtime); + + if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) + zlog_info ("SPF runtime: %ld sec %ld usec", + runtime.tv_sec, runtime.tv_usec); + + ospf6_intra_route_calculation (oa); + ospf6_intra_brouter_calculation (oa); + + return 0; +} + +void +ospf6_spf_schedule (struct ospf6_area *oa) +{ + if (oa->thread_spf_calculation) + return; + oa->thread_spf_calculation = + thread_add_event (master, ospf6_spf_calculation_thread, oa, 0); +} + +void +ospf6_spf_display_subtree (struct vty *vty, char *prefix, int rest, + struct ospf6_vertex *v) +{ + listnode node; + struct ospf6_vertex *c; + char *next_prefix; + int len; + int restnum; + + /* "prefix" is the space prefix of the display line */ + vty_out (vty, "%s+-%s [%d]%s", prefix, v->name, v->cost, VNL); + + len = strlen (prefix) + 4; + next_prefix = (char *) malloc (len); + if (next_prefix == NULL) + { + vty_out (vty, "malloc failed%s", VNL); + return; + } + snprintf (next_prefix, len, "%s%s", prefix, (rest ? "| " : " ")); + + restnum = listcount (v->child_list); + LIST_LOOP (v->child_list, c, node) + { + restnum--; + ospf6_spf_display_subtree (vty, next_prefix, restnum, c); + } + + free (next_prefix); +} + +DEFUN (debug_ospf6_spf_process, + debug_ospf6_spf_process_cmd, + "debug ospf6 spf process", + DEBUG_STR + OSPF6_STR + "Debug SPF Calculation\n" + "Debug Detailed SPF Process\n" + ) +{ + unsigned char level = 0; + level = OSPF6_DEBUG_SPF_PROCESS; + OSPF6_DEBUG_SPF_ON (level); + return CMD_SUCCESS; +} + +DEFUN (debug_ospf6_spf_time, + debug_ospf6_spf_time_cmd, + "debug ospf6 spf time", + DEBUG_STR + OSPF6_STR + "Debug SPF Calculation\n" + "Measure time taken by SPF Calculation\n" + ) +{ + unsigned char level = 0; + level = OSPF6_DEBUG_SPF_TIME; + OSPF6_DEBUG_SPF_ON (level); + return CMD_SUCCESS; +} + +DEFUN (debug_ospf6_spf_database, + debug_ospf6_spf_database_cmd, + "debug ospf6 spf database", + DEBUG_STR + OSPF6_STR + "Debug SPF Calculation\n" + "Log number of LSAs at SPF Calculation time\n" + ) +{ + unsigned char level = 0; + level = OSPF6_DEBUG_SPF_DATABASE; + OSPF6_DEBUG_SPF_ON (level); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf6_spf_process, + no_debug_ospf6_spf_process_cmd, + "no debug ospf6 spf process", + NO_STR + DEBUG_STR + OSPF6_STR + "Quit Debugging SPF Calculation\n" + "Quit Debugging Detailed SPF Process\n" + ) +{ + unsigned char level = 0; + level = OSPF6_DEBUG_SPF_PROCESS; + OSPF6_DEBUG_SPF_OFF (level); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf6_spf_time, + no_debug_ospf6_spf_time_cmd, + "no debug ospf6 spf time", + NO_STR + DEBUG_STR + OSPF6_STR + "Quit Debugging SPF Calculation\n" + "Quit Measuring time taken by SPF Calculation\n" + ) +{ + unsigned char level = 0; + level = OSPF6_DEBUG_SPF_TIME; + OSPF6_DEBUG_SPF_OFF (level); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf6_spf_database, + no_debug_ospf6_spf_database_cmd, + "no debug ospf6 spf database", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug SPF Calculation\n" + "Quit Logging number of LSAs at SPF Calculation time\n" + ) +{ + unsigned char level = 0; + level = OSPF6_DEBUG_SPF_DATABASE; + OSPF6_DEBUG_SPF_OFF (level); + return CMD_SUCCESS; +} + +int +config_write_ospf6_debug_spf (struct vty *vty) +{ + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + vty_out (vty, "debug ospf6 spf process%s", VNL); + if (IS_OSPF6_DEBUG_SPF (TIME)) + vty_out (vty, "debug ospf6 spf time%s", VNL); + if (IS_OSPF6_DEBUG_SPF (DATABASE)) + vty_out (vty, "debug ospf6 spf database%s", VNL); + return 0; +} + +void +install_element_ospf6_debug_spf () +{ + install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd); + install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd); + install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd); + install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd); + install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd); + install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd); +} + +void +ospf6_spf_init () +{ +} + + diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h new file mode 100644 index 0000000..8c5a80d --- /dev/null +++ b/ospf6d/ospf6_spf.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_SPF_H +#define OSPF6_SPF_H + +/* Debug option */ +extern unsigned char conf_debug_ospf6_spf; +#define OSPF6_DEBUG_SPF_PROCESS 0x01 +#define OSPF6_DEBUG_SPF_TIME 0x02 +#define OSPF6_DEBUG_SPF_DATABASE 0x04 +#define OSPF6_DEBUG_SPF_ON(level) \ + (conf_debug_ospf6_spf |= (level)) +#define OSPF6_DEBUG_SPF_OFF(level) \ + (conf_debug_ospf6_spf &= ~(level)) +#define IS_OSPF6_DEBUG_SPF(level) \ + (conf_debug_ospf6_spf & OSPF6_DEBUG_SPF_ ## level) + +/* Transit Vertex */ +struct ospf6_vertex +{ + /* type of this vertex */ + u_int8_t type; + + /* Vertex Identifier */ + struct prefix vertex_id; + + /* Identifier String */ + char name[128]; + + /* Associated Area */ + struct ospf6_area *area; + + /* Associated LSA */ + struct ospf6_lsa *lsa; + + /* Distance from Root (i.e. Cost) */ + u_int32_t cost; + + /* Router hops to this node */ + u_char hops; + + /* nexthops to this node */ + struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT]; + + /* capability bits */ + u_char capability; + + /* Optional capabilities */ + u_char options[3]; + + /* For tree display */ + struct ospf6_vertex *parent; + list child_list; +}; + +#define OSPF6_VERTEX_TYPE_ROUTER 0x01 +#define OSPF6_VERTEX_TYPE_NETWORK 0x02 +#define VERTEX_IS_TYPE(t, v) \ + ((v)->type == OSPF6_VERTEX_TYPE_ ## t ? 1 : 0) + +void ospf6_spf_table_finish (struct ospf6_route_table *result_table); +void ospf6_spf_calculation (u_int32_t router_id, + struct ospf6_route_table *result_table, + struct ospf6_area *oa); +void ospf6_spf_schedule (struct ospf6_area *oa); + +void ospf6_spf_display_subtree (struct vty *vty, char *prefix, + int rest, struct ospf6_vertex *v); + +int config_write_ospf6_debug_spf (struct vty *vty); +void install_element_ospf6_debug_spf (); +void ospf6_spf_init (); + +#endif /* OSPF6_SPF_H */ + diff --git a/ospf6d/ospf6_test.c b/ospf6d/ospf6_test.c new file mode 100644 index 0000000..a552b5c --- /dev/null +++ b/ospf6d/ospf6_test.c @@ -0,0 +1,427 @@ + +#include +#include + +#include "log.h" +#include "memory.h" +#include "prefix.h" +#include "table.h" +#include "command.h" +#include "vty.h" +#include "thread.h" +#include "linklist.h" +#include "if.h" + +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_route.h" +#include "ospf6_spf.h" + +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_intra.h" + +extern char *malloc_options; + +struct thread_master *master; + +#define NUMBER_OF_TRIALS 1000000 +int N = 4; + +#define ROW(n) ((n) % N) +#define COL(n) ((n) / N) + +#define IS_TOPOF(n) (COL(n) > 0) +#define IS_BOTTOMOF(n) (COL(n) < N - 1) +#define IS_LEFTOF(n) (ROW(n) > 0) +#define IS_RIGHTOF(n) (ROW(n) < N - 1) +#define TOPOF(n) (n - N) +#define BOTTOMOF(n) (n + N) +#define LEFTOF(n) (n - 1) +#define RIGHTOF(n) (n + 1) + +#define IFINDEX_TOP 0 +#define IFINDEX_BOTTOM 1 +#define IFINDEX_LEFT 2 +#define IFINDEX_RIGHT 3 + +struct in6_addr topaddr = +{{{ 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, IFINDEX_TOP }}}; +struct in6_addr leftaddr = +{{{ 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, IFINDEX_LEFT }}}; +struct in6_addr rightaddr = +{{{ 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, IFINDEX_RIGHT }}}; +struct in6_addr bottomaddr = +{{{ 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, IFINDEX_BOTTOM }}}; + +void +install_router_lsa (u_int32_t router_id, struct ospf6_lsdb *lsdb) +{ + char buffer[OSPF6_MAX_LSASIZE]; + struct ospf6_lsa_header *lsa_header; + struct ospf6_lsa *lsa; + struct ospf6_router_lsa *router_lsa; + struct ospf6_router_lsdesc *lsdesc; + + //printf ("install %d\n", router_id); + + lsa_header = (struct ospf6_lsa_header *) buffer; + router_lsa = (struct ospf6_router_lsa *) + ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); + lsdesc = (struct ospf6_router_lsdesc *) + ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa)); + + if (IS_TOPOF (router_id)) + { + lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT; + lsdesc->metric = htons (1); + lsdesc->interface_id = htonl (IFINDEX_TOP); + lsdesc->neighbor_interface_id = htonl (IFINDEX_BOTTOM); + lsdesc->neighbor_router_id = htonl (TOPOF (router_id)); + lsdesc++; + } + if (IS_LEFTOF (router_id)) + { + lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT; + lsdesc->metric = htons (1); + lsdesc->interface_id = htonl (IFINDEX_LEFT); + lsdesc->neighbor_interface_id = htonl (IFINDEX_RIGHT); + lsdesc->neighbor_router_id = htonl (LEFTOF (router_id)); + lsdesc++; + } + if (IS_RIGHTOF (router_id)) + { + lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT; + lsdesc->metric = htons (1); + lsdesc->interface_id = htonl (IFINDEX_RIGHT); + lsdesc->neighbor_interface_id = htonl (IFINDEX_LEFT); + lsdesc->neighbor_router_id = htonl (RIGHTOF (router_id)); + lsdesc++; + } + if (IS_BOTTOMOF (router_id)) + { + lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT; + lsdesc->metric = htons (1); + lsdesc->interface_id = htonl (IFINDEX_BOTTOM); + lsdesc->neighbor_interface_id = htonl (IFINDEX_TOP); + lsdesc->neighbor_router_id = htonl (BOTTOMOF (router_id)); + lsdesc++; + } + + OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_V6); + OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_E); + OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_MC); + OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_N); + OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_R); + OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_DC); + UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B); + UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E); + UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_V); + UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_W); + + lsa_header->age = 0; + lsa_header->type = htons (OSPF6_LSTYPE_ROUTER); + lsa_header->id = htonl (0); + lsa_header->adv_router = htonl (router_id); + lsa_header->seqnum = htonl (INITIAL_SEQUENCE_NUMBER); + lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); + + lsa = ospf6_lsa_create (lsa_header); + ospf6_lsdb_add (lsa, lsdb); +} + +static double +diffsec (struct timeval *end, struct timeval *start) +{ + double time; + time = (end->tv_sec - start->tv_sec) * 1.0 + + (end->tv_usec - start->tv_usec) / 1000000.0; + if (time < 0.0) + fprintf (stderr, "time: %f end{%010lu,%010lu} start{%010lu,%010lu}\n", + time, end->tv_sec, end->tv_usec, start->tv_sec, start->tv_usec); + return time; +} + +void +lsdb_lookup_try (int ntry, struct ospf6_lsdb *lsdb) +{ + struct ospf6_lsa *lsa; + struct timeval start, now; + double time, timesum, timesumsq; + double max, min, avg, variance, std; + int rets, retn; + int i; + u_int32_t router_id; + + max = 0.0; + min = 999999999.0; + timesum = 0.0; + timesumsq = 0.0; + for (i = 0; i < ntry; i++) + { + router_id = random () % (N * N); + + memset (&start, 0, sizeof (&start)); + memset (&now, 0, sizeof (&now)); + + lsa = NULL; + rets = gettimeofday (&start, NULL); + lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0), + htonl (router_id), lsdb); + retn = gettimeofday (&now, NULL); + assert (lsa); + + if (rets != 0 || retn != 0) + { + fprintf (stderr, "gettimeofday failed: %s\n", strerror (errno)); + i--; + continue; + } + + time = diffsec (&now, &start); + timesum += time; + timesumsq += time * time; + max = (time > max ? time : max); + min = (time < min ? time : min); + } + + avg = timesum / ntry; + variance = (timesumsq - ntry * avg * avg) / ntry; + std = sqrt (variance); + + printf ("test lsdb: #LSAs: %d #lookup: %d min: %.3f avg: %.3f max: %.3f stddev: %.3f (ms)\n", + N * N, ntry, min * 1000.0, avg * 1000.0, max * 1000.0, std * 1000.0); +} + +void +install_link_lsdb (u_int32_t router_id, int ifindex) +{ + struct interface *ifp; + struct ospf6_interface *oi; + char *ifname = NULL; + u_int32_t peer = 0; + int peer_ifindex = 0; + char buffer[OSPF6_MAX_LSASIZE]; + struct ospf6_lsa_header *lsa_header; + struct ospf6_link_lsa *link_lsa; + struct ospf6_lsa *lsa; + char *p; + + if (ifindex == IFINDEX_TOP && IS_TOPOF (router_id)) + { + ifname = "top"; + peer = TOPOF (router_id); + peer_ifindex = IFINDEX_BOTTOM; + } + else if (ifindex == IFINDEX_LEFT && IS_LEFTOF (router_id)) + { + ifname = "left"; + peer = LEFTOF (router_id); + peer_ifindex = IFINDEX_RIGHT; + } + else if (ifindex == IFINDEX_RIGHT && IS_RIGHTOF (router_id)) + { + ifname = "right"; + peer = RIGHTOF (router_id); + peer_ifindex = IFINDEX_LEFT; + } + else if (ifindex == IFINDEX_BOTTOM && IS_BOTTOMOF (router_id)) + { + ifname = "bottom"; + peer = BOTTOMOF (router_id); + peer_ifindex = IFINDEX_TOP; + } + else + assert (0); + + ifp = if_get_by_name (ifname); + ifp->ifindex = ifindex; + + oi = malloc (sizeof (struct ospf6_interface)); + oi->interface = ifp; + ifp->info = oi; + + oi->lsdb = ospf6_lsdb_create (oi); + + memset (buffer, 0, sizeof (buffer)); + lsa_header = (struct ospf6_lsa_header *) buffer; + link_lsa = (struct ospf6_link_lsa *) + ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); + p = ((caddr_t) link_lsa + sizeof (struct ospf6_link_lsa)); + + link_lsa->priority = 1; + link_lsa->options[0] = 0; + link_lsa->options[1] = 0; + link_lsa->options[2] = 0; + if (ifindex == IFINDEX_TOP) + link_lsa->linklocal_addr = topaddr; + else if (ifindex == IFINDEX_LEFT) + link_lsa->linklocal_addr = leftaddr; + else if (ifindex == IFINDEX_RIGHT) + link_lsa->linklocal_addr = rightaddr; + else + link_lsa->linklocal_addr = bottomaddr; + link_lsa->prefix_num = htonl (0); + + lsa_header->age = 0; + lsa_header->type = htons (OSPF6_LSTYPE_LINK); + lsa_header->id = htonl (ifindex); + lsa_header->adv_router = htonl (router_id); + lsa_header->seqnum = htonl (INITIAL_SEQUENCE_NUMBER); + lsa_header->length = htons ((caddr_t) p - (caddr_t) buffer); + + lsa = ospf6_lsa_create (lsa_header); + ospf6_lsdb_add (lsa, oi->lsdb); + + /* peer's */ + memset (buffer, 0, sizeof (buffer)); + lsa_header = (struct ospf6_lsa_header *) buffer; + link_lsa = (struct ospf6_link_lsa *) + ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); + p = ((caddr_t) link_lsa + sizeof (struct ospf6_link_lsa)); + + link_lsa->priority = 1; + link_lsa->options[0] = 0; + link_lsa->options[1] = 0; + link_lsa->options[2] = 0; + if (peer_ifindex == IFINDEX_TOP) + link_lsa->linklocal_addr = topaddr; + else if (peer_ifindex == IFINDEX_LEFT) + link_lsa->linklocal_addr = leftaddr; + else if (peer_ifindex == IFINDEX_RIGHT) + link_lsa->linklocal_addr = rightaddr; + else + link_lsa->linklocal_addr = bottomaddr; + link_lsa->prefix_num = htonl (0); + + lsa_header->age = 0; + lsa_header->type = htons (OSPF6_LSTYPE_LINK); + lsa_header->id = htonl (peer_ifindex); + lsa_header->adv_router = htonl (peer); + lsa_header->seqnum = htonl (INITIAL_SEQUENCE_NUMBER); + lsa_header->length = htons ((caddr_t) p - (caddr_t) buffer); + + lsa = ospf6_lsa_create (lsa_header); + ospf6_lsdb_add (lsa, oi->lsdb); + + return; +} + +void +spf_try (u_int32_t router_id, struct ospf6_lsdb *lsdb) +{ + struct ospf6_area *oa; + struct ospf6_interface *oi; + struct timeval start, end; + double time; + int rets, rete; + listnode node; + + oa = malloc (sizeof (struct ospf6_area)); + snprintf (oa->name, sizeof (oa->name), "spf_test"); + oa->lsdb = lsdb; + oa->spf_table = ospf6_route_table_create (); + + oa->if_list = list_new (); + if (IS_TOPOF (router_id)) + { + install_link_lsdb (router_id, IFINDEX_TOP); + oi = ospf6_interface_lookup_by_ifindex (IFINDEX_TOP); + listnode_add (oa->if_list, oi); + } + if (IS_LEFTOF (router_id)) + { + install_link_lsdb (router_id, IFINDEX_LEFT); + oi = ospf6_interface_lookup_by_ifindex (IFINDEX_LEFT); + listnode_add (oa->if_list, oi); + } + if (IS_RIGHTOF (router_id)) + { + install_link_lsdb (router_id, IFINDEX_RIGHT); + oi = ospf6_interface_lookup_by_ifindex (IFINDEX_RIGHT); + listnode_add (oa->if_list, oi); + } + if (IS_BOTTOMOF (router_id)) + { + install_link_lsdb (router_id, IFINDEX_BOTTOM); + oi = ospf6_interface_lookup_by_ifindex (IFINDEX_BOTTOM); + listnode_add (oa->if_list, oi); + } + + rets = gettimeofday (&start, (struct timezone *) NULL); + ospf6_spf_calculation (htonl (router_id), oa->spf_table, oa); + rete = gettimeofday (&end, (struct timezone *) NULL); + + if (rets != 0 || rete != 0) + fprintf (stderr, "gettimeofday failed: %s\n", strerror (errno)); + time = diffsec (&end, &start); + + printf ("test spf: root: %lu #LSAs: %d #routes: %d time: %.3f (ms)\n", + (unsigned long) router_id, N * N, oa->spf_table->count, + time * 1000.0); + + for (node = listhead (oa->if_list); node; nextnode (node)) + { + oi = (struct ospf6_interface *) getdata (node); + ospf6_lsdb_delete (oi->lsdb); + oi->interface->info = NULL; + free (oi); + } + list_delete (oa->if_list); + + ospf6_route_table_delete (oa->spf_table); + free (oa); +} + +int +main (int argc, char **argv) +{ + struct ospf6_lsdb *lsdb; + u_int32_t router_id; + struct timeval start, now; + double timeadd; + +#if 0 + malloc_options = "X"; +#endif + + if (argc > 1) + N = atoi (argv[1]); + + lsdb = ospf6_lsdb_create (NULL); + + fprintf (stderr, "Installing %d virtual Router-LSA ... ", N * N); + fflush (stdout); + gettimeofday (&start, NULL); + for (router_id = 0; router_id < N * N; router_id++) + install_router_lsa (router_id, lsdb); + gettimeofday (&now, NULL); + timeadd = diffsec (&now, &start); + fprintf (stderr, "done (%.3f ms) \n", timeadd * 1000.0); + + gettimeofday (&now, NULL); + srandom (now.tv_sec); + + //lsdb_lookup_try (NUMBER_OF_TRIALS, lsdb); + + cmd_init (0); + vty_init (); + if_init (); + zlog_default = openzlog ("ospf6_test", ZLOG_STDERR, ZLOG_OSPF6, + LOG_CONS|LOG_NDELAY|LOG_PERROR|LOG_PID, + LOG_DAEMON); + + OSPF6_DEBUG_SPF_OFF (OSPF6_DEBUG_SPF_PROCESS); + spf_try (0, lsdb); + spf_try ((N / 2) * (N + 1), lsdb); + + return 0; +} + + diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c new file mode 100644 index 0000000..cc4356c --- /dev/null +++ b/ospf6d/ospf6_top.c @@ -0,0 +1,681 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "memory.h" +#include "vty.h" +#include "linklist.h" +#include "prefix.h" +#include "table.h" +#include "thread.h" +#include "command.h" + +#include "ospf6_proto.h" +#include "ospf6_message.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_route.h" +#include "ospf6_zebra.h" + +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" + +#include "ospf6_flood.h" +#include "ospf6_asbr.h" +#include "ospf6_abr.h" +#include "ospf6_intra.h" +#include "ospf6d.h" + +/* global ospf6d variable */ +struct ospf6 *ospf6; + +void +ospf6_top_lsdb_hook_add (struct ospf6_lsa *lsa) +{ + switch (ntohs (lsa->header->type)) + { + case OSPF6_LSTYPE_AS_EXTERNAL: + ospf6_asbr_lsa_add (lsa); + break; + + default: + break; + } +} + +void +ospf6_top_lsdb_hook_remove (struct ospf6_lsa *lsa) +{ + switch (ntohs (lsa->header->type)) + { + case OSPF6_LSTYPE_AS_EXTERNAL: + ospf6_asbr_lsa_remove (lsa); + break; + + default: + break; + } +} + +void +ospf6_top_route_hook_add (struct ospf6_route *route) +{ + ospf6_abr_originate_summary (route); + ospf6_zebra_route_update_add (route); +} + +void +ospf6_top_route_hook_remove (struct ospf6_route *route) +{ + ospf6_abr_originate_summary (route); + ospf6_zebra_route_update_remove (route); +} + +void +ospf6_top_brouter_hook_add (struct ospf6_route *route) +{ + ospf6_abr_examin_brouter (ADV_ROUTER_IN_PREFIX (&route->prefix)); + ospf6_asbr_lsentry_add (route); + ospf6_abr_originate_summary (route); +} + +void +ospf6_top_brouter_hook_remove (struct ospf6_route *route) +{ + ospf6_abr_examin_brouter (ADV_ROUTER_IN_PREFIX (&route->prefix)); + ospf6_asbr_lsentry_remove (route); + ospf6_abr_originate_summary (route); +} + +struct ospf6 * +ospf6_create () +{ + struct ospf6 *o; + + o = XMALLOC (MTYPE_OSPF6_TOP, sizeof (struct ospf6)); + memset (o, 0, sizeof (struct ospf6)); + + /* initialize */ + gettimeofday (&o->starttime, (struct timezone *) NULL); + o->area_list = list_new (); + o->area_list->cmp = ospf6_area_cmp; + o->lsdb = ospf6_lsdb_create (o); + o->lsdb_self = ospf6_lsdb_create (o); + o->lsdb->hook_add = ospf6_top_lsdb_hook_add; + o->lsdb->hook_remove = ospf6_top_lsdb_hook_remove; + + o->route_table = ospf6_route_table_create (); + o->route_table->hook_add = ospf6_top_route_hook_add; + o->route_table->hook_remove = ospf6_top_route_hook_remove; + + o->brouter_table = ospf6_route_table_create (); + o->brouter_table->hook_add = ospf6_top_brouter_hook_add; + o->brouter_table->hook_remove = ospf6_top_brouter_hook_remove; + + o->external_table = ospf6_route_table_create (); + o->external_id_table = route_table_init (); + + return o; +} + +void +ospf6_delete (struct ospf6 *o) +{ + listnode i; + struct ospf6_area *oa; + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + ospf6_area_delete (oa); + } + + ospf6_lsdb_delete (o->lsdb); + ospf6_lsdb_delete (o->lsdb_self); + + ospf6_route_table_delete (o->route_table); + ospf6_route_table_delete (o->brouter_table); + + ospf6_route_table_delete (o->external_table); + route_table_finish (o->external_id_table); + + XFREE (MTYPE_OSPF6_TOP, o); +} + +void +ospf6_enable (struct ospf6 *o) +{ + listnode i; + struct ospf6_area *oa; + + if (CHECK_FLAG (o->flag, OSPF6_DISABLED)) + { + UNSET_FLAG (o->flag, OSPF6_DISABLED); + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + ospf6_area_enable (oa); + } + } +} + +void +ospf6_disable (struct ospf6 *o) +{ + listnode i; + struct ospf6_area *oa; + + if (! CHECK_FLAG (o->flag, OSPF6_DISABLED)) + { + SET_FLAG (o->flag, OSPF6_DISABLED); + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + ospf6_area_disable (oa); + } + + ospf6_lsdb_remove_all (o->lsdb); + ospf6_route_remove_all (o->route_table); + ospf6_route_remove_all (o->brouter_table); + } +} + +int +ospf6_maxage_remover (struct thread *thread) +{ + struct ospf6 *o = (struct ospf6 *) THREAD_ARG (thread); + struct ospf6_area *oa; + struct ospf6_interface *oi; + struct ospf6_neighbor *on; + listnode i, j, k; + + o->maxage_remover = (struct thread *) NULL; + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + for (k = listhead (oi->neighbor_list); k; nextnode (k)) + { + on = (struct ospf6_neighbor *) getdata (k); + if (on->state != OSPF6_NEIGHBOR_EXCHANGE && + on->state != OSPF6_NEIGHBOR_LOADING) + continue; + + return 0; + } + } + } + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + OSPF6_LSDB_MAXAGE_REMOVER (oi->lsdb); + } + OSPF6_LSDB_MAXAGE_REMOVER (oa->lsdb); + } + OSPF6_LSDB_MAXAGE_REMOVER (o->lsdb); + + return 0; +} + +void +ospf6_maxage_remove (struct ospf6 *o) +{ + if (o && ! o->maxage_remover) + o->maxage_remover = thread_add_event (master, ospf6_maxage_remover, o, 0); +} + +/* start ospf6 */ +DEFUN (router_ospf6, + router_ospf6_cmd, + "router ospf6", + ROUTER_STR + OSPF6_STR) +{ + if (ospf6 == NULL) + ospf6 = ospf6_create (); + if (CHECK_FLAG (ospf6->flag, OSPF6_DISABLED)) + ospf6_enable (ospf6); + + /* set current ospf point. */ + vty->node = OSPF6_NODE; + vty->index = ospf6; + + return CMD_SUCCESS; +} + +/* stop ospf6 */ +DEFUN (no_router_ospf6, + no_router_ospf6_cmd, + "no router ospf6", + NO_STR + OSPF6_ROUTER_STR) +{ + if (ospf6 == NULL || CHECK_FLAG (ospf6->flag, OSPF6_DISABLED)) + vty_out (vty, "OSPFv3 is not running%s", VNL); + else + ospf6_disable (ospf6); + + /* return to config node . */ + vty->node = CONFIG_NODE; + vty->index = NULL; + + return CMD_SUCCESS; +} + +/* change Router_ID commands. */ +DEFUN (ospf6_router_id, + ospf6_router_id_cmd, + "router-id A.B.C.D", + "Configure OSPF Router-ID\n" + V4NOTATION_STR) +{ + int ret; + u_int32_t router_id; + struct ospf6 *o; + + o = (struct ospf6 *) vty->index; + + ret = inet_pton (AF_INET, argv[0], &router_id); + if (ret == 0) + { + vty_out (vty, "malformed OSPF Router-ID: %s%s", argv[0], VNL); + return CMD_SUCCESS; + } + + o->router_id = router_id; + return CMD_SUCCESS; +} + +DEFUN (ospf6_interface_area, + ospf6_interface_area_cmd, + "interface IFNAME area A.B.C.D", + "Enable routing on an IPv6 interface\n" + IFNAME_STR + "Specify the OSPF6 area ID\n" + "OSPF6 area ID in IPv4 address notation\n" + ) +{ + struct ospf6 *o; + struct ospf6_area *oa; + struct ospf6_interface *oi; + struct interface *ifp; + u_int32_t area_id; + + o = (struct ospf6 *) vty->index; + + /* find/create ospf6 interface */ + ifp = if_get_by_name (argv[0]); + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + oi = ospf6_interface_create (ifp); + if (oi->area) + { + vty_out (vty, "%s already attached to Area %s%s", + oi->interface->name, oi->area->name, VNL); + return CMD_SUCCESS; + } + + /* parse Area-ID */ + if (inet_pton (AF_INET, argv[1], &area_id) != 1) + { + vty_out (vty, "Invalid Area-ID: %s%s", argv[1], VNL); + return CMD_SUCCESS; + } + + /* find/create ospf6 area */ + oa = ospf6_area_lookup (area_id, o); + if (oa == NULL) + oa = ospf6_area_create (area_id, o); + + /* attach interface to area */ + listnode_add (oa->if_list, oi); /* sort ?? */ + oi->area = oa; + + SET_FLAG (oa->flag, OSPF6_AREA_ENABLE); + + /* start up */ + thread_add_event (master, interface_up, oi, 0); + + /* If the router is ABR, originate summary routes */ + if (ospf6_is_router_abr (o)) + ospf6_abr_enable_area (oa); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_interface_area, + no_ospf6_interface_area_cmd, + "no interface IFNAME area A.B.C.D", + NO_STR + "Disable routing on an IPv6 interface\n" + IFNAME_STR + "Specify the OSPF6 area ID\n" + "OSPF6 area ID in IPv4 address notation\n" + ) +{ + struct ospf6 *o; + struct ospf6_interface *oi; + struct ospf6_area *oa; + struct interface *ifp; + u_int32_t area_id; + + o = (struct ospf6 *) vty->index; + + ifp = if_lookup_by_name (argv[0]); + if (ifp == NULL) + { + vty_out (vty, "No such interface %s%s", argv[0], VNL); + return CMD_SUCCESS; + } + + oi = (struct ospf6_interface *) ifp->info; + if (oi == NULL) + { + vty_out (vty, "Interface %s not enabled%s", ifp->name, VNL); + return CMD_SUCCESS; + } + + /* parse Area-ID */ + if (inet_pton (AF_INET, argv[1], &area_id) != 1) + { + vty_out (vty, "Invalid Area-ID: %s%s", argv[1], VNL); + return CMD_SUCCESS; + } + + if (oi->area->area_id != area_id) + { + vty_out (vty, "Wrong Area-ID: %s is attached to area %s%s", + oi->interface->name, oi->area->name, VNL); + return CMD_SUCCESS; + } + + thread_execute (master, interface_down, oi, 0); + + oa = oi->area; + listnode_delete (oi->area->if_list, oi); + oi->area = (struct ospf6_area *) NULL; + + /* Withdraw inter-area routes from this area, if necessary */ + if (oa->if_list->count == 0) + { + UNSET_FLAG (oa->flag, OSPF6_AREA_ENABLE); + ospf6_abr_disable_area (oa); + } + + return CMD_SUCCESS; +} + +void +ospf6_show (struct vty *vty, struct ospf6 *o) +{ + listnode n; + struct ospf6_area *oa; + char router_id[16], duration[32]; + struct timeval now, running; + + /* process id, router id */ + inet_ntop (AF_INET, &o->router_id, router_id, sizeof (router_id)); + vty_out (vty, " OSPFv3 Routing Process (0) with Router-ID %s%s", + router_id, VNL); + + /* running time */ + gettimeofday (&now, (struct timezone *)NULL); + timersub (&now, &o->starttime, &running); + timerstring (&running, duration, sizeof (duration)); + vty_out (vty, " Running %s%s", duration, VNL); + + /* Redistribute configuration */ + /* XXX */ + + /* LSAs */ + vty_out (vty, " Number of AS scoped LSAs is %u%s", + o->lsdb->count, VNL); + + /* Areas */ + vty_out (vty, " Number of areas in this router is %u%s", + listcount (o->area_list), VNL); + for (n = listhead (o->area_list); n; nextnode (n)) + { + oa = (struct ospf6_area *) getdata (n); + ospf6_area_show (vty, oa); + } +} + +/* show top level structures */ +DEFUN (show_ipv6_ospf6, + show_ipv6_ospf6_cmd, + "show ipv6 ospf6", + SHOW_STR + IP6_STR + OSPF6_STR) +{ + OSPF6_CMD_CHECK_RUNNING (); + + ospf6_show (vty, ospf6); + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_ospf6_route, + show_ipv6_ospf6_route_cmd, + "show ipv6 ospf6 route", + SHOW_STR + IP6_STR + OSPF6_STR + ROUTE_STR + ) +{ + ospf6_route_table_show (vty, argc, argv, ospf6->route_table); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_route, + show_ipv6_ospf6_route_detail_cmd, + "show ipv6 ospf6 route (X:X::X:X|X:X::X:X/M|detail|summary)", + SHOW_STR + IP6_STR + OSPF6_STR + ROUTE_STR + "Specify IPv6 address\n" + "Specify IPv6 prefix\n" + "Detailed information\n" + "Summary of route table\n" + ); + +DEFUN (show_ipv6_ospf6_route_match, + show_ipv6_ospf6_route_match_cmd, + "show ipv6 ospf6 route X:X::X:X/M match", + SHOW_STR + IP6_STR + OSPF6_STR + ROUTE_STR + "Specify IPv6 prefix\n" + "Display routes which match the specified route\n" + ) +{ + char *sargv[CMD_ARGC_MAX]; + int i, sargc; + + /* copy argv to sargv and then append "match" */ + for (i = 0; i < argc; i++) + sargv[i] = argv[i]; + sargc = argc; + sargv[sargc++] = "match"; + sargv[sargc] = NULL; + + ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table); + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_ospf6_route_match_detail, + show_ipv6_ospf6_route_match_detail_cmd, + "show ipv6 ospf6 route X:X::X:X/M match detail", + SHOW_STR + IP6_STR + OSPF6_STR + ROUTE_STR + "Specify IPv6 prefix\n" + "Display routes which match the specified route\n" + "Detailed information\n" + ) +{ + char *sargv[CMD_ARGC_MAX]; + int i, sargc; + + /* copy argv to sargv and then append "match" and "detail" */ + for (i = 0; i < argc; i++) + sargv[i] = argv[i]; + sargc = argc; + sargv[sargc++] = "match"; + sargv[sargc++] = "detail"; + sargv[sargc] = NULL; + + ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_route, + show_ipv6_ospf6_route_type_cmd, + "show ipv6 ospf6 route (intra-area|inter-area|external-1|external-2)", + SHOW_STR + IP6_STR + OSPF6_STR + ROUTE_STR + "Dispaly Intra-Area routes\n" + "Dispaly Inter-Area routes\n" + "Dispaly Type-1 External routes\n" + "Dispaly Type-2 External routes\n" + ); + +DEFUN (show_ipv6_ospf6_route_type_detail, + show_ipv6_ospf6_route_type_detail_cmd, + "show ipv6 ospf6 route (intra-area|inter-area|external-1|external-2) detail", + SHOW_STR + IP6_STR + OSPF6_STR + ROUTE_STR + "Dispaly Intra-Area routes\n" + "Dispaly Inter-Area routes\n" + "Dispaly Type-1 External routes\n" + "Dispaly Type-2 External routes\n" + "Detailed information\n" + ) +{ + char *sargv[CMD_ARGC_MAX]; + int i, sargc; + + /* copy argv to sargv and then append "detail" */ + for (i = 0; i < argc; i++) + sargv[i] = argv[i]; + sargc = argc; + sargv[sargc++] = "detail"; + sargv[sargc] = NULL; + + ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table); + return CMD_SUCCESS; +} + +/* OSPF configuration write function. */ +int +config_write_ospf6 (struct vty *vty) +{ + char router_id[16]; + listnode j, k; + struct ospf6_area *oa; + struct ospf6_interface *oi; + + /* OSPFv6 configuration. */ + if (ospf6 == NULL) + return CMD_SUCCESS; + if (CHECK_FLAG (ospf6->flag, OSPF6_DISABLED)) + return CMD_SUCCESS; + + inet_ntop (AF_INET, &ospf6->router_id, router_id, sizeof (router_id)); + vty_out (vty, "router ospf6%s", VNL); + vty_out (vty, " router-id %s%s", router_id, VNL); + + ospf6_redistribute_config_write (vty); + ospf6_area_config_write (vty); + + for (j = listhead (ospf6->area_list); j; nextnode (j)) + { + oa = (struct ospf6_area *) getdata (j); + for (k = listhead (oa->if_list); k; nextnode (k)) + { + oi = (struct ospf6_interface *) getdata (k); + vty_out (vty, " interface %s area %s%s", + oi->interface->name, oa->name, VNL); + } + } + vty_out (vty, "!%s", VNL); + return 0; +} + +/* OSPF6 node structure. */ +struct cmd_node ospf6_node = +{ + OSPF6_NODE, + "%s(config-ospf6)# ", + 1 /* VTYSH */ +}; + +/* Install ospf related commands. */ +void +ospf6_top_init () +{ + /* Install ospf6 top node. */ + install_node (&ospf6_node, config_write_ospf6); + + install_element (VIEW_NODE, &show_ipv6_ospf6_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_cmd); + install_element (CONFIG_NODE, &router_ospf6_cmd); + + install_element (VIEW_NODE, &show_ipv6_ospf6_route_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_route_detail_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_route_match_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_route_match_detail_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_route_type_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_route_type_detail_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_detail_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_detail_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_type_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_type_detail_cmd); + + install_default (OSPF6_NODE); + install_element (OSPF6_NODE, &ospf6_router_id_cmd); + install_element (OSPF6_NODE, &ospf6_interface_area_cmd); + install_element (OSPF6_NODE, &no_ospf6_interface_area_cmd); + install_element (OSPF6_NODE, &no_router_ospf6_cmd); +} + + diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h new file mode 100644 index 0000000..d831d94 --- /dev/null +++ b/ospf6d/ospf6_top.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_TOP_H +#define OSPF6_TOP_H + +#include "routemap.h" + +/* OSPFv3 top level data structure */ +struct ospf6 +{ + /* my router id */ + u_int32_t router_id; + + /* start time */ + struct timeval starttime; + + /* list of areas */ + list area_list; + + /* AS scope link state database */ + struct ospf6_lsdb *lsdb; + struct ospf6_lsdb *lsdb_self; + + struct ospf6_route_table *route_table; + struct ospf6_route_table *brouter_table; + + struct ospf6_route_table *external_table; + struct route_table *external_id_table; + u_int32_t external_id; + + /* redistribute route-map */ + struct + { + char *name; + struct route_map *map; + } rmap[ZEBRA_ROUTE_MAX]; + + u_char flag; + + struct thread *maxage_remover; +}; + +#define OSPF6_DISABLED 0x01 + +/* global pointer for OSPF top data structure */ +extern struct ospf6 *ospf6; + +/* prototypes */ +void ospf6_top_init (); + +void ospf6_maxage_remove (struct ospf6 *o); + +#endif /* OSPF6_TOP_H */ + + diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c new file mode 100644 index 0000000..d5ddad9 --- /dev/null +++ b/ospf6d/ospf6_zebra.c @@ -0,0 +1,669 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "log.h" +#include "vty.h" +#include "command.h" +#include "prefix.h" +#include "stream.h" +#include "zclient.h" +#include "memory.h" + +#include "ospf6_proto.h" +#include "ospf6_top.h" +#include "ospf6_interface.h" +#include "ospf6_route.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_asbr.h" +#include "ospf6_zebra.h" +#include "ospf6d.h" + +unsigned char conf_debug_ospf6_zebra = 0; + +/* information about zebra. */ +struct zclient *zclient = NULL; + +/* redistribute function */ +void +ospf6_zebra_redistribute (int type) +{ + if (zclient->redist[type]) + return; + zclient->redist[type] = 1; + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type); +} + +void +ospf6_zebra_no_redistribute (int type) +{ + if (! zclient->redist[type]) + return; + zclient->redist[type] = 0; + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type); +} + +/* Inteface addition message from zebra. */ +int +ospf6_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read (zclient->ibuf); + if (IS_OSPF6_DEBUG_ZEBRA (RECV)) + zlog_info ("Zebra Interface add: %s index %d mtu %d", + ifp->name, ifp->ifindex, ifp->mtu); + ospf6_interface_if_add (ifp); + return 0; +} + +int +ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length) +{ +#if 0 + struct interface *ifp; + + ifp = zebra_interface_delete_read (zclient->ibuf); + if (IS_OSPF6_DEBUG_ZEBRA (RECV)) + zlog_info ("Zebra Interface delete: %s index %d mtu %d", + ifp->name, ifp->ifindex, ifp->mtu); + + ospf6_interface_if_del (ifp); +#endif /*0*/ + return 0; +} + +int +ospf6_zebra_if_state_update (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_state_read (zclient->ibuf); + if (IS_OSPF6_DEBUG_ZEBRA (RECV)) + zlog_info ("Zebra Interface state change: " + "%s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + ospf6_interface_state_update (ifp); + return 0; +} + +int +ospf6_zebra_if_address_update_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + char buf[128]; + + c = zebra_interface_address_add_read (zclient->ibuf); + if (c == NULL) + return 0; + + if (IS_OSPF6_DEBUG_ZEBRA (RECV)) + zlog_info ("Zebra Interface address add: %s %5s %s/%d", + c->ifp->name, prefix_family_str (c->address), + inet_ntop (c->address->family, &c->address->u.prefix, + buf, sizeof (buf)), c->address->prefixlen); + + if (c->address->family == AF_INET6) + ospf6_interface_connected_route_update (c->ifp); + + return 0; +} + +int +ospf6_zebra_if_address_update_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + char buf[128]; + + c = zebra_interface_address_delete_read (zclient->ibuf); + if (c == NULL) + return 0; + + if (IS_OSPF6_DEBUG_ZEBRA (RECV)) + zlog_info ("Zebra Interface address delete: %s %5s %s/%d", + c->ifp->name, prefix_family_str (c->address), + inet_ntop (c->address->family, &c->address->u.prefix, + buf, sizeof (buf)), c->address->prefixlen); + + if (c->address->family == AF_INET6) + ospf6_interface_connected_route_update (c->ifp); + + return 0; +} + + + +const char *zebra_route_name[ZEBRA_ROUTE_MAX] = + { "System", "Kernel", "Connect", "Static", "RIP", "RIPng", "OSPF", + "OSPF6", "BGP" }; + +const char *zebra_route_abname[ZEBRA_ROUTE_MAX] = + { "X", "K", "C", "S", "r", "R", "o", "O", "B" }; + +int +ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv6 api; + unsigned long ifindex; + struct prefix_ipv6 p; + struct in6_addr *nexthop; + + s = zclient->ibuf; + ifindex = 0; + nexthop = NULL; + memset (&api, 0, sizeof (api)); + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv6 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + nexthop = (struct in6_addr *) + malloc (api.nexthop_num * sizeof (struct in6_addr)); + stream_get (nexthop, s, api.nexthop_num * sizeof (struct in6_addr)); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + else + api.distance = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + if (IS_OSPF6_DEBUG_ZEBRA (RECV)) + { + char prefixstr[128], nexthopstr[128]; + prefix2str ((struct prefix *)&p, prefixstr, sizeof (prefixstr)); + if (nexthop) + inet_ntop (AF_INET6, nexthop, nexthopstr, sizeof (nexthopstr)); + else + snprintf (nexthopstr, sizeof (nexthopstr), "::"); + + zlog_info ("Zebra Receive route %s: %s %s nexthop %s ifindex %ld", + (command == ZEBRA_IPV6_ROUTE_ADD ? "add" : "delete"), + zebra_route_name[api.type], prefixstr, nexthopstr, ifindex); + } + + if (command == ZEBRA_IPV6_ROUTE_ADD) + ospf6_asbr_redistribute_add (api.type, ifindex, (struct prefix *) &p, + api.nexthop_num, nexthop); + else + ospf6_asbr_redistribute_remove (api.type, ifindex, (struct prefix *) &p); + + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + free (nexthop); + + return 0; +} + + + + +DEFUN (show_zebra, + show_zebra_cmd, + "show zebra", + SHOW_STR + "Zebra information\n") +{ + int i; + if (zclient == NULL) + { + vty_out (vty, "Not connected to zebra%s", VNL); + return CMD_SUCCESS; + } + + vty_out (vty, "Zebra Infomation%s", VNL); + vty_out (vty, " enable: %d fail: %d%s", + zclient->enable, zclient->fail, VNL); + vty_out (vty, " redistribute default: %d%s", zclient->redist_default, + VNL); + vty_out (vty, " redistribute:"); + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (zclient->redist[i]) + vty_out (vty, " %s", zebra_route_name[i]); + } + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +DEFUN (router_zebra, + router_zebra_cmd, + "router zebra", + "Enable a routing process\n" + "Make connection to zebra daemon\n") +{ + vty->node = ZEBRA_NODE; + zclient->enable = 1; + zclient_start (zclient); + return CMD_SUCCESS; +} + +DEFUN (no_router_zebra, + no_router_zebra_cmd, + "no router zebra", + NO_STR + "Configure routing process\n" + "Disable connection to zebra daemon\n") +{ + zclient->enable = 0; + zclient_stop (zclient); + return CMD_SUCCESS; +} + +/* Zebra configuration write function. */ +int +config_write_ospf6_zebra (struct vty *vty) +{ + if (! zclient->enable) + { + vty_out (vty, "no router zebra%s", VNL); + vty_out (vty, "!%s", VNL); + } + else if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) + { + vty_out (vty, "router zebra%s", VNL); + vty_out (vty, " no redistribute ospf6%s", VNL); + vty_out (vty, "!%s", VNL); + } + return 0; +} + +/* Zebra node structure. */ +struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "%s(config-zebra)# ", +}; + +#define ADD 0 +#define REM 1 +static void +ospf6_zebra_route_update (int type, struct ospf6_route *request) +{ + struct zapi_ipv6 api; + char buf[64], ifname[IFNAMSIZ]; + int nhcount; + struct in6_addr **nexthops; + unsigned int *ifindexes; + int i, ret = 0; + struct prefix_ipv6 *dest; + + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + { + prefix2str (&request->prefix, buf, sizeof (buf)); + zlog_info ("Send %s route: %s", + (type == REM ? "remove" : "add"), buf); + } + + if (zclient->sock < 0) + { + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + zlog_info (" Not connected to Zebra"); + return; + } + + if (request->path.origin.adv_router == ospf6->router_id && + (request->path.type == OSPF6_PATH_TYPE_EXTERNAL1 || + request->path.type == OSPF6_PATH_TYPE_EXTERNAL2)) + { + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + zlog_info (" Ignore self-originated external route"); + return; + } + + /* If removing is the best path and if there's another path, + treat this request as add the secondary path */ + if (type == REM && ospf6_route_is_best (request) && + request->next && ospf6_route_is_same (request, request->next)) + { + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + zlog_info (" Best-path removal resulted Sencondary addition"); + type = ADD; + request = request->next; + } + + /* Only the best path will be sent to zebra. */ + if (! ospf6_route_is_best (request)) + { + /* this is not preferred best route, ignore */ + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + zlog_info (" Ignore non-best route"); + return; + } + + nhcount = 0; + for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) + if (ospf6_nexthop_is_set (&request->nexthop[i])) + nhcount++; + + if (nhcount == 0) + { + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + zlog_info (" No nexthop, ignore"); + return; + } + + /* allocate memory for nexthop_list */ + nexthops = XCALLOC (MTYPE_OSPF6_OTHER, + nhcount * sizeof (struct in6_addr *)); + if (nexthops == NULL) + { + zlog_warn ("Can't send route to zebra: malloc failed"); + return; + } + + /* allocate memory for ifindex_list */ + ifindexes = XCALLOC (MTYPE_OSPF6_OTHER, + nhcount * sizeof (unsigned int)); + if (ifindexes == NULL) + { + zlog_warn ("Can't send route to zebra: malloc failed"); + XFREE (MTYPE_OSPF6_OTHER, nexthops); + return; + } + + for (i = 0; i < nhcount; i++) + { + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + { + inet_ntop (AF_INET6, &request->nexthop[i].address, + buf, sizeof (buf)); + if_indextoname (request->nexthop[i].ifindex, ifname); + zlog_info (" nexthop: %s%%%s(%d)", buf, ifname, + request->nexthop[i].ifindex); + } + nexthops[i] = &request->nexthop[i].address; + ifindexes[i] = request->nexthop[i].ifindex; + } + + api.type = ZEBRA_ROUTE_OSPF6; + api.flags = 0; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = nhcount; + api.nexthop = nexthops; + SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = nhcount; + api.ifindex = ifindexes; + SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); + api.metric = (request->path.metric_type == 2 ? + request->path.cost_e2 : request->path.cost); + + dest = (struct prefix_ipv6 *) &request->prefix; + if (type == REM) + ret = zapi_ipv6_delete (zclient, dest, &api); + else + ret = zapi_ipv6_add (zclient, dest, &api); + + if (ret < 0) + zlog_err ("zapi_ipv6_%s () failed: %s", + (type == REM ? "delete" : "add"), strerror (errno)); + + XFREE (MTYPE_OSPF6_OTHER, nexthops); + XFREE (MTYPE_OSPF6_OTHER, ifindexes); + + return; +} + +void +ospf6_zebra_route_update_add (struct ospf6_route *request) +{ + if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) + { + ospf6->route_table->hook_add = NULL; + ospf6->route_table->hook_remove = NULL; + return; + } + ospf6_zebra_route_update (ADD, request); +} + +void +ospf6_zebra_route_update_remove (struct ospf6_route *request) +{ + if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) + { + ospf6->route_table->hook_add = NULL; + ospf6->route_table->hook_remove = NULL; + return; + } + ospf6_zebra_route_update (REM, request); +} + +DEFUN (redistribute_ospf6, + redistribute_ospf6_cmd, + "redistribute ospf6", + "Redistribute control\n" + "OSPF6 route\n") +{ + struct ospf6_route *route; + + if (zclient->redist[ZEBRA_ROUTE_OSPF6]) + return CMD_SUCCESS; + + zclient->redist[ZEBRA_ROUTE_OSPF6] = 1; + + if (ospf6 == NULL) + return CMD_SUCCESS; + + /* send ospf6 route to zebra route table */ + for (route = ospf6_route_head (ospf6->route_table); route; + route = ospf6_route_next (route)) + ospf6_zebra_route_update_add (route); + + ospf6->route_table->hook_add = ospf6_zebra_route_update_add; + ospf6->route_table->hook_remove = ospf6_zebra_route_update_remove; + + return CMD_SUCCESS; +} + +DEFUN (no_redistribute_ospf6, + no_redistribute_ospf6_cmd, + "no redistribute ospf6", + NO_STR + "Redistribute control\n" + "OSPF6 route\n") +{ + struct ospf6_route *route; + + if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) + return CMD_SUCCESS; + + zclient->redist[ZEBRA_ROUTE_OSPF6] = 0; + + if (ospf6 == NULL) + return CMD_SUCCESS; + + ospf6->route_table->hook_add = NULL; + ospf6->route_table->hook_remove = NULL; + + /* withdraw ospf6 route from zebra route table */ + for (route = ospf6_route_head (ospf6->route_table); route; + route = ospf6_route_next (route)) + ospf6_zebra_route_update_remove (route); + + return CMD_SUCCESS; +} + +void +ospf6_zebra_init () +{ + /* Allocate zebra structure. */ + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_OSPF6); + zclient->interface_add = ospf6_zebra_if_add; + zclient->interface_delete = ospf6_zebra_if_del; + zclient->interface_up = ospf6_zebra_if_state_update; + zclient->interface_down = ospf6_zebra_if_state_update; + zclient->interface_address_add = ospf6_zebra_if_address_update_add; + zclient->interface_address_delete = ospf6_zebra_if_address_update_delete; + zclient->ipv4_route_add = NULL; + zclient->ipv4_route_delete = NULL; + zclient->ipv6_route_add = ospf6_zebra_read_ipv6; + zclient->ipv6_route_delete = ospf6_zebra_read_ipv6; + + /* redistribute connected route by default */ + /* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */ + + /* Install zebra node. */ + install_node (&zebra_node, config_write_ospf6_zebra); + + /* Install command element for zebra node. */ + install_element (VIEW_NODE, &show_zebra_cmd); + install_element (ENABLE_NODE, &show_zebra_cmd); + install_element (CONFIG_NODE, &router_zebra_cmd); + install_element (CONFIG_NODE, &no_router_zebra_cmd); + + install_default (ZEBRA_NODE); + install_element (ZEBRA_NODE, &redistribute_ospf6_cmd); + install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd); + + return; +} + +/* Debug */ + +DEFUN (debug_ospf6_zebra_sendrecv, + debug_ospf6_zebra_sendrecv_cmd, + "debug ospf6 zebra (send|recv)", + DEBUG_STR + OSPF6_STR + "Debug connection between zebra\n" + "Debug Sending zebra\n" + "Debug Receiving zebra\n" + ) +{ + unsigned char level = 0; + + if (argc) + { + if (! strncmp (argv[0], "s", 1)) + level = OSPF6_DEBUG_ZEBRA_SEND; + else if (! strncmp (argv[0], "r", 1)) + level = OSPF6_DEBUG_ZEBRA_RECV; + } + else + level = OSPF6_DEBUG_ZEBRA_SEND | OSPF6_DEBUG_ZEBRA_RECV; + + OSPF6_DEBUG_ZEBRA_ON (level); + return CMD_SUCCESS; +} + +ALIAS (debug_ospf6_zebra_sendrecv, + debug_ospf6_zebra_cmd, + "debug ospf6 zebra", + DEBUG_STR + OSPF6_STR + "Debug connection between zebra\n" + ); + + +DEFUN (no_debug_ospf6_zebra_sendrecv, + no_debug_ospf6_zebra_sendrecv_cmd, + "no debug ospf6 zebra (send|recv)", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug connection between zebra\n" + "Debug Sending zebra\n" + "Debug Receiving zebra\n" + ) +{ + unsigned char level = 0; + + if (argc) + { + if (! strncmp (argv[0], "s", 1)) + level = OSPF6_DEBUG_ZEBRA_SEND; + else if (! strncmp (argv[0], "r", 1)) + level = OSPF6_DEBUG_ZEBRA_RECV; + } + else + level = OSPF6_DEBUG_ZEBRA_SEND | OSPF6_DEBUG_ZEBRA_RECV; + + OSPF6_DEBUG_ZEBRA_OFF (level); + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf6_zebra_sendrecv, + no_debug_ospf6_zebra_cmd, + "no debug ospf6 zebra", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug connection between zebra\n" + ); + +int +config_write_ospf6_debug_zebra (struct vty *vty) +{ + if (IS_OSPF6_DEBUG_ZEBRA (SEND) && IS_OSPF6_DEBUG_ZEBRA (RECV)) + vty_out (vty, "debug ospf6 zebra%s", VNL); + else + { + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + vty_out (vty, "debug ospf6 zebra send%s", VNL); + if (IS_OSPF6_DEBUG_ZEBRA (RECV)) + vty_out (vty, "debug ospf6 zebra recv%s", VNL); + } + return 0; +} + +void +install_element_ospf6_debug_zebra () +{ + install_element (ENABLE_NODE, &debug_ospf6_zebra_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_zebra_cmd); + install_element (ENABLE_NODE, &debug_ospf6_zebra_sendrecv_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_zebra_sendrecv_cmd); + install_element (CONFIG_NODE, &debug_ospf6_zebra_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_zebra_cmd); + install_element (CONFIG_NODE, &debug_ospf6_zebra_sendrecv_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_zebra_sendrecv_cmd); +} + + diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h new file mode 100644 index 0000000..fb9877b --- /dev/null +++ b/ospf6d/ospf6_zebra.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6_ZEBRA_H +#define OSPF6_ZEBRA_H + +#include "zclient.h" + +/* Debug option */ +extern unsigned char conf_debug_ospf6_zebra; +#define OSPF6_DEBUG_ZEBRA_SEND 0x01 +#define OSPF6_DEBUG_ZEBRA_RECV 0x02 +#define OSPF6_DEBUG_ZEBRA_ON(level) \ + (conf_debug_ospf6_zebra |= level) +#define OSPF6_DEBUG_ZEBRA_OFF(level) \ + (conf_debug_ospf6_zebra &= ~(level)) +#define IS_OSPF6_DEBUG_ZEBRA(e) \ + (conf_debug_ospf6_zebra & OSPF6_DEBUG_ZEBRA_ ## e) + +extern struct zclient *zclient; + +void ospf6_zebra_route_update_add (struct ospf6_route *request); +void ospf6_zebra_route_update_remove (struct ospf6_route *request); + +void ospf6_zebra_redistribute (int); +void ospf6_zebra_no_redistribute (int); +#define ospf6_zebra_is_redistribute(type) \ + (zclient->redist[type]) +void ospf6_zebra_init (); + +int config_write_ospf6_debug_zebra (struct vty *vty); +void install_element_ospf6_debug_zebra (); + +#endif /*OSPF6_ZEBRA_H*/ + diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c new file mode 100644 index 0000000..450774e --- /dev/null +++ b/ospf6d/ospf6d.c @@ -0,0 +1,1939 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "linklist.h" +#include "vty.h" +#include "command.h" + +#include "ospf6_proto.h" +#include "ospf6_network.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_message.h" +#include "ospf6_route.h" +#include "ospf6_zebra.h" +#include "ospf6_spf.h" +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" +#include "ospf6_intra.h" +#include "ospf6_asbr.h" +#include "ospf6_abr.h" +#include "ospf6_flood.h" +#include "ospf6d.h" + +#ifdef HAVE_SNMP +#include "ospf6_snmp.h" +#endif /*HAVE_SNMP*/ + +char ospf6_daemon_version[] = OSPF6_DAEMON_VERSION; + +void +ospf6_debug () +{ +} + +struct route_node * +route_prev (struct route_node *node) +{ + struct route_node *end; + struct route_node *prev = NULL; + + end = node; + node = node->parent; + if (node) + route_lock_node (node); + while (node) + { + prev = node; + node = route_next (node); + if (node == end) + { + route_unlock_node (node); + node = NULL; + } + } + route_unlock_node (end); + if (prev) + route_lock_node (prev); + + return prev; +} + + +/* show database functions */ +DEFUN (show_version_ospf6, + show_version_ospf6_cmd, + "show version ospf6", + SHOW_STR + "Displays ospf6d version\n" + ) +{ + vty_out (vty, "Zebra OSPF6d Version: %s%s", + ospf6_daemon_version, VNL); + + return CMD_SUCCESS; +} + +struct cmd_node debug_node = +{ + DEBUG_NODE, + "", + 1 /* VTYSH */ +}; + +int +config_write_ospf6_debug (struct vty *vty) +{ + config_write_ospf6_debug_message (vty); + config_write_ospf6_debug_lsa (vty); + config_write_ospf6_debug_zebra (vty); + config_write_ospf6_debug_interface (vty); + config_write_ospf6_debug_neighbor (vty); + config_write_ospf6_debug_spf (vty); + config_write_ospf6_debug_route (vty); + config_write_ospf6_debug_asbr (vty); + config_write_ospf6_debug_abr (vty); + config_write_ospf6_debug_flood (vty); + vty_out (vty, "!%s", VNL); + return 0; +} + +#define AREA_LSDB_TITLE_FORMAT \ + "%s Area Scoped Link State Database (Area %s)%s%s" +#define IF_LSDB_TITLE_FORMAT \ + "%s I/F Scoped Link State Database (I/F %s in Area %s)%s%s" +#define AS_LSDB_TITLE_FORMAT \ + "%s AS Scoped Link State Database%s%s" + +static int +parse_show_level (int argc, char **argv) +{ + int level = 0; + if (argc) + { + if (! strncmp (argv[0], "de", 2)) + level = OSPF6_LSDB_SHOW_LEVEL_DETAIL; + else if (! strncmp (argv[0], "du", 2)) + level = OSPF6_LSDB_SHOW_LEVEL_DUMP; + else if (! strncmp (argv[0], "in", 2)) + level = OSPF6_LSDB_SHOW_LEVEL_INTERNAL; + } + else + level = OSPF6_LSDB_SHOW_LEVEL_NORMAL; + return level; +} + +static u_int16_t +parse_type_spec (int argc, char **argv) +{ + u_int16_t type = 0; + assert (argc); + if (! strcmp (argv[0], "router")) + type = htons (OSPF6_LSTYPE_ROUTER); + else if (! strcmp (argv[0], "network")) + type = htons (OSPF6_LSTYPE_NETWORK); + else if (! strcmp (argv[0], "as-external")) + type = htons (OSPF6_LSTYPE_AS_EXTERNAL); + else if (! strcmp (argv[0], "intra-prefix")) + type = htons (OSPF6_LSTYPE_INTRA_PREFIX); + else if (! strcmp (argv[0], "inter-router")) + type = htons (OSPF6_LSTYPE_INTER_ROUTER); + else if (! strcmp (argv[0], "inter-prefix")) + type = htons (OSPF6_LSTYPE_INTER_PREFIX); + else if (! strcmp (argv[0], "link")) + type = htons (OSPF6_LSTYPE_LINK); + return type; +} + +DEFUN (show_ipv6_ospf6_database, + show_ipv6_ospf6_database_cmd, + "show ipv6 ospf6 database", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + + OSPF6_CMD_CHECK_RUNNING (); + + level = parse_show_level (argc, argv); + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, NULL, NULL, oa->lsdb); + } + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, NULL, NULL, oi->lsdb); + } + } + + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, NULL, NULL, o->lsdb); + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database, + show_ipv6_ospf6_database_detail_cmd, + "show ipv6 ospf6 database (detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +DEFUN (show_ipv6_ospf6_database_type, + show_ipv6_ospf6_database_type_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + u_int16_t type = 0; + + OSPF6_CMD_CHECK_RUNNING (); + + type = parse_type_spec (argc, argv); + argc--; + argv++; + level = parse_show_level (argc, argv); + + switch (OSPF6_LSA_SCOPE (type)) + { + case OSPF6_SCOPE_AREA: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, NULL, NULL, oa->lsdb); + } + break; + + case OSPF6_SCOPE_LINKLOCAL: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, NULL, NULL, oi->lsdb); + } + } + break; + + case OSPF6_SCOPE_AS: + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, NULL, NULL, o->lsdb); + break; + + default: + assert (0); + break; + } + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database_type, + show_ipv6_ospf6_database_type_detail_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +DEFUN (show_ipv6_ospf6_database_id, + show_ipv6_ospf6_database_id_cmd, + "show ipv6 ospf6 database * A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Any Link state Type\n" + "Specify Link state ID as IPv4 address notation\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + u_int32_t id = 0; + + OSPF6_CMD_CHECK_RUNNING (); + + if ((inet_pton (AF_INET, argv[0], &id)) != 1) + { + vty_out (vty, "Link State ID is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + level = parse_show_level (argc, argv); + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, &id, NULL, oa->lsdb); + } + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, &id, NULL, oi->lsdb); + } + } + + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, &id, NULL, o->lsdb); + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database_id, + show_ipv6_ospf6_database_id_detail_cmd, + "show ipv6 ospf6 database * A.B.C.D " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Any Link state Type\n" + "Specify Link state ID as IPv4 address notation\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +ALIAS (show_ipv6_ospf6_database_id, + show_ipv6_ospf6_database_linkstate_id_cmd, + "show ipv6 ospf6 database linkstate-id A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Search by Link state ID\n" + "Specify Link state ID as IPv4 address notation\n" + ); + +ALIAS (show_ipv6_ospf6_database_id, + show_ipv6_ospf6_database_linkstate_id_detail_cmd, + "show ipv6 ospf6 database linkstate-id A.B.C.D " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Search by Link state ID\n" + "Specify Link state ID as IPv4 address notation\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +DEFUN (show_ipv6_ospf6_database_router, + show_ipv6_ospf6_database_router_cmd, + "show ipv6 ospf6 database * * A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Any Link state Type\n" + "Any Link state ID\n" + "Specify Advertising Router as IPv4 address notation\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + u_int32_t adv_router = 0; + + OSPF6_CMD_CHECK_RUNNING (); + + if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) + { + vty_out (vty, "Advertising Router is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + level = parse_show_level (argc, argv); + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, oa->lsdb); + } + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, oi->lsdb); + } + } + + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, o->lsdb); + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database_router, + show_ipv6_ospf6_database_router_detail_cmd, + "show ipv6 ospf6 database * * A.B.C.D " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Any Link state Type\n" + "Any Link state ID\n" + "Specify Advertising Router as IPv4 address notation\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +ALIAS (show_ipv6_ospf6_database_router, + show_ipv6_ospf6_database_adv_router_cmd, + "show ipv6 ospf6 database adv-router A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Search by Advertising Router\n" + "Specify Advertising Router as IPv4 address notation\n" + ); + +ALIAS (show_ipv6_ospf6_database_router, + show_ipv6_ospf6_database_adv_router_detail_cmd, + "show ipv6 ospf6 database adv-router A.B.C.D " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Search by Advertising Router\n" + "Specify Advertising Router as IPv4 address notation\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +DEFUN (show_ipv6_ospf6_database_type_id, + show_ipv6_ospf6_database_type_id_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Specify Link state ID as IPv4 address notation\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + u_int16_t type = 0; + u_int32_t id = 0; + + OSPF6_CMD_CHECK_RUNNING (); + + type = parse_type_spec (argc, argv); + argc--; + argv++; + + if ((inet_pton (AF_INET, argv[0], &id)) != 1) + { + vty_out (vty, "Link state ID is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + level = parse_show_level (argc, argv); + + switch (OSPF6_LSA_SCOPE (type)) + { + case OSPF6_SCOPE_AREA: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, NULL, oa->lsdb); + } + break; + + case OSPF6_SCOPE_LINKLOCAL: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, NULL, oi->lsdb); + } + } + break; + + case OSPF6_SCOPE_AS: + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, NULL, o->lsdb); + break; + + default: + assert (0); + break; + } + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database_type_id, + show_ipv6_ospf6_database_type_id_detail_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) A.B.C.D " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Specify Link state ID as IPv4 address notation\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +ALIAS (show_ipv6_ospf6_database_type_id, + show_ipv6_ospf6_database_type_linkstate_id_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) linkstate-id A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Search by Link state ID\n" + "Specify Link state ID as IPv4 address notation\n" + ); + +ALIAS (show_ipv6_ospf6_database_type_id, + show_ipv6_ospf6_database_type_linkstate_id_detail_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) linkstate-id A.B.C.D " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Search by Link state ID\n" + "Specify Link state ID as IPv4 address notation\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +DEFUN (show_ipv6_ospf6_database_type_router, + show_ipv6_ospf6_database_type_router_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) * A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Any Link state ID\n" + "Specify Advertising Router as IPv4 address notation\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + u_int16_t type = 0; + u_int32_t adv_router = 0; + + OSPF6_CMD_CHECK_RUNNING (); + + type = parse_type_spec (argc, argv); + argc--; + argv++; + + if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) + { + vty_out (vty, "Advertising Router is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + level = parse_show_level (argc, argv); + + switch (OSPF6_LSA_SCOPE (type)) + { + case OSPF6_SCOPE_AREA: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, NULL, &adv_router, oa->lsdb); + } + break; + + case OSPF6_SCOPE_LINKLOCAL: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, NULL, &adv_router, oi->lsdb); + } + } + break; + + case OSPF6_SCOPE_AS: + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, NULL, &adv_router, o->lsdb); + break; + + default: + assert (0); + break; + } + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database_type_router, + show_ipv6_ospf6_database_type_router_detail_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) * A.B.C.D " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Any Link state ID\n" + "Specify Advertising Router as IPv4 address notation\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +ALIAS (show_ipv6_ospf6_database_type_router, + show_ipv6_ospf6_database_type_adv_router_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) adv-router A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Search by Advertising Router\n" + "Specify Advertising Router as IPv4 address notation\n" + ); + +ALIAS (show_ipv6_ospf6_database_type_router, + show_ipv6_ospf6_database_type_adv_router_detail_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) adv-router A.B.C.D " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Search by Advertising Router\n" + "Specify Advertising Router as IPv4 address notation\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +DEFUN (show_ipv6_ospf6_database_id_router, + show_ipv6_ospf6_database_id_router_cmd, + "show ipv6 ospf6 database * A.B.C.D A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Any Link state Type\n" + "Specify Link state ID as IPv4 address notation\n" + "Specify Advertising Router as IPv4 address notation\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + u_int32_t id = 0; + u_int32_t adv_router = 0; + + OSPF6_CMD_CHECK_RUNNING (); + + if ((inet_pton (AF_INET, argv[0], &id)) != 1) + { + vty_out (vty, "Link state ID is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + + if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) + { + vty_out (vty, "Advertising Router is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + level = parse_show_level (argc, argv); + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, oa->lsdb); + } + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, oi->lsdb); + } + } + + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, o->lsdb); + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database_id_router, + show_ipv6_ospf6_database_id_router_detail_cmd, + "show ipv6 ospf6 database * A.B.C.D A.B.C.D " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Any Link state Type\n" + "Specify Link state ID as IPv4 address notation\n" + "Specify Advertising Router as IPv4 address notation\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +DEFUN (show_ipv6_ospf6_database_adv_router_linkstate_id, + show_ipv6_ospf6_database_adv_router_linkstate_id_cmd, + "show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Search by Advertising Router\n" + "Specify Advertising Router as IPv4 address notation\n" + "Search by Link state ID\n" + "Specify Link state ID as IPv4 address notation\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + u_int32_t id = 0; + u_int32_t adv_router = 0; + + OSPF6_CMD_CHECK_RUNNING (); + + if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) + { + vty_out (vty, "Advertising Router is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + + if ((inet_pton (AF_INET, argv[0], &id)) != 1) + { + vty_out (vty, "Link state ID is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + level = parse_show_level (argc, argv); + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, oa->lsdb); + } + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, oi->lsdb); + } + } + + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, o->lsdb); + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database_adv_router_linkstate_id, + show_ipv6_ospf6_database_adv_router_linkstate_id_detail_cmd, + "show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Search by Advertising Router\n" + "Specify Advertising Router as IPv4 address notation\n" + "Search by Link state ID\n" + "Specify Link state ID as IPv4 address notation\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +DEFUN (show_ipv6_ospf6_database_type_id_router, + show_ipv6_ospf6_database_type_id_router_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) A.B.C.D A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Specify Link state ID as IPv4 address notation\n" + "Specify Advertising Router as IPv4 address notation\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + u_int16_t type = 0; + u_int32_t id = 0; + u_int32_t adv_router = 0; + + OSPF6_CMD_CHECK_RUNNING (); + + type = parse_type_spec (argc, argv); + argc--; + argv++; + + if ((inet_pton (AF_INET, argv[0], &id)) != 1) + { + vty_out (vty, "Link state ID is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + + if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) + { + vty_out (vty, "Advertising Router is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + level = parse_show_level (argc, argv); + + switch (OSPF6_LSA_SCOPE (type)) + { + case OSPF6_SCOPE_AREA: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oa->lsdb); + } + break; + + case OSPF6_SCOPE_LINKLOCAL: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oi->lsdb); + } + } + break; + + case OSPF6_SCOPE_AS: + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, &adv_router, o->lsdb); + break; + + default: + assert (0); + break; + } + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database_type_id_router, + show_ipv6_ospf6_database_type_id_router_detail_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) A.B.C.D A.B.C.D " + "(dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Specify Link state ID as IPv4 address notation\n" + "Specify Advertising Router as IPv4 address notation\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +DEFUN (show_ipv6_ospf6_database_type_adv_router_linkstate_id, + show_ipv6_ospf6_database_type_adv_router_linkstate_id_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) " + "adv-router A.B.C.D linkstate-id A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Search by Advertising Router\n" + "Specify Advertising Router as IPv4 address notation\n" + "Search by Link state ID\n" + "Specify Link state ID as IPv4 address notation\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + u_int16_t type = 0; + u_int32_t id = 0; + u_int32_t adv_router = 0; + + OSPF6_CMD_CHECK_RUNNING (); + + type = parse_type_spec (argc, argv); + argc--; + argv++; + + if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) + { + vty_out (vty, "Advertising Router is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + + if ((inet_pton (AF_INET, argv[0], &id)) != 1) + { + vty_out (vty, "Link state ID is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + level = parse_show_level (argc, argv); + + switch (OSPF6_LSA_SCOPE (type)) + { + case OSPF6_SCOPE_AREA: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oa->lsdb); + } + break; + + case OSPF6_SCOPE_LINKLOCAL: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oi->lsdb); + } + } + break; + + case OSPF6_SCOPE_AS: + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, &adv_router, o->lsdb); + break; + + default: + assert (0); + break; + } + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database_type_adv_router_linkstate_id, + show_ipv6_ospf6_database_type_adv_router_linkstate_id_detail_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) " + "adv-router A.B.C.D linkstate-id A.B.C.D " + "(dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Search by Advertising Router\n" + "Specify Advertising Router as IPv4 address notation\n" + "Search by Link state ID\n" + "Specify Link state ID as IPv4 address notation\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +DEFUN (show_ipv6_ospf6_database_self_originated, + show_ipv6_ospf6_database_self_originated_cmd, + "show ipv6 ospf6 database self-originated", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Self-originated LSAs\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + u_int32_t adv_router = 0; + + OSPF6_CMD_CHECK_RUNNING (); + + level = parse_show_level (argc, argv); + + adv_router = o->router_id; + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, oa->lsdb); + } + + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, oi->lsdb); + } + } + + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, o->lsdb); + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database_self_originated, + show_ipv6_ospf6_database_self_originated_detail_cmd, + "show ipv6 ospf6 database self-originated " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Self-originated LSAs\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ) + +DEFUN (show_ipv6_ospf6_database_type_self_originated, + show_ipv6_ospf6_database_type_self_originated_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) self-originated", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Display Self-originated LSAs\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + u_int16_t type = 0; + u_int32_t adv_router = 0; + + OSPF6_CMD_CHECK_RUNNING (); + + type = parse_type_spec (argc, argv); + argc--; + argv++; + level = parse_show_level (argc, argv); + + adv_router = o->router_id; + + switch (OSPF6_LSA_SCOPE (type)) + { + case OSPF6_SCOPE_AREA: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, NULL, &adv_router, oa->lsdb); + } + break; + + case OSPF6_SCOPE_LINKLOCAL: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, NULL, &adv_router, oi->lsdb); + } + } + break; + + case OSPF6_SCOPE_AS: + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, NULL, &adv_router, o->lsdb); + break; + + default: + assert (0); + break; + } + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database_type_self_originated, + show_ipv6_ospf6_database_type_self_originated_detail_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) self-originated " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Display Self-originated LSAs\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +DEFUN (show_ipv6_ospf6_database_type_self_originated_linkstate_id, + show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) self-originated " + "linkstate-id A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Display Self-originated LSAs\n" + "Search by Link state ID\n" + "Specify Link state ID as IPv4 address notation\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + u_int16_t type = 0; + u_int32_t adv_router = 0; + u_int32_t id = 0; + + OSPF6_CMD_CHECK_RUNNING (); + + type = parse_type_spec (argc, argv); + argc--; + argv++; + + if ((inet_pton (AF_INET, argv[0], &id)) != 1) + { + vty_out (vty, "Link State ID is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + level = parse_show_level (argc, argv); + + adv_router = o->router_id; + + switch (OSPF6_LSA_SCOPE (type)) + { + case OSPF6_SCOPE_AREA: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oa->lsdb); + } + break; + + case OSPF6_SCOPE_LINKLOCAL: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oi->lsdb); + } + } + break; + + case OSPF6_SCOPE_AS: + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, &adv_router, o->lsdb); + break; + + default: + assert (0); + break; + } + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database_type_self_originated_linkstate_id, + show_ipv6_ospf6_database_type_self_originated_linkstate_id_detail_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) self-originated " + "linkstate-id A.B.C.D (detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Display Self-originated LSAs\n" + "Search by Link state ID\n" + "Specify Link state ID as IPv4 address notation\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + +DEFUN (show_ipv6_ospf6_database_type_id_self_originated, + show_ipv6_ospf6_database_type_id_self_originated_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) A.B.C.D self-originated", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Specify Link state ID as IPv4 address notation\n" + "Display Self-originated LSAs\n" + ) +{ + int level; + listnode i, j; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_interface *oi; + u_int16_t type = 0; + u_int32_t adv_router = 0; + u_int32_t id = 0; + + OSPF6_CMD_CHECK_RUNNING (); + + type = parse_type_spec (argc, argv); + argc--; + argv++; + + if ((inet_pton (AF_INET, argv[0], &id)) != 1) + { + vty_out (vty, "Link State ID is not parsable: %s%s", + argv[0], VNL); + return CMD_SUCCESS; + } + + argc--; + argv++; + level = parse_show_level (argc, argv); + + adv_router = o->router_id; + + switch (OSPF6_LSA_SCOPE (type)) + { + case OSPF6_SCOPE_AREA: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oa->lsdb); + } + break; + + case OSPF6_SCOPE_LINKLOCAL: + for (i = listhead (o->area_list); i; nextnode (i)) + { + oa = (struct ospf6_area *) getdata (i); + for (j = listhead (oa->if_list); j; nextnode (j)) + { + oi = (struct ospf6_interface *) getdata (j); + vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, + oi->interface->name, oa->name, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oi->lsdb); + } + } + break; + + case OSPF6_SCOPE_AS: + vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); + ospf6_lsdb_show (vty, level, &type, &id, &adv_router, o->lsdb); + break; + + default: + assert (0); + break; + } + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_database_type_id_self_originated, + show_ipv6_ospf6_database_type_id_self_originated_detail_cmd, + "show ipv6 ospf6 database " + "(router|network|inter-prefix|inter-router|as-external|" + "group-membership|type-7|link|intra-prefix) A.B.C.D self-originated " + "(detail|dump|internal)", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Display Router LSAs\n" + "Display Network LSAs\n" + "Display Inter-Area-Prefix LSAs\n" + "Display Inter-Area-Router LSAs\n" + "Display As-External LSAs\n" + "Display Group-Membership LSAs\n" + "Display Type-7 LSAs\n" + "Display Link LSAs\n" + "Display Intra-Area-Prefix LSAs\n" + "Display Self-originated LSAs\n" + "Search by Link state ID\n" + "Specify Link state ID as IPv4 address notation\n" + "Display details of LSAs\n" + "Dump LSAs\n" + "Display LSA's internal information\n" + ); + + +DEFUN (show_ipv6_ospf6_border_routers, + show_ipv6_ospf6_border_routers_cmd, + "show ipv6 ospf6 border-routers", + SHOW_STR + IP6_STR + OSPF6_STR + "Display routing table for ABR and ASBR\n" + ) +{ + u_int32_t adv_router; + void (*showfunc) (struct vty *, struct ospf6_route *); + struct ospf6_route *ro; + struct prefix prefix; + + OSPF6_CMD_CHECK_RUNNING (); + + if (argc && ! strcmp ("detail", argv[0])) + { + showfunc = ospf6_route_show_detail; + argc--; + argv++; + } + else + showfunc = ospf6_brouter_show; + + if (argc) + { + if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) + { + vty_out (vty, "Router ID is not parsable: %s%s", argv[0], VNL); + return CMD_SUCCESS; + } + + ospf6_linkstate_prefix (adv_router, 0, &prefix); + ro = ospf6_route_lookup (&prefix, ospf6->brouter_table); + ospf6_route_show_detail (vty, ro); + return CMD_SUCCESS; + } + + if (showfunc == ospf6_brouter_show) + ospf6_brouter_show_header (vty); + + for (ro = ospf6_route_head (ospf6->brouter_table); ro; + ro = ospf6_route_next (ro)) + (*showfunc) (vty, ro); + + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_border_routers, + show_ipv6_ospf6_border_routers_detail_cmd, + "show ipv6 ospf6 border-routers (A.B.C.D|detail)", + SHOW_STR + IP6_STR + OSPF6_STR + "Display routing table for ABR and ASBR\n" + "Specify Router-ID\n" + "Display Detail\n" + ); + +DEFUN (show_ipv6_ospf6_linkstate, + show_ipv6_ospf6_linkstate_cmd, + "show ipv6 ospf6 linkstate", + SHOW_STR + IP6_STR + OSPF6_STR + "Display linkstate routing table\n" + ) +{ + listnode node; + struct ospf6_area *oa; + + for (node = listhead (ospf6->area_list); node; nextnode (node)) + { + oa = OSPF6_AREA (getdata (node)); + + vty_out (vty, "%s SPF Result in Area %s%s%s", + VNL, oa->name, VNL, VNL); + ospf6_linkstate_table_show (vty, argc, argv, oa->spf_table); + } + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +ALIAS (show_ipv6_ospf6_linkstate, + show_ipv6_ospf6_linkstate_router_cmd, + "show ipv6 ospf6 linkstate router A.B.C.D", + SHOW_STR + IP6_STR + OSPF6_STR + "Display linkstate routing table\n" + "Display Router Entry\n" + "Specify Router ID as IPv4 address notation\n" + ); + +ALIAS (show_ipv6_ospf6_linkstate, + show_ipv6_ospf6_linkstate_network_cmd, + "show ipv6 ospf6 linkstate network A.B.C.D A.B.C.D", + SHOW_STR + IP6_STR + OSPF6_STR + "Display linkstate routing table\n" + "Display Network Entry\n" + "Specify Router ID as IPv4 address notation\n" + "Specify Link state ID as IPv4 address notation\n" + ); + +DEFUN (show_ipv6_ospf6_linkstate_detail, + show_ipv6_ospf6_linkstate_detail_cmd, + "show ipv6 ospf6 linkstate detail", + SHOW_STR + IP6_STR + OSPF6_STR + "Display linkstate routing table\n" + ) +{ + char *sargv[CMD_ARGC_MAX]; + int i, sargc; + listnode node; + struct ospf6_area *oa; + + /* copy argv to sargv and then append "detail" */ + for (i = 0; i < argc; i++) + sargv[i] = argv[i]; + sargc = argc; + sargv[sargc++] = "detail"; + sargv[sargc] = NULL; + + for (node = listhead (ospf6->area_list); node; nextnode (node)) + { + oa = OSPF6_AREA (getdata (node)); + + vty_out (vty, "%s SPF Result in Area %s%s%s", + VNL, oa->name, VNL, VNL); + ospf6_linkstate_table_show (vty, sargc, sargv, oa->spf_table); + } + + vty_out (vty, "%s", VNL); + return CMD_SUCCESS; +} + +/* Install ospf related commands. */ +void +ospf6_init () +{ + ospf6_top_init (); + ospf6_area_init (); + ospf6_interface_init (); + ospf6_neighbor_init (); + ospf6_zebra_init (); + + ospf6_lsa_init (); + ospf6_spf_init (); + ospf6_intra_init (); + ospf6_asbr_init (); + ospf6_abr_init (); + +#ifdef HAVE_SNMP + ospf6_snmp_init (); +#endif /*HAVE_SNMP*/ + + install_node (&debug_node, config_write_ospf6_debug); + + install_element_ospf6_debug_message (); + install_element_ospf6_debug_lsa (); + install_element_ospf6_debug_interface (); + install_element_ospf6_debug_neighbor (); + install_element_ospf6_debug_zebra (); + install_element_ospf6_debug_spf (); + install_element_ospf6_debug_route (); + install_element_ospf6_debug_asbr (); + install_element_ospf6_debug_abr (); + install_element_ospf6_debug_flood (); + + install_element (VIEW_NODE, &show_version_ospf6_cmd); + install_element (ENABLE_NODE, &show_version_ospf6_cmd); + + install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_detail_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_border_routers_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_border_routers_detail_cmd); + + install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_router_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_network_cmd); + install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_detail_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_router_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_network_cmd); + install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_detail_cmd); + +#define INSTALL(n,c) \ + install_element (n ## _NODE, &show_ipv6_ospf6_ ## c); + + INSTALL (VIEW, database_cmd); + INSTALL (VIEW, database_detail_cmd); + INSTALL (VIEW, database_type_cmd); + INSTALL (VIEW, database_type_detail_cmd); + INSTALL (VIEW, database_id_cmd); + INSTALL (VIEW, database_id_detail_cmd); + INSTALL (VIEW, database_linkstate_id_cmd); + INSTALL (VIEW, database_linkstate_id_detail_cmd); + INSTALL (VIEW, database_router_cmd); + INSTALL (VIEW, database_router_detail_cmd); + INSTALL (VIEW, database_adv_router_cmd); + INSTALL (VIEW, database_adv_router_detail_cmd); + INSTALL (VIEW, database_type_id_cmd); + INSTALL (VIEW, database_type_id_detail_cmd); + INSTALL (VIEW, database_type_linkstate_id_cmd); + INSTALL (VIEW, database_type_linkstate_id_detail_cmd); + INSTALL (VIEW, database_type_router_cmd); + INSTALL (VIEW, database_type_router_detail_cmd); + INSTALL (VIEW, database_type_adv_router_cmd); + INSTALL (VIEW, database_type_adv_router_detail_cmd); + INSTALL (VIEW, database_adv_router_linkstate_id_cmd); + INSTALL (VIEW, database_adv_router_linkstate_id_detail_cmd); + INSTALL (VIEW, database_id_router_cmd); + INSTALL (VIEW, database_id_router_detail_cmd); + INSTALL (VIEW, database_type_id_router_cmd); + INSTALL (VIEW, database_type_id_router_detail_cmd); + INSTALL (VIEW, database_type_adv_router_linkstate_id_cmd); + INSTALL (VIEW, database_type_adv_router_linkstate_id_detail_cmd); + INSTALL (VIEW, database_self_originated_cmd); + INSTALL (VIEW, database_self_originated_detail_cmd); + INSTALL (VIEW, database_type_self_originated_cmd); + INSTALL (VIEW, database_type_self_originated_detail_cmd); + INSTALL (VIEW, database_type_id_self_originated_cmd); + INSTALL (VIEW, database_type_id_self_originated_detail_cmd); + INSTALL (VIEW, database_type_self_originated_linkstate_id_cmd); + INSTALL (VIEW, database_type_self_originated_linkstate_id_detail_cmd); + INSTALL (VIEW, database_type_id_self_originated_cmd); + INSTALL (VIEW, database_type_id_self_originated_detail_cmd); + + INSTALL (ENABLE, database_cmd); + INSTALL (ENABLE, database_detail_cmd); + INSTALL (ENABLE, database_type_cmd); + INSTALL (ENABLE, database_type_detail_cmd); + INSTALL (ENABLE, database_id_cmd); + INSTALL (ENABLE, database_id_detail_cmd); + INSTALL (ENABLE, database_linkstate_id_cmd); + INSTALL (ENABLE, database_linkstate_id_detail_cmd); + INSTALL (ENABLE, database_router_cmd); + INSTALL (ENABLE, database_router_detail_cmd); + INSTALL (ENABLE, database_adv_router_cmd); + INSTALL (ENABLE, database_adv_router_detail_cmd); + INSTALL (ENABLE, database_type_id_cmd); + INSTALL (ENABLE, database_type_id_detail_cmd); + INSTALL (ENABLE, database_type_linkstate_id_cmd); + INSTALL (ENABLE, database_type_linkstate_id_detail_cmd); + INSTALL (ENABLE, database_type_router_cmd); + INSTALL (ENABLE, database_type_router_detail_cmd); + INSTALL (ENABLE, database_type_adv_router_cmd); + INSTALL (ENABLE, database_type_adv_router_detail_cmd); + INSTALL (ENABLE, database_adv_router_linkstate_id_cmd); + INSTALL (ENABLE, database_adv_router_linkstate_id_detail_cmd); + INSTALL (ENABLE, database_id_router_cmd); + INSTALL (ENABLE, database_id_router_detail_cmd); + INSTALL (ENABLE, database_type_id_router_cmd); + INSTALL (ENABLE, database_type_id_router_detail_cmd); + INSTALL (ENABLE, database_type_adv_router_linkstate_id_cmd); + INSTALL (ENABLE, database_type_adv_router_linkstate_id_detail_cmd); + INSTALL (ENABLE, database_self_originated_cmd); + INSTALL (ENABLE, database_self_originated_detail_cmd); + INSTALL (ENABLE, database_type_self_originated_cmd); + INSTALL (ENABLE, database_type_self_originated_detail_cmd); + INSTALL (ENABLE, database_type_id_self_originated_cmd); + INSTALL (ENABLE, database_type_id_self_originated_detail_cmd); + INSTALL (ENABLE, database_type_self_originated_linkstate_id_cmd); + INSTALL (ENABLE, database_type_self_originated_linkstate_id_detail_cmd); + INSTALL (ENABLE, database_type_id_self_originated_cmd); + INSTALL (ENABLE, database_type_id_self_originated_detail_cmd); + + /* Make ospf protocol socket. */ + ospf6_serv_sock (); + thread_add_read (master, ospf6_receive, NULL, ospf6_sock); +} + + diff --git a/ospf6d/ospf6d.conf.sample b/ospf6d/ospf6d.conf.sample new file mode 100644 index 0000000..0a6ddb7 --- /dev/null +++ b/ospf6d/ospf6d.conf.sample @@ -0,0 +1,52 @@ +! +! Zebra configuration saved from vty +! 2003/11/28 00:49:49 +! +hostname ospf6d@plant +password zebra +log stdout +service advanced-vty +! +debug ospf6 neighbor state +! +interface fxp0 + ipv6 ospf6 cost 1 + ipv6 ospf6 hello-interval 10 + ipv6 ospf6 dead-interval 40 + ipv6 ospf6 retransmit-interval 5 + ipv6 ospf6 priority 0 + ipv6 ospf6 transmit-delay 1 + ipv6 ospf6 instance-id 0 +! +interface lo0 + ipv6 ospf6 cost 1 + ipv6 ospf6 hello-interval 10 + ipv6 ospf6 dead-interval 40 + ipv6 ospf6 retransmit-interval 5 + ipv6 ospf6 priority 1 + ipv6 ospf6 transmit-delay 1 + ipv6 ospf6 instance-id 0 +! +router ospf6 + router-id 255.1.1.1 + redistribute static route-map static-ospf6 + interface fxp0 area 0.0.0.0 +! +access-list access4 permit 127.0.0.1/32 +! +ipv6 access-list access6 permit 3ffe:501::/32 +ipv6 access-list access6 permit 2001:200::/48 +ipv6 access-list access6 permit ::1/128 +! +ipv6 prefix-list test-prefix seq 1000 deny any +! +route-map static-ospf6 permit 10 + match ipv6 address prefix-list test-prefix + set metric-type type-2 + set metric 2000 +! +line vty + access-class access4 + ipv6 access-class access6 + exec-timeout 0 0 +! diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h new file mode 100644 index 0000000..6fcf200 --- /dev/null +++ b/ospf6d/ospf6d.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2003 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef OSPF6D_H +#define OSPF6D_H + +#define OSPF6_DAEMON_VERSION "0.9.7o" + +/* global variables */ +extern int errno; +extern struct thread_master *master; + +#ifdef INRIA_IPV6 +#ifndef IPV6_PKTINFO +#define IPV6_PKTINFO IPV6_RECVPKTINFO +#endif /* IPV6_PKTINFO */ +#endif /* INRIA_IPV6 */ + +/* Historical for KAME. */ +#ifndef IPV6_JOIN_GROUP +#ifdef IPV6_ADD_MEMBERSHIP +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#endif /* IPV6_ADD_MEMBERSHIP. */ +#ifdef IPV6_JOIN_MEMBERSHIP +#define IPV6_JOIN_GROUP IPV6_JOIN_MEMBERSHIP +#endif /* IPV6_JOIN_MEMBERSHIP. */ +#endif /* ! IPV6_JOIN_GROUP*/ + +#ifndef IPV6_LEAVE_GROUP +#ifdef IPV6_DROP_MEMBERSHIP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP +#endif /* IPV6_DROP_MEMBERSHIP */ +#endif /* ! IPV6_LEAVE_GROUP */ + +/* cast macro */ +#define OSPF6_PROCESS(x) ((struct ospf6 *) (x)) +#define OSPF6_AREA(x) ((struct ospf6_area *) (x)) +#define OSPF6_INTERFACE(x) ((struct ospf6_interface *) (x)) +#define OSPF6_NEIGHBOR(x) ((struct ospf6_neighbor *) (x)) + +/* operation on timeval structure */ +#ifndef timerclear +#define timerclear(a) (a)->tv_sec = (tvp)->tv_usec = 0 +#endif /*timerclear*/ +#ifndef timersub +#define timersub(a, b, res) \ + do { \ + (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((res)->tv_usec < 0) \ + { \ + (res)->tv_sec--; \ + (res)->tv_usec += 1000000; \ + } \ + } while (0) +#endif /*timersub*/ +#define timerstring(tv, buf, size) \ + do { \ + if ((tv)->tv_sec / 60 / 60 / 24) \ + snprintf (buf, size, "%ldd%02ld:%02ld:%02ld", \ + (tv)->tv_sec / 60 / 60 / 24, \ + (tv)->tv_sec / 60 / 60 % 24, \ + (tv)->tv_sec / 60 % 60, \ + (tv)->tv_sec % 60); \ + else \ + snprintf (buf, size, "%02ld:%02ld:%02ld", \ + (tv)->tv_sec / 60 / 60 % 24, \ + (tv)->tv_sec / 60 % 60, \ + (tv)->tv_sec % 60); \ + } while (0) +#define timerstring_local(tv, buf, size) \ + do { \ + int ret; \ + struct tm *tm; \ + tm = localtime (&(tv)->tv_sec); \ + ret = strftime (buf, size, "%Y/%m/%d %H:%M:%S", tm); \ + if (ret == 0) \ + zlog_warn ("strftime error"); \ + } while (0) + +/* for commands */ +#define OSPF6_AREA_STR "Area information\n" +#define OSPF6_AREA_ID_STR "Area ID (as an IPv4 notation)\n" +#define OSPF6_SPF_STR "Shortest Path First tree information\n" +#define OSPF6_ROUTER_ID_STR "Specify Router-ID\n" +#define OSPF6_LS_ID_STR "Specify Link State ID\n" + +#define VNL VTY_NEWLINE +#define OSPF6_CMD_CHECK_RUNNING() \ + if (ospf6 == NULL) \ + { \ + vty_out (vty, "OSPFv3 is not running%s", VTY_NEWLINE); \ + return CMD_SUCCESS; \ + } + + +/* Function Prototypes */ +struct route_node *route_prev (struct route_node *node); + +void ospf6_debug (); +void ospf6_init (); + +#endif /* OSPF6D_H */ + + diff --git a/ospfd/ChangeLog b/ospfd/ChangeLog new file mode 100644 index 0000000..88bec84 --- /dev/null +++ b/ospfd/ChangeLog @@ -0,0 +1,3027 @@ +2005-09-08 Kunihiro Ishiguro + + * ospf_lsdb.c: Include "log.h". + +2005-06-21 Yasuhiro Ohara + + * ospf_packet.c (ospf_ls_upd): fix memory leak when NSSA enabled. + reported by [zebra 22449]. + +2005-06-02 Akihiro Mizutani + + * ospf_interface.c (ospf_if_cleanup): nbr_self added to neighbor list + when interface was changed from Down to Up. + +2005-06-01 Akihiro Mizutani + + * ospf_ism.c (ospf_elect_bdr/ospf_elect_dr): Fix DR election bug. + +2005-05-26 Yasuhiro Ohara + + * ospf_lsa.c (ospf_lsa_different): Asserting LSA length without + byte order conversion is fixed. + +2005-05-26 Yasuhiro Ohara + + * ospf_abr.c (ospf_abr_update_aggregate): Cost of aggregated route + for an area is fixed (from smallest to largest). + +2005-05-10 Kunihiro Ishiguro + + * ospf_packet.c (ospf_check_md5_digest): Suggested by Donald Sharp + + +2004-11-24 Yasuhiro Ohara + + * ospf_snmp.c: ospf_nbr_nbma_lookup_next() added for SNMP. + +2003-12-20 Kunihiro Ishiguro + + * ospf_packet.c (ospf_recv_packet): Merge fix of OpenBSD problem. + +2003-08-23 Hasso Tepper + + * OSPF NSSA fixes. + +2003-01-23 Masahiko Endo + + * ospf_ism.c: NSM event schedule bug fix. + +2002-10-30 Greg Troxel + + * ospf_packet.c (ospf_make_md5_digest): MD5 length fix. + +2002-10-23 endo@suri.co.jp (Masahiko Endo) + + * ospf_opaque.c: Update Opaque LSA patch. + +2002-10-23 Ralph Keller + + * ospf_vty.c (show_ip_ospf_database): Fix CLI parse. + +2002-10-23 Juris Kalnins + + * ospf_interface.c (ospf_if_stream_unset): When write queue + becomes empty stop write timer. + +2002-10-10 Greg Troxel + + * ospf_packet.c (ospf_check_md5_digest): Change >= to > to make it + conform to RFC. + +2002-07-25 Roger Venning + + * ospf_lsa.c: Point-to-Multipoint support is added. + +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2002-06-19 Kunihiro Ishiguro + + * ospf_spf.c (ospf_nexthop_calculation): Add NULL set to oi and + check of l2. Reported by: Daniel Drown + (ospf_lsa_has_link): LSA Length calculation fix. Reported by: + Paul Jakma . + + * ospfd.c (ospf_if_update): Fix nextnode reference bug. Reported + by: juris@mt.lv. + +2002-01-21 Kunihiro Ishiguro + + * ospfd.c: Merge [zebra 11445] Masahiko ENDO's Opaque-LSA support. + +2001-08-27 Kunihiro Ishiguro + + * ospf_interface.c (ospf_add_to_if): Use /32 address to register + OSPF interface information. + (ospf_delete_from_if): Likewise. + + * ospf_zebra.c (ospf_interface_address_delete): Likewise. + +2001-08-23 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_redistribute_unset): When redistribute type + is OSPF, do not unset redistribute flag. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-12 Kunihiro Ishiguro + + * ospfd.c (ospf_config_write): auto-cost reference-bandwidth + configuration display. + +2001-07-24 David Watson + + * ospf_spf.c (ospf_spf_next): Modify ospf_vertex_add_parent to + check for an existing link before connecting the parent and child. + ospf_nexthop_calculation is also modified to check for duplicate + entries when copying from the parent. Finally, ospf_spf_next + removes duplicates when it merges two equal cost candidates. + +2001-07-23 itojun@iijlab.net + + * ospfd.c (show_ip_ospf_neighbor): Check ospf_top before use it + [zebra 8549]. + +2001-07-23 Kunihiro Ishiguro + + * ospf_packet.c (ospf_write): Remove defined(__OpenBSD__) to make + it work on OpenBSD. + +2001-06-26 Kunihiro Ishiguro + + * ospf_zebra.c (config_write_ospf_default_metric): Display + default-metric configuration. + +2001-06-18 Kunihiro Ishiguro + + * ospf_ia.h (OSPF_EXAMINE_SUMMARIES_ALL): Remove old macros. + +2001-05-28 Kunihiro Ishiguro + + * ospf_snmp.c (ospfIfEntry): Fix interface lookup bug to avoid + crush. + (ospfIfMetricEntry): Likewise. + +2001-03-18 Kunihiro Ishiguro + + * ospf_packet.c (ospf_read): Fix typo. Reported by: "Jen B + Lin'Kova" . + +2001-03-15 Gleb Natapov + + * ospf_interface.c (ip_ospf_network): Set interface parameter. + (interface_config_write): Add check for OSPF_IFTYPE_LOOPBACK. + + * ospf_zebra.c (ospf_interface_add): Set interface parameter. + +2001-02-21 Kunihiro Ishiguro + + * ospf_packet.c (ospf_recv_packet): Solaris also need to add + (iph.ip_hl << 2) to iph.ip_len. + +2001-02-09 Kunihiro Ishiguro + + * ospfd.h (OSPF_LS_REFRESH_TIME): Fix OSPF_LS_REFRESH_TIME value. + Suggested by: David Watson . + + * ospf_zebra.c (zebra_init): Remove zebra node. + + * ospfd.c (ospf_area_range_set): Function name is changed from + ospf_ara_range_cmd. + (ospf_area_range_unset): New function which separated from DEFUN. + New commands are added: + "no area A.B.C.D range A.B.C.D/M advertise" + "no area <0-4294967295> range A.B.C.D/M advertise" + "no area A.B.C.D range A.B.C.D/M not-advertise" + "no area <0-4294967295> range A.B.C.D/M not-advertise" + + * ospf_lsa.c (ospf_lsa_more_recent): Fix previous change. + +2001-02-08 Matthew Grant + + * ospf_network.c (ospf_if_add_allspfrouters): Use + setsockopt_multicast_ipv4. + (ospf_if_drop_allspfrouters): Likewise. + + * ospf_lsa.c (ospf_router_lsa_install): Add rt_recalc flag. + (ospf_network_lsa_install): Likewise. + (ospf_summary_lsa_install): Likewise. + (ospf_summary_asbr_lsa_install): Likewise. + (ospf_external_lsa_install): Likewise. + (ospf_lsa_install): Call ospf_lsa_different to check this LSA is + new one or not. + +2001-02-08 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_interface_delete): Do not free interface + structure when ospfd receive interface delete message to support + pseudo interface. + +2001-02-01 Dick Glasspool + + * ospfd.c (area_range_notadvertise): Change area range "suppress" + command to "not-advertise". + + * ospfd.h (OSPF_LS_REFRESH_TIME): Change OSPF_LS_REFRESH_TIME from + 1800 to 60. + + * ospf_abr.c (ospf_abr_update_aggregate): When update_aggregate is + updating the area-range, the lowest cost is now saved. + + * ospf_lsa.c (ospf_lsa_more_recent): Routing to compare sequence + numbers rather than creating overflow during calculation. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-31 Kunihiro Ishiguro + + * ospf_packet.c (ospf_db_desc_proc): Do not continue process when + NSM_SeqNumberMismatch is scheduled. + (ospf_ls_req): Free ls_upd when return from this function. + (ospf_ls_upd_timer): When update list is empty do not call + ospf_ls_upd_send(). Suggested by: endo@suri.co.jp (Masahiko + Endo). + +2001-01-26 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_maxage_flood): Flood LSA when it reaches + MaxAge. RFC2328 Section 14. + (ospf_maxage_lsa_remover): Call above function during removing + MaxAge LSA. + +2001-01-26 Dick Glasspool + + * ospf_flood.c (ospf_flood_through_as): Function is updated for + NSSA Translations now done at ospf_abr.c with no change in P-bit. + + * ospf_lsa.c (ospf_get_nssa_ip): Get 1st IP connection for Forward + Addr. + (ospf_install_flood_nssa): Leave Type-7 LSA at Lock Count = 2. + + * ospf_ase.c (ospf_ase_calculate_route): Add debug codes. + + * ospf_abr.c (ospf_abr_translate_nssa): Recalculate LSA checksum. + + * ospf_packet.h (OSPF_SEND_PACKET_LOOP): Added for test packet. + + * ospf_dump.c (ospf_lsa_type_msg): Add OSPF_GROUP_MEMBER_LSA and + OSPF_AS_NSSA_LSA. + + * ospfd.c (data_injection): Function to inject LSA. This is + debugging command. + +2001-01-11 Kunihiro Ishiguro + + * ospf_route.c (ospf_route_match_same): Remove function. + (ospf_route_match_same_new): Renamed to ospf_route_match_same. + + * ospf_zebra.c (ospf_interface_address_delete): Add check for + oi->address. Suggested by Matthew Grant + . + (ospf_zebra_add): Remove function. + (ospf_zebra_add_multipath): Rename to ospf_zebra_add. + + * ospf_interface.c: Remove HAVE_IF_PSEUDO part. + + * ospf_zebra.c: Likewise. + +2001-01-10 Kunihiro Ishiguro + + * ospf_ase.c: Remove OLD_RIB part. + + * ospf_route.c: Likewise. + + * zebra-0.90 is released. + + * ospf_packet.c (ospf_recv_packet): Use ip_len adjestment code to + NetBSD. + +2001-01-09 Kunihiro Ishiguro + + * ospf_route.c (ospf_route_delete): Use + ospf_zebra_delete_multipath. + +2001-01-09 Matthew Grant + + * ospf_interface.c (ospf_if_cleanup): Function name is renamed + from ospf_if_free(). Rewrite whole procudure to support primary + address deletion. + + * ospf_zebra.c (ospf_interface_address_delete): Add primary + address deletion process. + +2001-01-09 Kunihiro Ishiguro + + * ospf_packet.c (ospf_recv_packet): OpenBSD has same ip_len + treatment like FreeBSD. + +2001-01-09 endo@suri.co.jp (Masahiko Endo) + + * ospf_packet.c (ospf_recv_packet): FreeBSD kernel network code + strips IP header size from receiving IP Packet. So we adjust + ip_len to whole IP packet size by adding IP header size. + +2001-01-08 endo@suri.co.jp (Masahiko Endo) + + * ospf_network.c (ospf_serv_sock): When socket() is failed return + immediately. + (ospf_serv_sock): Close socket when it is not used. + + * ospf_packet.c (ospf_write): Set sin_len when HAVE_SIN_LEN is + defined. + (ospf_write): When bind is fined, close sock. + +2001-01-07 Gleb Natapov + + * ospf_zebra.c (ospf_interface_state_up): Fixes coredump that + appears when you try to configure bandwidth on the ppp interface + that is not yet configured in ospfd. + +2001-01-07 Michael Rozhavsky + + * ospf_route.c (show_ip_ospf_route_external): "show ip ospf route" + will print nexthops for AS-external routes. + + * ospf_ase.c (ospf_ase_route_match_same): New function to compare + ASE route under multipath environment. + (ospf_ase_compare_tables): Likewise. + +2001-01-01 Kunihiro Ishiguro + + * ospfd.h (OSPF_VTYSH_PATH): Change "/tmp/ospfd" to "/tmp/.ospfd". + +2000-12-28 Kunihiro Ishiguro + + * ospf_route.c (ospf_route_install): Install multipath information + to zebra daemon. + + * ospf_zebra.c (ospf_zebra_add_multipath): Function for passing + multipath information to zebra daemon. + +2000-12-25 Dick Glasspool + + * ospf_packet.c (ospf_write): Call ospf_packet_delete when sendto + fail. + (DISCARD_LSA): Add argument N for logging point of DISCARD_LSA is + called. + + * ospf_lsa.c (ospf_external_lsa_refresh): NSSA install_flood will + leave Type-7 LSA at Lock Count = 2. + + * ospf_flood.c (ospf_flood_through): Flood_though_as updated for + NSSA no P-bit off during Area flooding, but P-bit is turned off + for mulitple NSSA AS flooding. + + * ospf_ase.c (ospf_ase_calculate_timer): Added calculations for + Type-7 LSDB. + + * ospf_abr.c (ospf_abr_translate_nssa): Removed one unlock call. + (ospf_abr_announce_nssa_defaults): Corrected Debug from EVENT to + NSSA. + +2000-12-25 Michael Rozhavsky + + * ospf_zebra.c (ospf_zebra_read_ipv4): Checking the age of the + found LSA and if the LSA is MAXAGE we should call refresh instead + of originate. + +2000-12-18 Dick Glasspool + + * ospf_abr.c: Removed redundant "...flood" in + announce_network_to_area(). Repaired nssa Unlock by using + discard. + + * ospf_packet.c: Removed old NSSA translate during mk_ls_update. + + * ospfd.c: Free up all data bases including NSSA. + + * ospf_lsa.c: Now allow removal of XLATE LSA's Check in + discard_callback. Added routine to get ip addr from within the + ifp. + + * ospf_flood.c: Now set Forward Address for outgoing Type-7. + + * ospf_lsa.h: Added prototype for the below. struct in_addr + ospf_get_ip_from_ifp (struct interface *ifp). + +2000-12-14 Gleb Natapov + + * ospf_packet.c (ospf_recv_packet): New OSPF pakcet read method. + Now maximum packet length may be 65535 bytes (maximum IP packet + length). + + * ospf_interface.c (ospf_if_stream_set): Don't make input buffer. + + * ospfd.c (config_write_network_area): Remove unnecessary area + lookup code. + +2000-12-13 Kunihiro Ishiguro + + * ospf_packet.c (ospf_read): Accept packet bigger than MTU value. + +2000-12-13 Gleb Natapov + + * ospfd.c (config_write_network_area): Fix bug in + config_write_network_area function. + +2000-12-12 Gleb Natapov + + * ospf_abr.c (ospf_abr_announce_network_to_area): Make Summary + LSA's origination and refreshment as same as other type of LSA. + + * ospf_lsa.c (ospf_summary_lsa_refresh): Return struct ospf_lsa *. + + * ospf_lsa.c (ospf_summary_asbr_lsa_refresh): Likewise. + +2000-12-08 Dick Glasspool + + The bulk of NSSA changes are contained herein; This version will + require manual setting of "always" for NSSA Translator, and will + not perform aggregation yet. + + * ospf_dump.c: "debug ospf nssa" is added. + + * ospf_dump.h: Likewise. + + * ospf_packet.c (ospf_hello): Display router ID on Bad NSSA Hello. + + * ospfd.c: Discard_LSA to stay away from LOCAL_XLT Process NSSA + 'never, candidate, always'. Change "suppress" to "not-advertise". + + * ospfd.h: Add TranslatorRole to struct ospf_area. Add anyNSSA to + struct ospf. + + * ospf_ase.c (ospf_ase_calculate_route): External to stay away + from LOCAL_XLT + + * ospf_nsm.c (ospf_db_summary_add): External to stay away from + LOCAL_XLT + + * ospf_abr.c: Major logic added for abr_nssa_task(). If ABR, and + NSSA translator, then do it. Approve the global list, and flush + any unapproved. + + * ospf_lsa.h: New LSA flag OSPF_LSA_LOCAL_XLT to indicate that the + Type-5 resulted from a Local Type-7 translation; not used for + flooding, but used for flushing. + + * ospf_flood.c: New NSSA flooding. + +2000-12-08 Michael Rozhavsky + + * ospfd.c (ospf_find_vl_data): New function for looking up virtual + link data. + (ospf_vl_set_security): Virtual link configuration with + authentication. + (ospf_vl_set_timers): Set timers for virtual link. + + * New commands are added. + "area A.B.C.D virtual-link A.B.C.D" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535>" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> authentication-key AUTH_KEY" + "area A.B.C.D virtual-link A.B.C.D authentication-key AUTH_KEY" + "area A.B.C.D virtual-link A.B.C.D hello-interval <1-65535> retransmit-interval <3-65535> transmit-delay <1-65535> dead-interval <1-65535> message-digest-key <1-255> md5 KEY" + "area A.B.C.D virtual-link A.B.C.D message-digest-key <1-255> md5 KEY" + + * ospf_packet.c (ospf_check_md5_digest): Add neighbor's + cryptographic sequence number treatment. + (ospf_check_auth): OSPF input buffer is added to argument. + (ospf_read): Save neighbor's cryptographic sequence number. + + * ospf_nsm.c (nsm_change_status): Clear cryptographic sequence + number when neighbor status is changed to NSM down. + + * ospf_neighbor.c (ospf_nbr_new): Set zero to crypt_seqnum. + + * ospf_neighbor.h (struct ospf_neighbor): Add cryptographic + sequence number to neighbor structure. + +2000-11-29 Kunihiro Ishiguro + + * ospf_snmp.c (ospfIfLookup): OSPF MIB updates. + (ospfExtLsdbEntry): Add OspfExtLsdbTable treatment. + +2000-11-28 Michael Rozhavsky + + * ospfd.c (ospf_interface_down): Clear a ls_upd_queue queue of the + interface. + (ospf_ls_upd_queue_empty): New function to empty ls update queue + of the OSPF interface. + (no_router_ospf): 'no router ospf' unregister redistribution + requests from zebra. + +2000-11-28 Kunihiro Ishiguro + + * ospf_ism.c (ism_change_status): Increment status change number. + + * ospf_interface.h (struct ospf_interface): Add new member for + status change statistics. + + * Makefile.am: Update dependencies. + + * ospf_zebra.c (ospf_interface_add): OSPF SNMP interface update. + (ospf_interface_delete): OSPF SNMP interface delete. + + * ospf_snmp.h: New file is added. + +2000-11-23 Dick Glasspool + + * ospfd.h: Add new ospf_area structure member for + NSSATranslatorRole and NSSATranslator state. + + * ospfd.c: Provided for eventual commands to specify NSSA + elections for "translator- ALWAYS/NEVER/CANDIDATE". Provided for + decimal integer version of area-suppress. + + * ospf_flood.c: Flood Type-7's only into NSSA (not AS). + + * ospf_lsa.c: Undo some previous changes for NSSA. If NSSA + translator, advertise Nt bit. + + * ospf_route.c: 1st version of "sh ip os border-routers". + +2000-11-23 Michael Rozhavsky + + * ospfd.c (area_vlink): Virtual link can not configured in stub + area. + +2000-11-23 Gleb Natapov + + * ospf_packet.c (ospf_db_desc): In states Loading and Full the + slave must resend its last Database Description packet in response + to duplicate Database Description packets received from the + master. For this reason the slave must wait RouterDeadInterval + seconds before freeing the last Database Description packet. + Reception of a Database Description packet from the master after + this interval will generate a SeqNumberMismatch neighbor + event. RFC2328 Section 10.8 + (ospf_make_db_desc): DD Master flag treatment. + + * ospf_nsm.c (nsm_twoway_received): Move DD related procedure to + nsm_change_status(). + (nsm_bad_ls_req): Likewise. + (nsm_adj_ok): Likewise. + (nsm_seq_number_mismatch): Likewise. + (nsm_oneway_received): Likewise. + + * ospf_neighbor.h (struct ospf_neighbor): New structure member + last_send_ts for timestemp when last Database Description packet + was sent. + + * ospf_nsm.c (ospf_db_desc_timer): Make it sure nbr->last_send is + there. Call ospf_db_desc_resend() in any case. + +2000-11-16 Michael Rozhavsky + + * ospf_lsa.c (lsa_link_broadcast_set): When there is no DR on + network (suppose you have only one router with interface priority + 0). It's router LSA does not contain the link information about + this network. + + * ospf_nsm.c (nsm_timer_set): When you change a priority of + interface from/to 0 ISM_NeighborChange event should be scheduled + in order to elect new DR/BDR on the network. + + * ospf_interface.c (ip_ospf_priority): Likewise. + + * ospf_flood.c (ospf_ls_retransmit_add): When we add some LSA into + retransmit list we need to check whether the present old LSA in + retransmit list is not more recent than the new + one. + +2000-11-09 Dick Glasspool + + * ospf_packet.c: Allows for NSSA Type-7 LSA's throughout the NSSA + area. Any that exit the NSSA area are translated to type-5 LSA's. + The instantiated image is restored after translation. + (ospf_ls_upd_send_list): Renamed to ospf_ls_upd_queu_send(). + (ospf_ls_upd_send): Old function which enclosed by #ifdef 0 is + removed. + (ospf_ls_ack_send): Likewise. + + * ospf_flood.c: NSSA-LSA's without P-bit will be restricted to + local area. Otherwise they are allowed out the area to be + translated by ospf_packet.c. + + * ospf_lsa.c: Undo some previous changes for NSSA. + + * ospf_lsdb.h: New access for type 7. + +2000-11-07 Kunihiro Ishiguro + + * ospf_route.c (ospf_path_exist): New function to check nexthop + and interface are in current OSPF path or not. + (ospf_route_copy_nexthops_from_vertex): Add nexthop to OSPF path + when it is not there. Reported by Michael Rozhavsky + + +2000-11-06 Kunihiro Ishiguro + + * ospf_dump.c (config_write_debug): Add seventh string "detail" is + added for flag is OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | + OSPF_DEBUG_DETAIL. + +2000-11-06 Michael Rozhavsky + + * ospf_lsa.c (router_lsa_flags): ASBR can't exit in stub area. + +2000-11-06 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_router_lsa_originate): Reduce unconditional + logging. + +2000-11-06 Dick Glasspool + + * ospfd.h: Add ait_ntoa function prototype. + + * ospfd.c (ait_ntoa): New function for displaying area ID and + Stub/NSSA status. + (show_ip_ospf_interface_sub): Use ait_ntoa. + (show_ip_ospf_nbr_static_detail_sub): Likewise. + (show_ip_ospf_neighbor_detail_sub): Likewise. + + * ospf_route.c (ospf_intra_route_add): Set external routing type + to ospf route. + (ospf_intra_add_router): Likewise. + (ospf_intra_add_transit): Likewise. + (ospf_intra_add_stub): Likewise. + (ospf_add_discard_route): Likewise. + (show_ip_ospf_route_network): Use ait_ntoa. + (show_ip_ospf_route_network): Likewise. + (show_ip_ospf_route_router): Likewise. + + * ospf_lsa.c (show_lsa_detail): Use ait_ntoa. + (show_lsa_detail_adv_router): Likewise. + (show_ip_ospf_database_summary): Likewise. + + * ospf_route.h (struct route_standard): Add new member + external_routing. + + * ospf_ia.c (process_summary_lsa): Set external routing tyep to ospf + route. + (ospf_update_network_route): Likewise. + (ospf_update_router_route): Likewise. + +2000-11-04 Kunihiro Ishiguro + + * ospf_flood.c (ospf_process_self_originated_lsa): Enclose + OSPF_AS_NSSA_LSA treatment with #ifdef HAVE_NSSA. + +2000-11-03 Kunihiro Ishiguro + + * Unconditional logging is enclosed with if (IS_DEBUG_OSPF_EVENT). + Please specify "debug ospf event" for enable logging. + + * ospf_ism.c: Do not extern debug flag varible. It is done by + ospf_debug.h + * ospf_asbr.c: Likewise. + * ospf_lsa.c: Likewise. + * ospf_nsm.c: Likewise. + * ospf_zebra.c: Likewise. + + * ospf_dump.c (debug_ospf_event): New command "debug ospf event" + is added. + + * ospfd.c (router_ospf): Change logging from vty_out() to + zlog_info(). + (ospf_area_stub_cmd): Likewise. + + * ospf_dump.h: Extern term_debug flags. + (OSPF_DEBUG_EVENT): Add new flag. + (IS_DEBUG_OSPF_EVENT): Add new macro. + +2000-11-03 Dick Glasspool + + * ospf_flood.c (ospf_process_self_originated_lsa): + OSPF_AS_NSSA_LSA is treated as same as OSPF_AS_EXTERNAL_LSA. + (ospf_flood): Type-5's have no change. Type-7's can be received, + and will Flood the AS as Type-5's They will also flood the local + NSSA Area as Type-7's. The LSDB will be updated as Type-5's, and + during re-fresh will be converted back to Type-7's (if within an + NSSA). + (ospf_flood_through): Incoming Type-7's were allowed here if our + neighbor was an NSSA. So Flood our area with the Type-7 and also + if we are an ABR, flood thru AS as Type-5. + + * ospf_lsa.c (ospf_external_lsa_refresh): Flood NSSA both NSSA + area and other area. + + * ospf_packet.c (ospf_db_desc_proc): When AS External LSA is + exists in DD packet, make it sure that this area is not stub. + (ospf_ls_upd_list_lsa): When LSA type is NSSA then set lsa's area + to NULL. + (ospf_ls_upd): If the LSA is AS External LSA and the area is stub + then discard the lsa. If the LSA is NSSA LSA and the area is not + NSSA then discard the lsa. + +2000-11-03 Kunihiro Ishiguro + + * ospfd.c (ospf_interface_run): Fix bug of Hello packet's option + is not properly set when interface comes up. + +2000-11-02 Kunihiro Ishiguro + + * ospfd.h (OSPF_OPTION_O): Add new hello header option. + +2000-11-01 Dick Glasspool + + * ospf_lsa.h: Define OSPF_MAX_LSA to 8 when HAVE_NSSA is enabled. + (OSPF_GROUP_MEMBER_LSA): Define OSPF_GROUP_MEMBER_LSA. + + * ospf_lsa.c (show_database_desc): Add "Group Membership LSA" + string. + +2000-10-31 Dick Glasspool + + * ospf_lsa.h (OSPF_AS_NSSA_LSA): Define OSPF_AS_NSSA_LSA. + + * ospf_lsa.c (show_ip_ospf_database): NSSA database display + function is added. ALIASES which have "show ip ospf database + nssa-external" is added. + (show_ip_ospf_border_routers): New command "show ip ospf + border-routers" is added. + +2000-10-30 Dick Glasspool + + * ospfd.c (router_ospf): NSSA Enabled message is added for + testing. + (ospf_area_type_set): Are type set for NSSA area. + (ospf_area_stub_cmd): Special translation of no_summary into NSSA + and summary information. If NSSA is enabled pass the information + to ospf_area_type_set(). + (area_nssa): New commands are added: + "area A.B.C.D nssa" + "area <0-4294967295> nssa" + "area A.B.C.D nssa no-summary" + "area <0-4294967295> nssa no-summary" + (ospf_no_area_stub_cmd): Special translation of no_summary into + NSSA and summary information. If external_routing is + OSPF_AREA_NSSA unset area with ospf_area_type_set (area, + OSPF_AREA_DEFAULT). + (show_ip_ospf_area): Display NSSA status. + (config_write_ospf_area): Show NSSA configuration. + + * ospf_packet.c (ospf_hello): For NSSA support, ensure that NP is + on and E is off. + +2000-10-26 Gleb Natapov + + * ospf_lsa.c (ospf_network_lsa_body_set): The network-LSA lists + those routers that are fully adjacent to the Designated Router; + each fully adjacent router is identified by its OSPF Router ID. + The Designated Router includes itself in this list. RFC2328, + Section 12.4.2. + +2000-10-23 Jochen Friedrich + + * ospf_snmp.c: ospf_oid and ospfd_oid are used in smux_open after + it is registered. So those variables must be static. + +2000-10-18 K N Sridhar + + * ospfd.c: Add area_default_cost_decimal_cmd and + no_area_default_cost_decimal_cmd alias. + +2000-10-05 Gleb Natapov + + * ospfd.c (ospf_network_new): Fix setting area format. + (no_router_ospf): Check area existance when calling + ospf_interface_down(). + + * ospf_flood.c (ospf_external_info_check): Fix bug of refreshing + default route. + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-09-29 Kunihiro Ishiguro + + * ospf_snmp.c (ospfHostEntry): OSPF Host MIB is implemented. + + * ospfd.c (ospf_nbr_static_cmp): OSPF neighbor is sorted by it's + address. + +2000-09-28 Michael Rozhavsky + + * ospf_interface.c (ospf_if_free): Fix deleting self neighbor twice. + +2000-09-27 Kunihiro Ishiguro + + * ospf_packet.c (ospf_read): Solaris on x86 has ip_len with host + byte order. + +2000-09-25 Toshiaki Takada + + * ospfd.c (ospf_compatible_rfc1583), (no_ospf_compatible_rfc1583): + Add CISCO compatible command. + +2000-09-25 Kunihiro Ishiguro + + * ospf_abr.c (ospf_area_range_lookup): New function is added for + area range lookup in OSPF-MIB. + (ospf_area_range_lookup_next): Likewise. + +2000-09-22 Kunihiro Ishiguro + + * ospfd.c (no_router_ospf): Delete virtual link before deleting + area structure. + + * ospf_lsa.c (ospf_external_lsa_refresh_type): Check + EXTERNAL_INFO(type). + + * ospfd.c (no_router_ospf): Call ospf_vl_delete() instead of + ospf_vl_data_free(). + + * ospf_interface.c (ospf_vl_shutdown): Execute ISM_InterfaceDown + when ospf_vl_shutdown is called. + (ospf_vl_delete): Call ospf_vl_shutdown() to delete virtual link + interface's thread. + +2000-09-21 Gleb Natapov + + * ospf_lsa.c: New implementation of OSPF refresh. + +2000-09-20 Kunihiro Ishiguro + + * ospf_snmp.c (ospfLsdbLookup): Add LSDB MIB implementation. + +2000-09-18 Kunihiro Ishiguro + + * ospf_snmp.c (ospfStubAreaEntry): Add OSPF stub area MIB. + +2000-09-18 Gleb Natapov + + * ospf_route.h (route_standard): Change member from `struct area' + to area_id. + + * ospf_abr.c (ospf_abr_announce_network), (ospf_abr_should_announce), + (ospf_abr_process_network_rt), (ospf_abr_announce_rtr), + (ospf_abr_process_router_rt): + * ospf_ase.c (ospf_find_asbr_route), + (ospf_find_asbr_router_through_area), + * ospf_ia.c (ospf_find_abr_route), (ospf_ia_router_route), + (process_summary_lsa), (ospf_update_network_route), + (ospf_update_router_route): + * ospf_route.c (ospf_intra_route_add), (ospf_intra_add_router), + (ospf_intra_add_transit), (ospf_intra_add_stub), + (ospf_route_table_dump), (show_ip_ospf_route_network), + (show_ip_ospf_route_router), (ospf_asbr_route_cmp), + (ospf_prune_unreachable_routers): + * ospf_spf.c (ospf_rtrs_print): + * ospfd.c (ospf_rtrs_free): Fix the struct change above. + +2000-09-14 Kunihiro Ishiguro + + * ospf_network.c (ospf_serv_sock_init): Enclose SO_BINDTODEVICE + with ifdef. + +2000-09-13 Gleb Natapov + + * ospf_ism.c (ospf_elect_dr), (ospf_elect_bdr): Fix DR election. + + * ospf_network.c (ospf_serv_sock_init): Add socket option + SO_BINDTODEVICE on read socket. + + * ospf_packet.c (ospf_hello): Ignore Hello packet if E-bit does + not match. + + * ospfd.c (ospf_area_check_free), (ospf_area_get), + (ospf_area_add_if): New function added. + +2000-09-13 Kunihiro Ishiguro + + * ospf_route.c (ospf_intra_add_router): Update ABR and ASBR router + count. + + * ospf_spf.c (ospf_spf_init): Rest ABR and ASBR router count + starting SPF calculation. + + * ospfd.h (struct ospf_area): Add ABR and ASBR router count. + +2000-09-12 Kunihiro Ishiguro + + * ospfd.c (ospf_area_id_cmp): New area structure is sorted by area + ID. + + * ospf_lsa.c (ospf_router_lsa_originate): For OSPF MIB update + lsa_originate_count. + (ospf_network_lsa_originate): Likewise. + (ospf_summary_lsa_originate): Likewise. + (ospf_summary_asbr_lsa_originate): Likewise. + (ospf_external_lsa_originate): Likewise. + +2000-09-11 Kunihiro Ishiguro + + * ospf_snmp.c (ospf_variables): ospfRouterID's type RouterID + syntax is IpAddress. + (ospf_admin_stat): New function for OSPF administrative status + check. + +2000-09-10 Jochen Friedrich + + * ospf_snmp.c: Implement OSPF MIB skeleton. + +2000-09-08 Kunihiro Ishiguro + + * ospf_snmp.c: New file is added. + +2000-09-07 David Lipovkov + + * ospf_zebra.c (ospf_interface_delete): Add pseudo interface + treatment. + + * ospf_interface.c (interface_config_write): Likewise. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +2000-08-17 Michael Rozhavsky + + * ospfd.c (ospf_area_free): Remove virtual link configuration only + when Area is removed. + +2000-08-17 Kunihiro Ishiguro + + * ospfd.c (network_area): Revert check for EXTERNAL_INFO + (ZEBRA_ROUTE_CONNECT). + (no_network_area): Likewise. + +2000-08-16 Kunihiro Ishiguro + + * ospfd.h (struct ospf): Add distance_table and + distance_{all,intra,inter,external}. + + * ospf_zebra.c: Add OSPF distance related functions. + +2000-08-15 Gleb Natapov + + * ospf_asbr.c (ospf_external_info_find_lsa): New function added. + + * ospf_lsa.c (ospf_default_external_info), + (ospf_default_originate_timer), (ospf_external_lsa_refresh_default): + New function added. + + * ospf_zebra.c + (ospf_default_information_originate_metric_type_routemap), + (ospf_default_information_originate_always_metric_type_routemap): + Change name and add route-map function. + (ospf_default_information_originate_metric_routemap), + (ospf_default_information_originate_routemap), + (ospf_default_information_originate_type_metric_routemap): + New DEFUN added. + +2000-08-14 Kunihiro Ishiguro + + * ospf_zebra.c (zebra_interface_if_set_value): Change ifindex + restore size from two octet to four. + +2000-08-14 Michael Rozhavsky + + * ospf_ase.c (ospf_ase_incremental_update): Implement incremental + AS-external-LSA in 16.6 of RFC2328. + +2000-08-14 Matthew Grant + + * ospf_interface.c (ospf_if_get_output_cost): Change cost + calculation algorithm. + + * ospf_packet (ospf_ls_upd): Fix problem of LSA retransmitting. + +2000-08-11 Michael Rozhavsky + + * ospf_lsa.c (ospf_maxage_lsa_remover): Fix maxage remover for + AS-external-LSAs. + +2000-08-10 Toshiaki Takada + + * ospfd.c (auto_cost_reference_bandwidth): New DEFUN added. + `auto-cost reference-bandwidth' OSPF router command added. + +2000-08-08 Gleb Natapov + + * ospf_routemap.c (ospf_route_map_update): New function added. + Add route-map event hook. + +2000-08-08 Toshiaki Takada + + * ospf_zebra.c (ospf_distribute_check_connected): If redistribute + prefix is connected route on OSPF enabled interface, suppress to + announce it. + +2000-08-08 Matthew Grant + + * ospf_interface.c (ospf_if_get_output_cost): + New function added. Handle bandwidth parameter for cost + calculation. + +2000-08-08 Michael Rozhavsky + + * ospf_interface.c (interface_config_write): Show interface + configuration regardless interface is down. + + * ospf_ase.c (ospf_ase_caocluate_route): Whole rewritten external + route calculate function. + +2000-08-08 Gleb Natapov + + * ospf_routemap.c: New file added. + + * ospf_asbr.c (ospf_reset_route_map_set_values), + (ospf_route_map_set_compare): New function added. + + * ospf_lsa.c (ospf_external_lsa_body_set): Set routemap metric + with AS-external-LSA. + +2000-08-05 Kunihiro Ishiguro + + * ospf_ase.c (ospf_ase_calculate_route_add): Pass new->cost to + ospf_zebra_add as metric. + (ospf_ase_calculate_route_add): Likewise. + + * ospf_route.c (ospf_route_install): Pass or->cost to + ospf_zebra_add as metric. + + * ospf_zebra.c (ospf_zebra_add): Add metric arguemnt. + (ospf_zebra_delete): Likewise. + +2000-08-03 Matthew Grant + + * ospf_flood.c (ospf_flood_delayed_lsa_ack): New function added. + Dispatch delayed-ACK with flooding AS-external-LSA across virtual + link. + +2000-07-31 Matthew Grant + + * ospfd.c (show_ip_ospf_area): Fix lack of VTY_NEWLINE when + `show ip ospf'. + + * ospf_interface.c (ospf_if_free): Fix bug of crash with + Point-to-Point interface. + +2000-07-27 Michael Rozhavsky + + * ospf_flood.c (ospf_process_self_originated_lsa): + Make sure to clear LSA->param (redistributed external information) + before refreshment. + +2000-07-27 Gleb Natapov + + * ospfd.c (refresh_group_limit), (refresh_per_slice), + (refresh_age_diff): New defun added. Refresher related parameter + can be configurable. + +2000-07-27 Akihiro Mizutani + + * ospf_interface.c (interface_config_write): Print `description' + config directive to work. + +2000-07-24 Akihiro Mizutani + + * ospf_interface.c (ospf_if_init): Use install_default for + INTERFACE_NODE. + +2000-07-24 Gleb Natapov + + * ospf_packet.c (ospf_ls_upd_send_list), (ospf_ls_upd_send_event), + (ospf_ls_ack_send_list), (ospf_ls_ack_send_event): New function added. + This make sending always as many LS update/Ack combined in one ospf + packet. + +2000-07-24 Gleb Natapov + + * ospf_packet.c (ospf_ls_upd_list_lsa): Set NULL to lsa->area if + LSA is AS-external-LSA. + + * ospf_nsm.c (nsm_reset_nbr): Do not cancel Inactivity timer. + +2000-07-21 Toshiaki Takada + + * ospf_zebra.c (ospf_default_originate_timer): Set timer for + `default-information originate'. Fix some default originate + related functions. + +2000-07-12 Toshiaki Takada + + * ospf_lsa.c (stream_put_ospf_metric): New function added. + +2000-07-12 Toshiaki Takada + + * ospf_lsa.c (show_ip_ospf_database_router), + (show_ip_ospf_database_network), (show_ip_ospf_database_summary), + (show_ip_ospf_database_summary_asbr), (show_ip_ospf_database_externel), + (show_router_lsa), (show_any_lsa), (show_router_lsa_self), + (show_any_lsa_self): Functions removed. + + (show_lsa_prefix_set), (show_lsa_detail_proc), (show_lsa_detail), + (show_lsa_detail_adv_router_proc), (show_lsa_detail_adv_router): + New functions added. Replace above functions. + + (show_ip_ospf_database_all), (show_ip_ospf_database_self_originated): + Functions removed. + (show_ip_ospf_database_summary): New functions added. Replace + above functions. + + (show_ip_ospf_database_cmd): DEFUN rearranged. + (show_ip_ospf_database_type_id_cmd), + (show_ip_ospf_database_type_id_adv_router_cmd), + (show_ip_ospf_database_type_is_self_cmd): New ALIASes added. + (show_ip_ospf_database_type_adv_rotuer_cmd): New DEFUN added. + (show_ip_ospf_database_type_self_cmd): New ALIAS added. + +2000-07-11 Toshiaki Takada + + * ospf_asbr.c (ospf_external_info_new), + (ospf_external_info_free): New functions added. + + * ospf_lsa.h (ospf_lsa): Add new member `void *param' to set + origination parameter for external-LSA. + Remove member `redistribute'. + + * ospf_zebra.c (ospf_redistirbute_set): When `redistribute' + command executed, metric and metric-type values are overridden. + If one of those is changed refresh AS-external-LSAs for appropriate + type. + +2000-07-11 Michael Rozhavsky + + * ospf_lsa.c (ospf_summary_lsa_refresh), + (ospf_summary_asbr_lsa_refresh): Make sure to refresh summary-LSAs. + + * ospf_abr.c (set_metric): New function added. + +2000-07-07 Toshiaki Takada + + * ospf_zebra.c (ospf_default_information_originate_metric_type), + (ospf_default_information_originate_type_metric): New defun added. + Metic and Metric type can be set to default route. + (ospf_default_information_originate_always_metric_type): + (ospf_default_information_originate_always_type_metric): + New defun added. Metric and Metric type can be set to default + always route. + + * ospf_zebra.c (ospf_default_metric), (no_ospf_default_metric): + New defun added. + +2000-07-06 Gleb Natapov + + * ospf_flood.c (ospf_flood_through_area): Fix bug of considering + on the same interface the LSA was received from. + +2000-07-06 Michael Rozhavsky + + * ospfd.c (ospf_config_write): Fix bug of printing `area stub' + command with `write mem'. + + * ospfd.c (no_router_ospf): Remove installed routes from zebra. + + * ospf_zebra.c (ospf_interface_delete): Fix function to handle + zebra interface delete event. + +2000-07-06 Toshiaki Takada + + * ospf_zebra.c (ospf_default_information_originate), + (ospf_default_information_originate_always): New DEFUN added. + +2000-07-05 Michael Rozhavsky + + * ospf_route.c (ospf_terminate): Make sure to remove external route + when SIGINT received. + +2000-07-03 Gleb Natapov + + * ospf_flood.c, ospf_ism.c, ospf_lsa,c, ospfd.c: Make sure to free + many structure with `no router ospf'. + +2000-06-30 Gleb Natapov + + * ospf_neighbor.c (ospf_nbr_new), + ospf_nsm.c (nsm_timer_set): Start LS update timer only + when neighbor enters Exchange state. + +2000-06-29 Gleb Natapov + + * ospf_nsm.c (nsm_timer_set), (nsm_exchange_done), + ospf_packet.c (ospf_db_desc_proc): + Do not cancel DD retransmit timer when Master. + +2000-06-29 Gleb Natapov + + * ospf_abr.c (ospf_abr_announce_network_to_area), + (ospf_abr_announce_rtr_to_area) + ospf_ase.c (ospf_ase_rtrs_register_lsa), + ospf_flood.c (ospf_process_self_originated_lsa), + (ospf_flood_through_area), (ospf_ls_request_delete), + ospf_interface.c (ospf_if_free), + ospf_ism.c (ism_change_status), + ospf_lsa.c (ospf_router_lsa_update_timer), + (ospf_router_lsa_install), (ospf_network_lsa_install), + (ospf_lsa_maxage_delete), (ospf_lsa_action), + (ospf_schedule_lsa_flood_area), + ospf_nsm.c (nsm_change_status), + ospf_packet.c (ospf_make_ls_req_func), (ospf_make_ls_ack): + Use ospf_lsa_{lock,unlock} for all looking-up of LSA. + + * ospf_flood.c (ospf_ls_request_free): Function deleted. + + * ospf_lsa.c (ospf_discard_from_db): New function added. + +2000-06-26 Toshiaki Takada + + * ospfd.h (ospf): struct member `external_lsa' name changed to + `lsdb'. + +2000-06-26 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_install), (ospf_router_lsa_install), + (ospf_network_lsa_install), (ospf_summary_lsa_install), + (ospf_summary_asbr_lsa_install), (ospf_external_lsa_install): + Functions re-arranged. + + * ospf_lsa.c (IS_LSA_MAXAGE), (IS_LSA_SELF): Macro added. + +2000-06-20 Michael Rozhavsky + + * ospf_packet.c (ospf_ls_req), (ospf_ls_upd), (ospf_ls_ack): Add + verification of LS type. + +2000-06-20 Gleb Natapov + + * ospf_ase.c (ospf_ase_calculate_timer): Add more sanity check + whether rn->info is NULL. + +2000-06-20 Toshiaki Takada + + * ospfd.c (show_ip_ospf_interface_sub): Show Router-ID of both + DR and Backup correctly with `show ip ospf interface' command. + +2000-06-20 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_lock), (ospf_lsa_unlock), + (ospf_lsa_discard): These functions are used for avoiding + unexpected reference to freed LSAs. + +2000-06-13 Kunihiro Ishiguro + + * ospf_packet.c (ospf_ls_upd): Initialize lsa by NULL to avoid + warning. + +2000-06-12 Kunihiro Ishiguro + + * ospf_ase.h (ospf_ase_rtrs_register_lsa): Add prototype. + +2000-06-12 Toshiaki Takada + + * ospf_lsa.c (ospf_external_lsa_install): Make sure to register + LSA to rtrs_external when replacing AS-external-LSAs in LSDB. + Fix core dump. + +2000-06-10 Toshiaki Takada + + * ospf_lsdb.c (id_to_prefix), (ospf_lsdb_hash_key), + (ospf_lsdb_hash_cmp), (ospf_lsdb_new), (ospf_lsdb_iterator), + (lsdb_free), (ospf_lsdb_free), (ospf_lsdb_add), (ospf_lsdb_delete), + (find_lsa), (ospf_lsdb_lookup), (find_by_id), + (ospf_lsdb_lookup_by_id), (ospf_lsdb_lookup_by_header): Functinos + removed for migration to new_lsdb. + + * ospf_lsa.c (ospf_summary_lsa_install), + (ospf_summary_asbr_lsa_install), (ospf_maxage_lsa_remover), + (ospf_lsa_maxage_walker), (ospf_lsa_lookup), + (ospf_lsa_lookup_by_id): Use new_lsdb instead of ospf_lsdb. + (count_lsa), (ospf_lsa_count_table), (ospf_lsa_count), + (ospf_get_free_id_for_prefix): Funcitions removed. + +2000-06-09 Gleb Natapov + + * ospf_ism.c (ism_interface_down): Prevent some unneeded DR changes. + + * ospf_packet.c (ospf_db_desc_proc): Fix memory leak. + (ospf_hello): Always copy router-ID when hello is received. + +2000-06-08 Gleb Natapov + + * ospf_lsa.h (struct ospf_lsa): Add member of pointer to struct + ospf_area. + +2000-06-08 Michael Rozhavsky + + * ospf_ase.c (ospf_asbr_route_same): New function added. + This function makes sure external route calculation more + precisely. + +2000-06-07 Michael Rozhavsky + + * ospf_ism.c (ism_change_status): Use ospf_lsa_flush_area for + network-LSA deletion instead of using ospf_lsdb_delete. + Also cancel network-LSA origination timer. + +2000-06-07 Levi Harper + + * ospf_interface.c (ospf_if_down): Close read fd when an interface + goes down. + +2000-06-05 Kunihiro Ishiguro + + * ospf_asbr.c (ospf_external_info_lookup): Add explicit brace for + avoid ambiguous else. + + * ospf_flood.c (ospf_external_info_check): Likewise. + +2000-06-05 Toshiaki Takada + + * ospf_nsm.c (nsm_adj_ok): Fix bug of DR election. + +2000-06-04 Toshiaki Takada + + * ospf_zebra.c (ospf_default_information_originate), + (no_ospf_default_information_originate): New DEFUN added. + +2000-06-03 Toshiaki Takada + + * ospf_lsa.h, ospf_asbr.h (external_info): Struct moved from + ospf_lsa.h to ospf_asbr.h. + + * ospf_lsa.c, ospf_asbr.c (ospf_external_info_add), + (ospf_external_info_delete): Function moved from ospf_lsa.c + to ospf_asbr.c. + +2000-06-03 Toshiaki Takada + + * ospf_flood.c (ospf_external_info_check): New function added. + (ospf_process_self_orignated_lsa): Make sure to flush + self-originated AS-external-LSA, when router reboot and no longer + originate those AS-external-LSA. + +2000-06-02 Toshiaki Takada + + * ospf_network.c (ospf_serv_sock): Remove SO_DONTROUTE + socket option. + + * ospf_packet.c (ospf_write): Set MSG_DONTROUTE flag for + unicast destination packets. + +2000-06-02 Toshiaki Takada + + * ospf_lsdb.c (new_lsdb_delete): Delete entry from LSDB only when + specified LSA matches. + +2000-06-02 Gleb Natapov + + * ospf_network.c (ospf_serv_sock): Set SO_DONTROUTE + socket option. + +2000-06-01 Akihiro Mizutani + + * ospf_dump.c: Replace string `Debugging functions\n' with DEBUG_STR. + Replace string `OSPF information\n' with OSPF_STR. + +2000-06-01 Toshiaki Takada + + * ospf_lsdb.[ch]: Use new_lsdb struct for network-LSA instead of + ospf_lsdb. + +2000-06-01 Toshiaki Takada + + * ospf_dump.c (config_debug_ospf_packet), (config_debug_ospf_event), + (config_debug_ospf_ism), (config_debug_ospf_nsm), + (config_debug_ospf_lsa), (config_debug_ospf_zebra), + (term_debug_ospf_packet), (term_debug_ospf_event), + (term_debug_ospf_ism), (term_debug_ospf_nsm), + (term_debug_ospf_lsa), (term_debug_ospf_zebra): Repalce debug_ospf_* + variable to use for debug option flags. + + (debug_ospf_packet), (debug_ospf_ism), (debug_ospf_nsm), + (debug_ospf_lsa), (debug_ospf_zebra): Set {config,term}_debug_* + flags when vty->node is CONFIG_NODE, otherwise set only term_debug_* + flags. + + * ospf_dump.h (CONF_DEBUG_PACKET_ON), (CONF_DEBUG_PACKET_OFF), + (TERM_DEBUG_PACKET_ON), (TERM_DEBUG_PACKET_OFF), + (CONF_DEBUG_ON), (CONF_DEBUG_OFF), (IS_CONF_DEBUG_OSPF_PACKET), + (IS_CONF_DEBUG_OSPF): New Macro added. + +2000-05-31 Toshiaki Takada + + * ospfd.c (clear_ip_ospf_neighbor): New DEFUN added. + Currently this command is used for only debugging. + + * ospf_nsm.c (nsm_change_status): Make sure thread cancellation + for network-LSA when DR has no full neighbors. + + * ospf_nsm.c (ospf_db_summary_clear): New function added. + +2000-05-30 Toshiaki Takada + + * ospf_lsdb.c (new_lsdb_insert): LSAs are always freed by + maxage_lsa_remover when LSA is replaced. + +2000-05-25 Gleb Natapov + + * ospf_flood.c (ospf_ls_retransmit_delete_nbr_all): Add argument + `struct ospf_area' to remove LSA from Link State retransmission list + of neighbor from only one Area. + +2000-05-24 Michael Rozhavsky + + * ospf_lsdb.c (ospf_lsdb_add): Preserve flags field when + overriting old LSA with new LSA. + +2000-05-24 Gleb Natapov + + * ospf_lsa.c (ospf_router_lsa_body_set): Fix bug of router-LSA + size calculation. + +2000-05-22 Michael Rozhavsky + + * ospf_route.c (ospf_intra_add_stub): + * ospf_spf.h (struct vertex): Use u_int32_t for distance (cost) + value instead of u_int16_t. + +2000-05-22 Axel Gerlach + + * ospf_ia.c (ospf_ia_network_route): Fix bug of Inter-area route + equal cost path calculation. + +2000-05-21 Toshiaki Takada + + * ospf_ase.c (ospf_ase_calculate_route_delete): New function added. + Make sure, when rotuer route is deleted, related external routes + are also deleted. + +2000-05-20 Toshiaki Takada + + * ospfd.c (ospf_interface_down): Make sure interface flag is disable + and set fd to -1. + +2000-05-16 Toshiaki Takada + + * ospf_asbr.c (ospf_asbr_should_announce), (ospf_asbr_route_remove): + Functions removed. + + * ospfd.h (EXTERNAL_INFO): Macro added. + Substitute `ospf_top->external_info[type]' with it. + +2000-05-16 Toshiaki Takada + + * ospf_lsa.c (ospf_rtrs_external_remove): New function added. + +2000-05-14 Gleb Natapov + + * ospf_flood.c (ospf_ls_retransmit_delete_nbr_all) + * ospf_lsdb.c (new_lsdb_insert) + * ospf_packet.c (ospf_ls_ack): Fix database synchonization problem. + +2000-05-14 Gleb Natapov + + * ospf_lsa.h (tv_adjust), (tv_ceil), (tv_floor), (int2tv), + (tv_add), (tv_sub), (tv_cmp): Prototype definition added. + + * ospf_nsm.h (ospf_db_summary_delete_all): Prototype definition added. + +2000-05-13 Toshiaki Takada + + * ospf_lsa.[ch] (ospf_lsa): struct timestamp type is changed from + time_t to struct timeval. + (tv_adjust), (tv_ceil), (tv_floor), (int2tv), (tv_add), + (tv_sub), (tv_cmp): timeval utillity functions added. + +2000-05-12 Toshiaki Takada + + * ospf_lsa.[ch] (ospf_schedule_update_router_lsas): Delete function. + Change to use macro OSPF_LSA_UPDATE_TIMER instead of using + this function. + router-LSA refresh timer related stuff is re-organized. + +2000-05-10 Gleb Natapov + + * ospf_interface.c (ospf_vl_set_params): + * ospf_packet.c (ospf_check_network_mask): + * ospf_spf.[ch] (ospf_spf_next): + Remove field address from `struct vertex', and search for peer + address of virtual link in function `ospf_vl_set_params' instead. + +2000-05-10 Gleb Natapov + + * ospf_packet.c (ospf_ls_upd): Fix some memory leak related LSA. + +2000-05-08 Thomas Molkenbur + + * ospf_packet.c (ospf_packet_dup): Replace ospf_steram_copy() + with ospf_stream_dup() to fix memory leak. + +2000-05-08 Michael Rozhavsky + + * ospf_flood.c (ospf_flood_through_area): Fix the problem of + LSA update without DROther. + +2000-05-04 Gleb Natapov + + * ospf_spf.c (ospf_vertex_free): Fix memory leak of SPF calculation. + +2000-05-03 Toshiaki Takada + + * ospf_neighbor.c (ospf_db_summary_add): Use new_lsdb struct + instead linked-list. + (ospf_db_summary_count), (ospf_db_summary_isempty): + New function added. + + * ospf_lsa.c (ospf_rotuer_lsa): Re-arrange and divide functions. + +2000-05-02 Gleb Natapov + + * ospf_lsdb.c (new_lsdb_cleanup): Fix memory leak. When LSDB are + not needed any more, then free them. + +2000-05-02 Toshiaki Takada + + * ospfd.c (timers_spf), (no_timers_spf): New defun added. + SPF calculation timers related stuff is rearranged. + + * ospf_spf.c (ospf_spf_calculate_timer_add): Function removed. + SPF timer is scheduled by SPF calculation delay and holdtime + configuration variable. + + * ospf_lsa.c (ospf_external_lsa_nexthop_get): Set AS-external-LSA's + forwarding address when nexthop learned by other protocols is + in the OSPF domain. + + * ospf_zebra.c (ospf_redistribute_source_metric_type), + (ospf_redistribute_source_type_metric): Re-arrange DEFUNs and + ALIASes. + +2000-05-01 Toshiaki Takada + + * ospf_flood.c (ospf_ls_retransmit_count), + (ospf_ls_retransmit_isempty): New function added. + + (ospf_ls_retransmit_add), (ospf_ls_retransmit_delete), + (ospf_ls_retransmit_clear), (ospf_ls_retransmit_lookup), + (ospf_ls_retransmit_delete_all), (ospf_ls_retransmit_delete_nbr_all), + (ospf_ls_retransmit_add_nbr_all): Replace these functions to use + new_lsdb. + +2000-04-29 Toshiaki Takada + + * ospfd.c (no_network_area): Add check Area-ID whether specified + Area-ID with prefix matches config. + +2000-04-27 Toshiaki Takada + + * ospf_lsa.c (ospf_maxage_lsa_remover): Fix problem of + remaining withdrawn routes on zebra. + +2000-04-25 Michael Rozhavsky + + * ospf_nsm.c (nsm_kill_nbr), (nsm_ll_down), (nsm_change_status), + (ospf_nsm_event): Fix network-LSA re-origination problem. + +2000-04-24 Toshiaki Takada + + * ospf_nsm.c (ospf_db_desc_timer): Fix bug of segmentation fault + with DD retransmission. + + * ospf_nsm.c (nsm_kill_nbr): Fix bug of re-origination when + a neighbor disappears. + +2000-04-23 Michael Rozhavsky + + * ospf_abr.c (ospf_abr_announce_network_to_area): Fix bug of + summary-LSAs reorigination. Correctly copy OSPF_LSA_APPROVED + flag to new LSA. when summary-LSA is reoriginatd. + + * ospf_flood.c (ospf_flood_through_area): Fix bug of flooding + procedure. Change the condition of interface selection. + +2000-04-21 Toshiaki Takada + + * ospf_lsa.c (ospf_refresher_register_lsa): Fix bug of refresh never + occurs. + + * ospfd.c (show_ip_ospf_neighbor_id): New defun added. + `show ip ospf neighbor' related commands are re-arranged. + +2000-04-20 Toshiaki Takada + + * ospf_dump.c (debug_ospf_zebra): New defun added. + Suppress zebra related debug information. + +2000-04-19 Toshiaki Takada + + * ospf_zebra.c (ospf_distribute_list_update_timer), + (ospf_distribute_list_update), (ospf_filter_update): + New function added. Re-organize `distribute-list' router ospf + command. + +2000-04-13 Michael Rozhavsky + + * ospf_packet.c (ospf_make_ls_upd): Add check for MAX_AGE. + +2000-04-14 Michael Rozhavsky + + * ospf_packet.c (ospf_make_ls_upd): Increment LS age by configured + interface transmit_delay. + +2000-04-14 Sira Panduranga Rao + + * ospf_interface.c (ip_ospf_cost), (no_ip_ospf_cost): + Add to schedule router_lsa origination when the interface cost changes. + +2000-04-12 Toshiaki Takada + + * ospf_lsa.c (ospf_refresher_register_lsa), + (ospf_refresher_unregister_lsa): Fix bug of core dumped. + + * ospfd.c (no_router_ospf): Fix bug of core dumped. + +2000-03-29 Toshiaki Takada + + * ospf_nsm.c (nsm_oneway_received): Fix bug of MS flag unset. + +2000-03-29 Michael Rozhavsky + + * ospf_lsa.c (ospf_network_lsa): + * ospf_nsm.c (ospf_nsm_event): Fix bug of Network-LSA originated + in stub network. + +2000-03-28 Toshiaki Takada + + * ospf_nsm.c (nsm_bad_ls_req), (nsm_seq_number_mismatch), + (nsm_oneway_received): Fix bug of NSM state flapping between + ExStart and Exchange. + +2000-03-28 Toshiaki Takada + + * ospf_packet.h (strcut ospf_header): Fix the size of ospf_header, + change u_int8_t to u_char. + +2000-03-27 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_checksum): Take care of BIGENDIAN architecture. + +2000-03-27 Toshiaki Takada + + * ospfd.c (ospf_interface_run): Make sure Address family matches. + +2000-03-26 Love + + * ospf_packet.c (ospf_write): Chack result of sendto(). + +2000-03-26 Sira Panduranga Rao + + * ospf_nsm.c (nsm_oneway_received): Fix bug of 1-WayReceived in NSM. + +2000-03-23 Libor Pechacek + + * ospf_lsa.c (ospf_network_lsa) + * ospf_lsdb.c (new_lsdb_insert): Fix bug of accessing to + unallocated memory. + +2000-03-23 Toshiaki Takada + + * ospfd.c (ospf_config_write): Fix bug of duplicate line for + `area A.B.C.D authentication'. + +2000-03-22 Toshiaki Takada + + * ospf_debug.c (debug_ospf_lsa), (no_debug_ospf_lsa): Defun added. + Suppress all zlog related to LSAs with this config option. + +2000-03-21 Kunihiro Ishiguro + + * ospf_nsm.c (ospf_nsm_event): Add check for NSM_InactivityTimer. + +2000-03-21 Toshiaki Takada + + * ospf_packet.c (ospf_ls_upd_timer), (ospf_ls_req): + Fix bug of memory leak about linklist. + + * ospf_flood.c (ospf_flood_through_area): Likewise. + +2000-03-18 Sira Panduranga Rao + + * ospf_flood.c (ospf_ls_retransmit_lookup): Add checksum comparison + to identify LSA uniquely. This fix routes lost. + +2000-03-18 Toshiaki Takada + + * ospf_ase.c (ospf_find_asbr_route): Add sanity check with router + routing table. + +2000-03-17 Alex Zinin + + * ospf_spf.[ch]: Bug fix. + The 2nd stage of Dijkstra could consider one vertex + more than once if there is more than one link + between the routers, thus adding extra CPU overhead + and extra next-hops. + Fixed. + +2000-03-15 Sira Panduranga Rao + + * ospf_nsm.c (nsm_inactivity_timer): Changed to call nsm_kill_nbr(). + +2000-03-14 Toshiaki Takada + + * ospf_route.c (ospf_route_copy_nexthops): Fix bug of memory leak of + ospf_path. Actually ignore merging ospf_route with completely same + paths. + +2000-03-12 Toshiaki Takada + + * ospf_lsa.c (show_as_external_lsa_detail): fix bug of + external route tag byte order. + +2000-03-11 Toshiaki Takada + + * ospf_lsdb.c (ospf_lsdb_insert): New function added. + +2000-03-09 Toshiaki Takada + + * ospf_lsa.c (ospf_external_lsa_install), + (ospf_lsa_lookup), (show_ip_ospf_database_all), + (show_ip_ospf_database_self_originate): Use struct new_lsdb for + LSDB of AS-external-LSAs instead of ospf_lsdb. + + * ospf_lsa.c (ospf_lsa_unique_id): New function added. + Use for assigning Unique Link State ID instead of + ospf_get_free_id_for_prefix(). + +2000-03-09 Toshiaki Takada + + * ospf_ase.c (ospf_ase_calculate_timer): Fix bug of segmentation + fault reported by George Bonser . + +2000-03-07 Libor Pechacek + + * ospfd.c (ospf_interface_down): Fix bug of segmentation fault. + +2000-03-06 Toshiaki Takada + + * ospf_route.c (ospf_route_cmp): Change meaning of return values. + +2000-03-02 Alex Zinin + * ospfd.h, ospf_ia.h + New Shortcut ABR code. Now area's flag can be configured + with Default, Enable, and Disable values. + More info will be in the new ver of I-D soon (see IETF web). + +2000-02-25 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_header_set), (ospf_external_lsa_body_set), + (osfp_external_lsa_originate), (ospf_external_lsa_queue), + (ospf_external_lsa_originate_from_queue): New function added. + (ospf_external_lsa): Function removed. + + * ospf_zebra.c (ospf_zebra_read_ipv4): Originate AS-external-LSA + when listen a route from Zebra, instead creating external route. + + * ospf_asbr.c (ospf_asbr_route_add_flood_lsa), + (ospf_asbr_route_add_queue_lsa), + (ospf_asbr_route_install_lsa), (ospf_asbr_route_add): + Functions removed. + + * ospf_ase.c (process_ase_lsa): Function will not be used. + (ospf_ase_calculate), (ospf_ase_calculate_route_add), + (ospf_ase_calculate_new_route), (ospf_ase_caluculate_asbr_route): + process_ase_lsa () is separated to these functions. + + OSPF AS-external-LSA origination is whole re-organized. + +2000-02-18 Toshiaki Takada + + * ospf_packet.c (ospf_ls_upd): Fix bug of OSPF LSA memory leak. + + * ospf_asbr.c (ospf_asbr_route_add_flood_lsa), + (ospf_asbr_route_add_queue_lsa): Fix bug of OSPF external route + memory leak. + +2000-02-12 Kunihiro Ishiguro + + * ospf_asbr.c (ospf_asbr_route_install_lsa): Re-calculate LSA + checksum after change Advertised Router field. + +2000-02-09 Toshiaki Takada + + * ospf_asbr.c (ospf_external_route_lookup): Add new function. + +2000-02-08 Toshiaki Takada + + * ospfd.c (ospf_router_id_get), (ospf_router_id_update), + (ospf_router_id_update_timer): Router ID decision algorithm is changed. + Router ID is chosen from all of eligible interface addresses even if + it is not enable to OSPF. + +2000-02-08 Toshiaki Takada + + * ospf_asbr.c (ospf_asbr_route_add): Function divided to + ospf_asbr_route_add_flood_lsa, ospf_asbr_route_add_queue_lsa and + ospf_asbr_route_install_lsa. If Router-ID is not set, then LSA is + waited to install to LSDB. + `0.0.0.0 adv_router' AS-external-LSA origination bug was fixed. + +2000-02-01 Sira Panduranga Rao + + * ospf_flood.c (ospf_ls_retransmit_lookup): Compare LS seqnum + in the ACK before deleting. + + * ospf_packet.c (ospf_hello): Reset the flags after a shutdown + and no shutdown of the interface. + +2000-01-31 Toshiaki Takada + + * ospf_packet.c (ospf_ls_req): Send multiple Link State Update + packets respond to a Link State Request packet. + + * ospfd.c (show_ip_ospf_neighbor_detail_sub): Show thread state. + + * ospf_interface.c (ospf_vl_new): Crash when backbone area + is not configured and set virtual-link to no-backbone area, + bug fixed. + +2000-01-30 Kunihiro Ishiguro + + * ospf_neighbor.h (struct ospf_neighbor): Add pointer to last send + LS Request LSA. + + * ospf_packet.c (ospf_ls_upd): Comment out LS request list + treatment. That should be done in OSPF flooding procedure. + + * ospf_flood.c (ospf_flood_through_area): Enclose + ospf_check_nbr_loding inside if-else close. + +2000-01-31 Toshiaki Takada + + * ospf_packet.c (ospf_make_ls_upd): Fix bug of #LSAs counting. + +2000-01-29 Toshiaki Takada + + * ospf_packet.c (ospf_make_md5_digest): Fix bug of md5 authentication. + +2000-01-28 Toshiaki Takada + + * ospfd.c (show_ip_ospf): Show Number of ASE-LSAs. + +2000-01-27 Kunihiro Ishiguro + + * ospf_packet.c (ospf_make_db_desc): Don't use rm_list for + removing LSA from nbr->db_summary. + +2000-01-27 Sira Panduranga Rao + + * ospf_packet.c (ospf_ls_upd_send): Set AllSPFRouters to + destination when the link is point-to-point. + (ospf_ls_ack_send_delayed): Likewise. + +2000-01-27 Kunihiro Ishiguro + + * ospf_flood.c (ospf_ls_request_delete_all): Fix bug of next + pointer lookup after the node is freed. + +2000-01-26 Kunihiro Ishiguro + + * ospf_asbr.c (ospf_asbr_route_add): Instead of scanning all AS + external route, use ospf_top->external_self. + +2000-01-27 Toshiaki Takada + + * ospf_lsa.c (ospf_forward_address_get): New function added. + + * ospf_asbr.c (ospf_asbr_check_lsas): Originate AS-external-LSA + only when it should be replaced. + +2000-01-25 Kunihiro Ishiguro + + * ospf_flood.c (ospf_ls_retransmit_clear): Delete list node. + + * ospf_lsa.c (ospf_lsa_free): Reduce logging message using + ospf_zlog value. + + * ospf_ism.c (ism_change_status): Fix bug of DR -> non DR status + change. Self originated LSA is freed but not deleted from lsdb. + +2000-01-24 Kunihiro Ishiguro + + * ospf_ism.c (ism_interface_down): Don't use router_id for + detecting self neighbor structure. Instead of that compare + pointer itself. + + * ospf_neighbor.c (ospf_nbr_free): Cancel all timer when neighbor + is deleted. + (ospf_nbr_free): Free last send packet. + + * ospf_neighbor.h (struct ospf_neighbor): Remove host strucutre. + Instead of that src is introduced. + + * ospf_nsm.h: Enclose macro defenition with do {} while (0). + +2000-01-17 Kunihiro Ishiguro + + * ospfd.c: Change part of passive interface implementation. For + passive interface just disabling sending/receiving Hello on the + interface. + +2000-01-16 Kai Bankett + + * ospf_interface.h (OSPF_IF_PASSIVE): Add passive flag. + * ospf_interface.c (ospf_if_lookup_by_name): Add new function. + * ospf_lsa.c (ospf_router_lsa): Skip passive interface. + * ospfd.c (passive_interface): New command passive-interface is + added. + (ospf_config_write): Print passive interface. + +2000-01-15 Toshiaki Takada + + * ospf_interface.h (crypt_key): New struct added to store + multiple cryptographic autheitication keys. + (ospf_interface): struct changed. + + * ospf_interface.c: ospf_crypt_key_new, ospf_crypt_key_add, + ospf_crypt_key_lookup, ospf_crypt_key_delete: new functions added. + + * ospf_packet.c (ip_ospf_message_digest_key): Changed to store + multiple cryptographic authentication keys. + +2000-01-14 Toshiaki Takada + + * ospf_interface.c: DEFUN (if_ospf_*) commands changed name to + ip_ospf_* (). + Old notation `ospf *' still remains backward compatibility. + +1999-12-29 Alex Zinin + * ospf_lsa.c: ospf_lsa_more_recent() bug fix + * ospf_nsm.c, ospf_packet.c: remove nbr data struct when + int goes down, also check DD flags correctly (bug fix) + +1999-12-28 Alex Zinin + * "redistribute metric-type (1|2) metric " added + +1999-12-23 Alex Zinin + * added RFC1583Compatibility flag + * added dynamic interface up/down functionality + +1999-11-19 Toshiaki Takada + + * ospf_neighbor.h (struct ospf_neighbor): Add member state_change + for NSM state change statistics. + +1999-11-19 Toshiaki Takada + + * ospfd.c (show_ip_ospf_neighbor_detail), + (show_ip_ospf_neighbor_int_detail): DEFUN Added. + +1999-11-14 Kunihiro Ishiguro + + * ospf_asbr.c (ospf_asbr_check_lsas): Add check of + lsa->refresh_list. + +1999-11-11 Toshiaki Takada + + * ospf_ia.[ch] (OSPF_EXAMINE_SUMMARIES_ALL): Macro added. + This macro is expanded to ospf_examine_summaries () + for SUMMARY_LSA and SUMMARY_LSA_ASBR. + (OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL): Macro added. + This macro is expanded to ospf_examine_transit_summaries () + for SUMMARY_LSA and SUMMARY_LSA_ASBR. + +1999-11-11 Toshiaki Takada + + * ospf_lsa.[ch] (ospf_find_self_summary_lsa_by_prefix): Changed to + macro OSPF_SUMMARY_LSA_SELF_FIND_BY_PREFIX. + (ospf_find_self_summary_asbr_lsa_by_prefix): Changed to + macro OSPF_SUMMARY_ASBR_LSA_SELF_FIND_BY_PREFIX. + (ospf_find_self_external_lsa_by_prefix): Changed to + macro OSPF_EXTERNAL_LSA_SELF_FIND_BY_PREFIX. + +1999-11-11 Toshiaki Takada + + * ospfd.c (ospf_abr_type): ospf_abr_type_cisco, ospf_abr_type_ibm, + ospf_abr_type_shortcut and ospf_abr_type_standard DEFUNs are + combined. + * ospfd.c (no_ospf_abr_type): no_ospf_abr_type_cisco, + no_ospf_abr_type_ibm and no_ospf_abr_type_shortcut DEFUNS are + combined. + +1999-11-10 Toshiaki Takada + + * ospf_route.c (ospf_lookup_int_by_prefix): Move function to + ospf_interface.c and change name to ospf_if_lookup_by_prefix (). + +1999-11-01 Alex Zinin + * ospf_packet.c + some correction to LSU processing + + * ospf_lsa.c ospfd.h + randomize initial LSA refreshment interval + and limit the size of LSA-group to 10 + to let randomization work more effectively. + +1999-10-31 Alex Zinin + * ospf_interface.c + cancel t_network_lsa_self + when freeing int structure + + * ospf_abr.c ospf_asbr.c ospf_flood.c ospf_lsa.c + ospf_lsa.h ospf_lsdb.h ospfd.c ospfd.h + + Summary and ASE LSA refreshment functions + added---LSA refreshment is paced to 70 LSAs + per sec to avoid link overflow. Refreshment events + are further randomized within a 10 sec interval + to avoid syncing. + + Also the sigfault of memcmp() in ospf_lsa_is_different() + is fixed. + +1999-10-30 Alex Zinin + * ospf_nsm.c + Fix the bug where MAX_AGE LSAs + are included into the DB summary. + + * ospf_interface.c + allocate 2*MTU input buffer instead of just MTU + for the cases when the other router mistakenly + sends larger packets thus causing fragmentation, etc. + + * ospf_nsm.c + in nsm_reset_nbr() lists should be freed + not when they are empty. + +1999-10-29 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_acl_hook): Move OSPF_IS_ASBR and OSPF_IS_ABR + check inside of if (ospf_top). + +1999-10-29 Alex Zinin + * ospf_lsa.c ospf_lsdb.c : + add assertion in lsa and lsa->data alloc functions, + as well as in lsdb_add for new->data + + * ospf_lsdb.c: free hash table correctly + +1999-10-28 John Capo + + * ospf_packet.h (OSPF_PACKET_MAX): Correct MAX packet length + calculation + +1999-10-27 Kunihiro Ishiguro + + * OSPF-TRAP-MIB.txt: New file added. Edited version of RFC1850. + + * OSPF-MIB.txt: New file added. Edited version of RFC1850. + +1999-10-27 Alex Zinin + * ospfd, ospf_zebra, ospf_abr + "area import-list" command is added. + This command allows to filter the inter-area routes + injected into an area. Access list hook function + extended to invalidate area exp/imp lists. + +1999-10-25 Yoshinobu Inoue + + * ospfd.c (ospf_interface_run): Enable to detect P2P network + on an OSPF interface. + +1999-10-19 Jordan Mendelson + + * ospf_lsdb.c (ospf_lsdb_add): Fix bug of crash + in ospf_ls_retransmit_lookup (). + +1999-10-19 Vladimir B. Grebenschikov + + * ospf_route.c: Workaround about installation of OSPF routes into + the zebra daemon. Add checking of existance routes. Free + ospf_top->old_table if it exists. + +1999-10-15 Jordan Mendelson + + * Add support for MD5 authentication. + +1999-10-12 Alex Zinin + * ospfd.c, ospfd.h, ospf_abr.c: + a new command "area export-list" was added, it allows + the admin. to control which intra-area routes are + announced to other areas by the ABR + +1999-10-12 Alex Zinin + * ospf_asbr.c (ospf_asbr_check_lsas): Fix bug of coredump + when "no redistribute" is used after a distribute list + denying some networks was used + +1999-10-05 Toshiaki Takada + + * ospf_route.c (ospf_path_dup): New function added. + +1999-10-05 Toshiaki Takada + + * ospf_interface.[ch]: Some of VL related funciton name changed. + +1999-09-27 Alex Zinin + + * ospf_zebra.c: Distribute-list functionality added + +1999-09-27 Toshiaki Takada + + * ospfd.c (show_ip_ospf): Fix bug of segmentation fault when no ospf + instance exists. + +1999-09-25 Kunihiro Ishiguro + + * ospfd.c (ospf_interface_down): Fix bug of misusing nextnode() + instead of node->next. Reported by Hiroki Ishibashi + . + + * ospf_route.c (show_ip_ospf_route): Add check for ospf is enabled + or not. + +1999-09-23 Alex Zinin + + * stub area support added + +1999-09-23 Alex Zinin + + * fwd_addr in ASE-LSAs is now set correctly + * ASE routing changed to check the fwd_addr + and skip the route if the addr points to one + of our interfaces to avoid loops. + +1999-09-22 Alex Zinin + + * ospf_interface: + ospf_vls_in_area() added, it returns + the number of VLs configured through the area + + * ospf_interface.c ospf_lsa.c ospf_lsdb.c ospfd.c + honor correct mem alloc + +1999-09-22 Alex Zinin + + * memory.[ch]: + Some OSPF mem types added, + plus more info in "show mem" + +1999-09-21 Alex Zinin + + * ospfd.c: + "area range substitute" added. + It can be used on NAT-enabled (IP-masquarade) + routers to announce private networks + from an area as public ones into the outside + world (not in the RFC, btw :) + +1999-09-21 Alex Zinin + + * ospfd.c: + "area range suppress" added. + This command allows to instruct the router + to be silent about specific ranges, i.e., + it is a method of route filtering on area + borders + +1999-09-21 Alex Zinin + + * ospfd.c VLs removed when "no network area" executed + +1999-09-20 Alex Zinin + + * ospf_ase.c bug fix for not-zero fwd_addr + and directly connected routes. + +1999-09-20 Yon Uriarte + + * ospf_packet.c (ospf_make_ls_req): Introduce delta value for + checking the length of OSPF packet exceeds MTU or not. + + * ospf_lsa.c (ospf_lsa_different): Apply ntohs for checking + l1->data->length. + +1999-09-18 Alex Zinin + + * ospf_lsa.c bug fix for ospf_network_lsa() to + include itself into the RID list + +1999-09-10 Alex Zinin + + * Alternative ABR behaviors IBM/Cisco/Shortcut + implemented + +1999-09-10 Alex Zinin + + * router and network-LSA origination + changed to honor MinLSInterval + +1999-09-08 Alex Zinin + + * modified ABR behavior to honor VLs and transit + areas + +1999-09-07 Alex Zinin + + * completed VL functionality + +1999-09-06 Kunihiro Ishiguro + + * ospf_asbr.c: New file. + ospf_asbr.h: New file. + + * ospf_zebra.c (ospf_redistribute_connected): Add redistribute + related stuff. + +1999-09-05 Kunihiro Ishiguro + + * ospfd.h (OSPF_FLAG_VIRTUAL_LINK): Change OSPF_FLAG_VEND to + OSPF_FLAG_VIRTUAL_LINK for comprehensiveness. + +1999-09-03 Kunihiro Ishiguro + + * ospf_spf.c (ospf_spf_register): Change name from + ospf_spf_route_add() to ospf_spf_register(). + Include "ospfd/ospf_abr.h" for ospf_abr_task() prototype. + +1999-09-02 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_external_lsa_install): Change to update + lsa->data rather than install new one, when same id lsa is already + installed. + +1999-09-01 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_router_lsa_install): Return lsa value. + (ospf_network_lsa_install): Likewise. + (ospf_summary_lsa_install): Likewise. + (ospf_summary_asbr_lsa_install): Likewise. + (ospf_external_lsa_install): Likewise. + + * ospf_spf.c (ospf_spf_calculate): Comment out debug function + ospf_rtrs_print(). + +1999-08-31 Kunihiro Ishiguro + + * ospf_spf.c (ospf_rtrs_free): Add ospf_spf_calculate() for + freeing rtrs. + +1999-08-31 Toshiaki Takada + + * ospf_lsa.c (show_ip_ospf_database_summary), + (show_ip_ospf_database_summary_asbr), + (show_ip_ospf_database_external): New function added. + `show ip ospf database summary', + `show ip ospf database asbr-summary' + `show ip ospf database external' command can be used. + + * ospf_lsa.c (ospf_lsa_count_table): New function added. + (show_ip_ospf_database_all): show nothing if a type of LSA + does not exist. + +1999-08-31 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_maxage_lsa_remover): Preserve next pointer when + the node is deleted. + +1999-08-31 Toshiaki Takada + + * ospf_flood.c (ospf_ls_retransmit_lookup): change to return + struct ospf_lsa *. + (ospf_ls_request_new), (ospf_ls_request_free), + (ospf_ls_request_add), (ospf_ls_request_delete), + (ospf_ls_request_delete_all), (ospf_ls_request_lookup): + New function added. + + * ospf_packet.c (ospf_ls_upd_send_lsa): New function added. + + * ospf_lsa.h (LS_AGE): Slightly change macro definition. + + * ospf_lsa.c (ospf_lsa_more_recent), (ospf_lsa_diffrent): + Use LS_AGE macro. + +1999-08-30 Alex Zinin + + * ospfd.c + fix a bug with area range config write + added "show ip ospf" command, it will be enhanced later on + +1999-08-30 Alex Zinin + + * ospf_lsa.c + updated ospf_router_lsa() to honor flags (B-bit) + +1999-08-30 Alex Zinin + + * ospf_abr.c + wrote major functions implementing ABR activity + +1999-08-30 Alex Zinin + + * ospf_ia.c ospf_route.c ospf_route.h + fixed the bug with ospf_route.origin field. + Now it holds pointer to lsa_header + +1999-08-30 Alex Zinin + + * ospf_flood.c ospf_flood.h: + transformed ospf_flood_if_select into ospf_flood_through_area() + added new ospf_flood_if_select() and ospf_flood_through_as() + +1999-08-30 Toshiaki Takada + + * ospf_flood.[ch]: New file added. + + * ospf_packet.c (ospf_lsa_flooding), + (ospf_lsa_flooding_select_if): functions move to ospf_flood.c + + * ospf_neighbor.c (ospf_put_lsa_on_retransm_list), + (ospf_remove_lsa_from_retransm_list), + (ospf_nbr_remove_all_lsas_from_retransm_list), + (ospf_lsa_remove_from_ls_retransmit): + (ospf_lsa_retransmit): functions move to + ospf_flood.c, and change function's name: + + ospf_put_lsa_on_retransm_list () + -> ospf_ls_retransmit_add () + ospf_remove_lsa_from_retransm_list () + -> ospf_ls_retransmit_delete () + ospf_nbr_remove_all_lsas_from_retransm_list () + -> ospf_ls_retransmit_clear () + ospf_lsa_remove_from_ls_retransmit () + -> ospf_ls_retransmit_delete_nbr_all () + ospf_lsa_retransmit () + -> ospf_ls_retransmit_add_nbr_all () + + * ospf_lsa.c (ospf_lsa_lookup_from_list): function move to + ospf_flood.c, and change name to ospf_ls_retransmit_lookup (). + +1999-08-30 Kunihiro Ishiguro + + * ospf_neighbor.c (ospf_nbr_lookup_by_addr): Use + route_node_lookup() instead of route_node_get(). + + * ospf_packet.c (ospf_ls_upd): Temporary comment out (6) check. + +1999-08-30 Kunihiro Ishiguro + + * ospf_route.c (ospf_lookup_int_by_prefix): Add check of + oi->address. + +1999-08-29 Alex Zinin + * ospf_lsa.c + MaxAge LSA deletion functions added. + +1999-08-29 Alex Zinin + * ospf_neighbor.c + ospf_nbr_lookup_by_addr(): added route_unlock_node() + when function returns NULL if (rn->info == NULL) + +1999-08-29 Alex Zinin + * ospfd.c + added a hack for area range deletion + +1999-08-29 Alex Zinin + * ospf_lsa.h + included lsdb field into struct ospf_lsa, to find + LSDB easier when removing MaxAge LSAs. + +1999-08-29 Alex Zinin + * ospf_lsa.c ospf_neighbor.c ospf_nsm.c + ospf_packet.c changed to honor new retransmit list + management functions + +1999-08-29 Alex Zinin + * ospf_neighbor.c , .h added new retransmit list functions. + +1999-08-29 Alex Zinin + * Makefile.in + added ospf_ase, ospf_abr, ospf_ia + +1999-08-29 Alex Zinin + * ospf_spf.c: + - changed ospf_next_hop_calculation() to include interface + and nexthop addr for directly connected routers---more informative + and solves problem with route installation into the kernel + - changed ospf_nexthop_out_if_addr() to support routers, not only + transit networks + - added ospf_process_stubs(); + +1999-08-29 Alex Zinin + * ospf_lsa.c: + - changed ospf_router_lsa() to provide correct links + for p-t-p interfaces; + - changed ospf_summary_lsa_install() to support table + of self-originated summary-LSAs; + - added ospf_summary_asbr_lsa_install() and ospf_external_lsa_install() + - changed ospf_lsa_install() accordingly + - changed show_ip_ospf_database_router_links() to support p-t-p + +1999-08-29 Kunihiro Ishiguro + + * ospf_packet.c (ospf_make_db_desc): Only master can clear more + flag. + +1999-08-29 Kunihiro Ishiguro + + * ospf_packet.c (ospf_read): Add check of IP src address. + +1999-08-28 Alex Zinin + * ospf_neighbor.h + added ospf_nbr_lookup_by_routerid() + +1999-08-28 Alex Zinin + * ospfd.h + added ABR/ASBR flag definitions and fields; + added iflist field to area structure; + summary_lsa_self and summary_lsa_asbr_self are changed + to be route tables; + added ranges field---configured area ranges; + A separate Routers RT added; + area range config commands and config write added + + +1999-08-28 Alex Zinin + * ospf_route.c : + ospf_route_free()--added code to free the list of paths; + The following functions added: + ospf_intra_add_router(); + ospf_intra_add_transit(); + ospf_intra_add_stub(); + the last function uses new ospf_int_lookup_by_prefix(); + show_ip_ospf_route_cmd()--changed to support new RT structure; + added ospf_cmp_routes()--general route comparision function; + added ospf_route_copy_nexthops() and ospf_route_copy_nexthops_from_vertex() + they are used in ASE and IA routing; + added ospf_subst_route() and ospf_add_route(); + +1999-08-28 Alex Zinin + * ospf_route.h : + changed struct ospf_path to include output interface, + changed struct ospf_route to support IA and ASE routing. + added prototypes of the function used in IA and ASE modules. + +1999-08-28 Alex Zinin + * ospf_lsa.h ospf_lsa.c : + added ospf_my_lsa(), an interface independent version of + ospf_lsa_is_self_originated(), it will be used in ASE and IA-routing. + +1999-08-27 Kunihiro Ishiguro + + * ospf_interface.c (interface_config_write): Add check for + oi->nbr_self. + +1999-08-25 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_dup): New function added. + + * ospf_packet.c (ospf_write), (ospf_read): Print send/recv + interface in debug message. + +1999-08-25 Toshiaki Takada + + * ospf_packet.c (ospf_ls_ack_send): The name is changed from + `ospf_ls_ack_send'. + (ospf_ls_ack_send_delayed) (ospf_ls_ack_timer): New function added. + Delayed Link State Acknowledgment is scheduled by timer. + +1999-08-25 Alex Zinin + + * ospf_lsa.c (ospf_router_lsa): Incorrectly included link to + a stub network instead of link to a transit network into + originated router-LSA, bug fixed. + +1999-08-24 Toshiaki Takada + + * ospfd.c (ospf_update_router_id): New function added. + + * ospf_network.c (ospf_write): Create new socket per transmission. + And select outgoing interface whether dst is unicast or multicast. + + * ospf_packet.c: LSA flooding will work. + +1999-08-24 VOP + + * ospf_route.c: Include "sockunion.h" + +1999-08-24 Kunihiro Ishiguro + + * ospf_network.c (ospf_serv_sock_init): Enclose + IPTOS_PREC_INTERNETCONTROL setting with #ifdef for OS which does + not have the definition. + +1999-08-23 Toshiaki Takada + + * ospf_packet.c: Fix bug of DD processing. + +1999-08-18 Toshiaki Takada + + * ospf_lsa.c (show_ip_ospf_database): Show actual `LS age'. + +1999-08-17 Toshiaki Takada + + * ospf_lsa.h (OSPF_MAX_LSA): The value of OSPF_MAX_LSA is + corrected. The bug of `mes_lookup' is fixed. + This had been reported by Poul-Henning Kamp . + + * ospf_lsa.c (ospf_router_lsa_install): The name is changed from + `ospf_add_router_lsa'. + (ospf_network_lsa_install): The name is changed from + `ospf_add_network_lsa'. + + * ospf_interface.h (ospf_interface): Add member `nbr_self'. + + * ospf_interface.c (ospf_if_is_enable): New function added. + +1999-08-16 Toshiaki Takada + + * ospf_lsa.h (struct lsa_header): The name is changed from + `struct ospf_lsa'. + (struct ospf_lsa): New struct added to control each LSA's aging + and timers. + + * ospf_lsa.c (ospf_lsa_data_free): The name is change from + `ospf_lsa_free'. + (ospf_lsa_data_new), (ospf_lsa_new), (ospf_lsa_free), + (ospf_lsa_different), (ospf_lsa_install): New function added. + + * ospf_packet.c (ospf_ls_upd_list_lsa): New function added. + +1999-08-12 Toshiaki Takada + + * ospf_nsm.c (nsm_reset_nbr): New function added. + KillNbr and LLDown neighbor event call this function. + +1999-08-10 Toshiaki Takada + + * ospf_packet.c (ospf_ls_retransmit) + (ospf_ls_upd_timer): New function added. + Set retransmission timer for Link State Update. + +1999-07-29 Toshiaki Takada + + * ospf_ism.c (ospf_dr_election): Fix bug of DR election. + +1999-07-28 Toshiaki Takada + + * ospf_network.c (ospf_serv_sock_init): Set IP precedence field + with IPTOS_PREC_INTERNET_CONTROL. + + * ospf_nsm.c (nsm_change_status): Schedule NeighborChange event + if NSM status change. + + * ospf_packet.c (ospf_make_hello): Never include a neighbor in + Hello packet, when the neighbor goes down. + +1999-07-26 Kunihiro Ishiguro + + * Makefile.am (noinst_HEADERS): Add ospf_route.h. + + * ospf_route.c (show_ip_ospf_route): Add `show ip ospf route' + command. + +1999-07-25 Toshiaki Takada + + * ospf_lsa.c (ospf_router_lsa): Fix bug of LS sequence number + assignement. + +1999-07-25 Kunihiro Ishiguro + + * ospf_route.c (ospf_route_table_free): New function added. + + * ospf_spf.c (ospf_spf_next): Free vertex w when cw's and w's + distance is same. + + * ospfd.h (struct ospf): Add old_table. + + * ospf_main.c (sighup): Call of log_rotate () removed. + + * ospf_lsa.c (ospf_lsa_is_self_originated): Fix bug of checking + area->lsa as self LSA. This should be area->lsa_self. + +1999-07-24 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_zebra_add): ospf_zebra_add + (),ospf_zebra_delete () added. + + * ospf_spf.c (ospf_spf_calculate): Call ospf_intra_route_add (). + +1999-07-24 Toshiaki Takada + + * ospf_lsa.c: Change LS sequence number treatment. + (ospf_lsa_is_self_originated): New function added. + (show_ip_ospf_database_self_originated): New DEFUN added. + +1999-07-23 Kunihiro Ishiguro + + * ospf_interface.c (ospf_if_lookup_by_addr): Add loopback check. + +1999-07-22 Toshiaki Takada + + * ospf_spf.c (ospf_nexthop_new), (ospf_nexthop_free), + (ospf_nexthop_dup): function added. + (ospf_nexthop_calculation): function changed. + + * ospf_interface.c (ospf_if_lookup_by_addr): function added. + +1999-07-21 Toshiaki Takada + + * ospf_spf.c (ospf_spf_closest_vertex): function removed. + +1999-07-21 Kunihiro Ishiguro + + * ospf_spf.c (ospf_spf_next): Apply ntohs for fetching metric. + +1999-07-21 Toshiaki Takada + + * ospf_neighbor.c (ospf_nbr_lookup_by_router_id): fundtion removed. + + * ospf_lsa.c (show_ip_ospf_database_router): describe each + connected link. + +1999-07-21 Kunihiro Ishiguro + + * ospf_spf.c (ospf_spf_next): V is router LSA or network LSA so + change behavior according to LSA type. + (ospf_lsa_has_link): Link check function is added. + +1999-07-20 Kunihiro Ishiguro + + * ospf_spf.c (ospf_spf_calculate_schedule): Add new function for + SPF calcultion schedule addtition. + (ospf_spf_calculate_timer_add): Rough 30 sec interval SPF calc + timer is added. + (ospf_spf_next_router): Delete ospf_spf_next_network (). + + * ospf_lsa.c (show_ip_ospf_database_all): Network-LSA display + header typo correction. Display of router LSA's #link added. + +1999-07-19 Toshiaki Takada + + * ospf_packet.c (ospf_check_network_mask): Added new function for + receiving Raw IP packet on an appropriate interface. + +1999-07-16 Toshiaki Takada + + * ospfd.c (ospf_router_id): new DEFUN added. + +1999-07-15 Toshiaki Takada + + * ospf_spf.c (ospf_spf_init), (ospf_spf_free), + (ospf_spf_has_vertex), (ospf_vertex_lookup), + (ospf_spf_next_router), (ospf_spf_next_network), + (ospf_spf_closest_vertex), (ospf_spf_calculate): + function added. + +1999-07-13 Toshiaki Takada + + * ospf_ism.c: fix bug of DR Election. + + * ospf_nsm.c: fix bug of adjacency forming. + +1999-07-05 Kunihiro Ishiguro + + * ospfd.c (ospf_init): Change to use install_default. + +1999-07-01 Rick Payne + + * ospf_zebra.c (zebra_init): Install standard commands to + ZEBRA_NODE. + +1999-06-30 Toshiaki Takada + + * ospf_dump.c: Whole debug command is improved. + (ISM|NSM) (events|status|timers) debug option added. + (show_debugging_ospf): new DEFUN added. + +1999-06-30 Kunihiro Ishiguro + + * ospf_lsa.c (ospf_lsa_lookup_from_list): Change !IPV4_ADDR_CMP to + IPV4_ADDR_SAME. + +1999-06-29 Toshiaki Takada + + * ospf_dump.c (ospf_summary_lsa_dump): Add summary-LSA dump routine. + (ospf_as_external_lsa_dump): Add AS-external-LSA dump routine. + + * ospf_nsm.c (nsm_twoway_received): fix condtion of adjacnet. + + * ospf_ism.c (ospf_dr_election): fix DR Election. + + * ospf_dump.c (ospf_nbr_state_message): fix `show ip ospf neighbor' + command's state. + +1999-06-29 Kunihiro Ishiguro + + * ospf_dump.c (ospf_router_lsa_dump): Add router-LSA dump routine. + +1999-06-28 Toshiaki Takada + + * ospf_lsa.c (show_ip_ospf_database_network): fix bug of + `show ip ospf database network' command output. + + * ospf_nsm.c (nsm_inactivity_timer): Clear list of Link State + Retransmission, Database Summary and Link State Request. + + * ospf_packet.c (ospf_ls_req_timer): New function added. + Set Link State Request retransmission timer. + +1999-06-27 Kunihiro Ishiguro + + * ospf_main.c (main): Change default output from ZLOG_SYSLOG to + ZLOG_STDOUT. + + * ospfd.c (ospf_init): Register show_ip_ospf_interface_cmd and + show_ip_ospf_neighbor_cmd to VIEW_NODE. + + * ospf_lsa.c (ospf_lsa_init): Register show_ip_ospf_database_cmd + and show_ip_ospf_database_type_cmd to VIEW_NODE. + +1999-06-25 Toshiaki Takada + + * ospf_packet.c: fix bug of DD making. + fix bug of LS-Update reading. + +1999-06-23 Toshiaki Takada + + * ospf_packet.c: All type of packets are changed to use + fifo queue structure. + (ospf_fill_header) function added. + +1999-06-22 Toshiaki Takada + + * ospf_packet.c (ospf_packet_new): New function added to handle + sending ospf packet by fifo queue structure. + (ospf_packet_free), (ospf_fifo_new), (ospf_fifo_push), + (ospf_fifo_pop), (ospf_fifo_head), (ospf_fifo_flush), + (ospf_fifo_free): Likewise. + +1999-06-21 Toshiaki Takada + + * ospf_nsm.c (ospf_db_desc_timer): function added. + (nsm_timer_set) function added. + * ospf_dump.c (ospf_option_dump): function added. + * ospf_packet.c (ospf_ls_req) (ospf_make_ls_req): function added. + +1999-06-20 Toshiaki Takada + + * ospf_lsa.c (ospf_lsa_more_recent): function added. + * ospf_neighbor.h (struct ospf_neighbor): Change member ms_flag + to dd_flags. + +1999-06-19 Toshiaki Takada + + * ospf_lsa.c: DEFUN (show_ip_ospf_database) Added. + * ospf_interface.c (if_ospf_cost), (if_ospf_dead_interval), + (if_ospf_hello_interval), (if_ospf_priority), + (if_ospf_retransmit_interval), (if_ospf_transmit_delay) + argument changed from NUMBER to . + DEFUN (if_ospf_network_broadcast), + DEFUN (if_ospf_network_non_broadcast), + DEFUN (if_ospf_network_point_to_multipoint), + DEFUN (if_ospf_network_point_to_point) functions are combined to + DEFUN (if_ospf_network). + +1999-06-18 Toshiaki Takada + + * ospf_lsa.c: ospf_add_router_lsa (), ospf_add_network_lsa (), + ospf_lsa_lookup (), ospf_lsa_count () Added. + +1999-06-15 Toshiaki Takada + + * DEFUN (ospf_debug_ism), DEFUN (ospf_debug_nsm), + DEFUN (no_ospf_debug_ism), DEFUN (no_ospf_debug_nsm) Added. + `debug ospf ism' command shows debug message. + `debuf ospf nsm' command shows debug message. + +1999-06-14 Toshiaki Takada + + * ospf_lsa.c: ospf_network_lsa () Added. + ospf_lsa_checksum () Added. + * DEFUN (ospf_debug_packet), DEFUN (no_ospf_debug_packet) Added. + `debug ospf packet' command shows debug message. + +1999-06-13 Toshiaki Takada + + * ospf_packet.h: Remove struct ospf_ls_req {}, ospf_ls_upd {}, + ospf_ls_ack {}. + +1999-06-11 Toshiaki Takada + + * ospf_dump.c: fix IP packet length treatment. + +1999-06-10 Toshiaki Takada + + * ospf_ism.h: Add OSPF_ISM_EVENT_EXECUTE() Macro Added. + * ospf_nsm.h: Add OSPF_NSM_EVENT_EXECUTE() Macro Added. + + * ospf_packet.c: ospf_db_desc (), ospf_db_desc_send () Added. + ospf_make_hello (), ospf_make_db_desc () Added. + ospf_db_desc_proc () Added.n + + * Database Description packet can be processed. + +1999-06-08 Toshiaki Takada + + * ospf_lsa.c: New file. + +1999-06-07 Toshiaki Takada + + * ospf_neighbor.c: ospf_fully_adjacent_count () Added. + +1999-06-07 Kunihiro Ishiguro + + * ospf_spf.[ch]: New file. + +1999-05-30 Kunihiro Ishiguro + + * ospf_zebra.c: Changed to use lib/zclient.c routines. + + * ospf_zebra.h (zebra_start): Remove struct zebra. + +1999-05-29 Kunihiro Ishiguro + + * ospfd.c (ospf_config_write): Add cast (unsigned long int) to + ntohl for sprintf warning. + +1999-05-19 Toshiaki Takada + + * ospf_ism.c (ospf_dr_election): Join AllDRouters Multicast group + if interface state changes to DR or BDR. + +1999-05-14 Stephen R. van den Berg + + * ospf_main.c (signal_init): SIGTERM call sigint. + (sigint): Logging more better message. + +1999-05-12 Toshiaki Takada + + * ospfd.c: Fix bug of `no router ospf' statement, it will work. + +1999-05-11 Toshiaki Takada + + * ospf_neighbor.c: ospf_nbr_free () Added. + +1999-05-10 Toshiaki Takada + + * ospfd.h: struct ospf_area { }, struct ospf_network { } Changed. + * Fix bug of `no network' statement, it will work. + +1999-05-07 Toshiaki Takada + + * ospf_interface.c, ospf_zebra.c: Fix bug of last interface is not + updated by ospf_if_update (). + +1999-04-30 Kunihiro Ishiguro + + * Makefile.am (noinst_HEADERS): Add ospf_lsa.h for distribution. + +1999-04-25 Toshiaki Takada + + * ospf_interface.c: DEFUN (no_if_ospf_cost), + DEFUN (no_if_ospf_dead_interval), + DEFUN (no_if_ospf_hello_interval), + DEFUN (no_if_ospf_priority), + DEFUN (no_if_ospf_retransmit_interval), + DEFUN (no_if_ospf_transmit_delay) Added. + + interface_config_write () suppress showing interface + default values. + +1999-04-25 Kunihiro Ishiguro + + * ospf_dump.c (ospf_timer_dump): If thread is NULL return "inactive". + + * ospfd.c (ospf_if_update): Fix bug of using ospf_area { } instead + of ospf_network { }. So `router ospf' statement in ospfd.conf + works again. + (ospf_if_update): Call ospf_get_router_id for updating router ID. + +1999-04-25 Toshiaki Takada + + * ospf_interface.c: DEFUN (if_ospf_network) deleted. + DEFUN (if_ospf_network_broadcast), + DEFUN (if_ospf_network_non_broadcast), + DEFUN (if_ospf_network_point_to_multipoint), + DEFUN (if_ospf_network_point_to_point), + DEFUN (no_if_ospf_network) Added. + +1999-04-23 Toshiaki Takada + + * ospfd.h: struct area { } changed to struct ospf_network { }. + Add struct ospf_area { }. + * ospfd.c: Add ospf_area_lookup_by_area_id (), ospf_network_new (), + and ospf_network_free (). + DEFUN (area_authentication), DEFUN (no_area_authentication) Added. + +1999-04-22 Toshiaki Takada + + * ospf_lsa.h: New file. + * ospf_packet.h: LSA related struct definition are moved to + ospf_lsa.h. + * ospf_packet.c: ospf_verify_header () Added. + +1999-04-21 Toshiaki Takada + + * ospf_ism.c: ospf_elect_dr () and related function is changed. + DR Election bug fixed. + * ospf_dump.c: ospf_nbr_state_message (), ospf_timer_dump () Added. + * ospfd.c: DEFUN (show_ip_ospf_neighbor) Added. + +1999-04-19 Kunihiro Ishiguro + + * ospf_main.c (main): access_list_init () is added for vty + connection filtering. + +1999-04-16 Toshiaki Takada + + * ospfd.c: DEFUN (show_ip_ospf_interface) Added. + * ospf_neighbor.c: ospf_nbr_count () Added. + +1999-04-15 Toshiaki Takada + + * ospfd.h: struct ospf { } Changed. + * ospfd.c: ospf_lookup_by_process_id () Deleted. + * ospf_ism.c: ospf_wait_timer () Added. WaitTimer will work. + +1999-04-14 Toshiaki Takada + + * ospf_ism.c: ospf_elect_dr () Added. + * ospf_network.c: ospf_if_ipmulticast () Added. + +1999-04-11 Toshiaki Takada + + * ospf_interface.c: interface_config_write (), + DEFUN (if_ip_ospf_cost), + DEFUN (if_ip_ospf_dead_interval), + DEFUN (if_ip_ospf_hello_interval), + DEFUN (if_ip_ospf_priority), + DEFUN (if_ip_ospf_retransmit_interval) and + DEFUN (if_ip_ospf_transmit_delay) Added. + +1999-04-08 Toshiaki Takada + + * ospf_dump.c: ospf_packet_db_desc_dump () Added. + * ospf_neighbor.c: ospf_nbr_bidirectional () Added. + * ospf_nsm.c: nsm_twoway_received () Added. + +1999-04-02 Toshiaki Takada + + * ospf_neighbor.c: New file. + * ospf_neighbor.h: New file. + * ospf_nsm.c: New file. + * ospf_nsm.h: New file. + * ospf_packet.c: Add ospf_make_header (), ospf_hello () and + ospf_hello_send (). Now OSPFd can receive Hello and send Hello. + +1999-03-27 Kunihiro Ishiguro + + * ospf_packet.c: Add ospf_recv_packet (). Now OSPF Hello can receive. + +1999-03-19 Toshiaki Takada + + * ospf_packet.c: New file. + * ospf_packet.h: New file. + * ospf_network.c: New file. + * ospf_network.h: New file. + * ospfd.h: move OSPF message structure has moved to ospf_packet.h. + +1999-03-17 Kunihiro Ishiguro + + * ospf_zebra.c (ospf_zebra_get_interface): Fix for IPv6 interface + address. + + * Makefile.am (install-sysconfDATA): Overwrite install-sysconfDATA + for install ospfd.conf.sample as owner read only file. + + * ospf_main.c (usage): Change to use ZEBRA_BUG_ADDRESS. + +1999-03-15 Toshiaki Takada + + * ospf_ism.c: New file. + * ospf_ism.h: New file. + * ospf_dump.c: New file. + * ospf_dump.h: New file. + + * ospfd.h: Add (struct ospf), (struct config_network), + (struct message) structure. + + * ospf_interface.c: Add ospf_if_match_network (). + * ospf_interface.h (struct ospf_interface): Change struct members. + + * ospfd.c: ospf_lookup_by_process_id (), ospf_network_new (), + DEFUN (network_area): Added. + + * ospfd.conf.sample: Change sample configuration. + +1999-03-05 Toshiaki Takada + + * ospf_interface.c: New file. + * ospf_interface.h: New file. + * ospf_zebra.h: New file. + * ospf_zebra.c: Add interface function for zebra daemon. + * ospfd.c: New file. + +1999-02-23 Kunihiro Ishiguro + + * Move IPv6 codes and files to ospf6d directory. + +1999-02-18 Peter Galbavy + + * syslog support added + +1998-12-22 Toshiaki Takada + + * ospfd.h: New file. + * ospf_lsa.h: New file. + +1998-12-15 Kunihiro Ishiguro + + * Makefile.am: New file. + * ospf_main.c: New file. + diff --git a/ospfd/ChangeLog.opaque.txt b/ospfd/ChangeLog.opaque.txt new file mode 100644 index 0000000..782e332 --- /dev/null +++ b/ospfd/ChangeLog.opaque.txt @@ -0,0 +1,221 @@ +----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- +Changes 2002.12.20 + +1. Bug fixes + + 1.1 When an opaque LSA is being removed from (or added to) the LSDB, + it does not mean a change in network topology. Therefore, SPF + recalculation should not be triggered in that case. + There was an assertion failure problem "assert (rn && rn->info)" + inside the function "ospf_ase_incremental_update()", because + the upper function "ospf_lsa_maxage_walker_remover()" called it + when a type-11 opaque LSA is removed due to MaxAge. + + 1.2 Type-9 LSA is defined to have "link-local" flooding scope. + In the Database exchange procedure with a new neighbor, a type-9 + LSA was added in the database summary of a DD message, even if + the link is different from the one that have bound to. + +2. Feature enhancements + + 2.1 Though a "wildcard" concept to handle type-9/10/11 LSAs altogether + has introduced about a year ago, it was only a symbol definition + and actual handling mechanism was not implemented. Now it works. + +----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- +Changes 2002.7.8 + +1. Bug fixes + + 1.1 When "ospf_delete_opaque_functab()" is called, internal structure + "oipt" remain unfreed. If register/delete functab is repeated, + illegal memory access happens due to this "oipt". + + 1.2 In "free_opaque_info_per_id()", there was a crucial typo which + ignores a condition test. + + "if (oipi->lsa != NULL);" <-- semicolon! + +2. Feature enhancements + + None. + +----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- +Changes 2001.12.03 + +1. Bug fixes + + 1.1 Though a new member "oi" has added to "struct ospf_lsa" to control + flooding scope of type-9 Opaque-LSAs, the value was always NULL + because no one set it. + + 1.2 In the function "show_ip_ospf_database_summary()" and "show_lsa_ + detail_adv_router()", VTY output for type-11 Opaque-LSAs did not + work properly. + + 1.3 URL for the opaque-type assignment reference has changed. + + 1.4 In the file "ospf_mpls_te.c", printf formats have changed to + avoid compiler warning messages; "%lu" -> "%u", "%lx" -> "%x". + Note that this hack depends on OS, compiler and their versions. + + 1.5 One of attached documentation "opaque_lsa.txt" has changed to + reflect the latest coding. + +2. Feature enhancements + + 2.1 Knowing that it is an ugly hack, an "officially unallocated" + opaque-type value 0 has newly introduced as a "wildcard", + which matches to all opaque-type. + This value must not be flooded to the network, of course. + + 2.2 The Opaque-core module makes use of newly introduced hooks to + dispatch every LSDB change (LSA installation and deletion) to + preregistered opaque users. + Therefore, by providing appropriate callback functions as new + parameters of "ospf_register_opaque_functab()", an opaque user + can refer to every LSA instance to be installed into, or to be + deleted from, the LSDB. + +----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- +Changes 2001.10.31 + +1. Bug fixes + + 1.1 Since each LSA has their own lifetime, they will remain in a + routing domain (being stored in LSDB of each router), until their + age naturally reach to MaxAge or explicitly being flushed by the + originated router. Therefore, if a router restarted with a short + downtime, it is possible that previously flooded self-originated + LSAs might received if the NSM status is not less than Exchange. + + There were some problems in the way of handling self-originated + Opaque-LSAs if they are contained in a received LSUpd message, + but not installed to the local LSDB yet. + Regardless of some conditions to start originating Opaque-LSAs + (there should be at least one opaque-capable full-state neighbor), + the function "ospf_flood()" will be called to flood and install + this brand-new looking LSA. + As the result, when the NSM of an opaque-capable neighbor gets + full, internal state inconsistency happens; a user of Opaque-LSA + such as MPLS-TE can refer to self-originated LSAs in the local + LSDB, but cannot modify their contents... + + Above problems have fixed with a policy "flush it from the whole + routing domain and keep silent until the flushing completed". + By using this sweeping technique, we can be free from confusion + caused by self-originated LSAs received via network. + + 1.2 The function "ospf_opaque_type_name()" contained massive ifdefs + corresponding to each "opaque-type". + These unnecessary ifdefs are removed completely. + + 1.3 In the function "ospf_delete_opaque_functab()", there was an + improper loop control that causes illegal memory access. + Original coding was "next = nextnode (node)". + + 1.4 The function "ospf_mpls_te_ism_change()" could not handle the + case when the ISM changes from Waiting to DR/BDR/Other. + So, there was a case that even if one of an ISM become + operational and MPLS-TE module has started, the corresponding + Opaque-LSA cannot be originated. + + 1.5 The function "ospf_opaque_lsa_reoriginate_schedule()" did not + allow to be called multiple times, simply because handling + module for the given "lsa-type & opaque-type" already exists. + But this assumption seems to be wrong. + Change the policy to allow this function to be called multiple + times and let the caller to decide what should do when the + corresponding callback function "(* functab->lsa_originator)()" + is called. + +2. Feature enhancements + + 2.1 The global bitmap "opaque" has introduced instead of former flag + "OpaqueCapable", to store complex conditions to handle Opaque-LSAs. + + 2.2 The MPLS-TE module now referes to "draft-katz-yeung-ospf-traffic + -06.txt", no significant changes with 05 version, though. + +----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- +Changes 2001.08.03 + +1. Bug fixes + + 1.1 Even if the ospfd started with opaque capability enabled, when + the ospfd receives an unknown opaque-type (unregistered by the + function "ospf_register_opaque_functab()" beforehand), the LSA + was discarded. As the result, only the opaque-LSAs that have + commonly registered by opaque-capable ospf routers can be + flooded in a routing domain. + + This behavior has fixed so that arbitrary opaque-type LSAs can + be flooded among opaque-capable ospf routers. + If the ospfd has opaque-LSA capability but disabled at runtime, + received opaque-LSAs can be accepted and registered to LSDB as + is, but not be flooded to the network; those opaque LSAs will + remain in LSDB until explicitly flushed by incoming LSUpd + messages with MaxAge, or their age naturally reaches to MaxAge. + + 1.2 The function "ospf_register_opaque_functab()" did not check + if the entry corresponding to the given "lsa-type, opaque-type" + combination already exists or not. + This problem has fixed not to allow multiple registration. + + 1.3 Since type-11 (AS external) LSAs will be flooded beyond areas, + there is little relationship between "struct lsa" and "struct + area". More specifically, the pointer address "lsa->area" can + be NULL if the lsa-type is 11, thus an illegal memory access + will happen. This problem has fixed. + + 1.4 When self-originated opaque-LSAs are received via network and + if the corresponding opaque-type functions are not available + (they have already deleted) at that time, those LSAs were + dropped due to "unknown opaque-type" error. + After the problem 1.1 has fixed, those "self-originated" LSAs + were registered to LSDB and then flooded to the network, even + if the processing functions did not exist... + + After all, this problem has fixed so that those LSAs should + explicitly be flushed from the routing domain immediately, if + the processing functions cannot find at that time. + + 1.5 Some typo have fixed. + + --- EXAMPLE --- + static int + opaque_lsa_originate_callback (list funclist, void *lsa_type_dependent) + ^^^^^ + --- EXAMPLE --- + +2. Feature enhancements + + 2.1 According to the description of rfc2328 in section 10.8, any + change in the router's optional capabilities should trigger + the option re-negotiation procedures with neighbors. + + --- EXCERPT --- + If for some reason the router's optional + capabilities change, the Database Exchange procedure should be + restarted by reverting to neighbor state ExStart. + --- EXCERPT --- + + For the opaque-capability changes, this feature has implemented. + More specifically, if "ospf opaque-lsa" or "no ospf opaque-lsa" + VTY command is given at runtime, all self-originated LSAs will + be flushed immediately and then all neighbor status will be + forced to ExStart by generating SeqNumberMismatch events. + + 2.1 When we change opaque-capability dynamically (ON -> OFF -> ON), + there was no trigger at "OFF->ON" timing to reactivate opaque + LSA handling modules (such as MPLS-TE) that have once forcibly + stopped at "ON->OFF" timing. + Now this dynamic reactivation feature has added. + + 2.2 The MPLS-TE module now referes to "draft-katz-yeung-ospf-traffic + -05.txt", no significant changes with 04 version, though. + +----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- +Changes 2001.03.28 + + Initial release of Opaque-LSA/MPLS-TE extensions for the zebra/ospfd. diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am new file mode 100644 index 0000000..2b90580 --- /dev/null +++ b/ospfd/Makefile.am @@ -0,0 +1,44 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +noinst_LIBRARIES = libospf.a +sbin_PROGRAMS = ospfd + +libospf_a_SOURCES = \ + ospfd.c ospf_zebra.c ospf_interface.c ospf_ism.c ospf_neighbor.c \ + ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \ + ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \ + ospf_lsdb.c ospf_asbr.c ospf_routemap.c ospf_snmp.c \ + ospf_opaque.c ospf_te.c ospf_vty.c + +noinst_HEADERS = \ + ospf_dump.h ospf_interface.h ospf_ism.h ospf_neighbor.h \ + ospf_network.h ospf_nsm.h ospf_packet.h ospf_zebra.h ospfd.h \ + ospf_lsa.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ + ospf_flood.h ospf_lsdb.h ospf_asbr.h ospf_snmp.h ospf_opaque.h \ + ospf_te.h ospf_vty.h + +ospfd_SOURCES = \ + ospf_main.c $(libospf_a_SOURCES) + +ospfd_LDADD = ../lib/libzebra.a + +sysconf_DATA = ospfd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) OSPF-MIB.txt OSPF-TRAP-MIB.txt ChangeLog.opaque.txt + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done diff --git a/ospfd/Makefile.in b/ospfd/Makefile.in new file mode 100644 index 0000000..7182572 --- /dev/null +++ b/ospfd/Makefile.in @@ -0,0 +1,461 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CPP = @CPP@ +CURSES = @CURSES@ +DEPDIR = @DEPDIR@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LIBPAM = @LIBPAM@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ +DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA = @INSTALL@ -m 600 + +noinst_LIBRARIES = libospf.a +sbin_PROGRAMS = ospfd + +libospf_a_SOURCES = \ + ospfd.c ospf_zebra.c ospf_interface.c ospf_ism.c ospf_neighbor.c \ + ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \ + ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \ + ospf_lsdb.c ospf_asbr.c ospf_routemap.c ospf_snmp.c \ + ospf_opaque.c ospf_te.c ospf_vty.c + + +noinst_HEADERS = \ + ospf_dump.h ospf_interface.h ospf_ism.h ospf_neighbor.h \ + ospf_network.h ospf_nsm.h ospf_packet.h ospf_zebra.h ospfd.h \ + ospf_lsa.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ + ospf_flood.h ospf_lsdb.h ospf_asbr.h ospf_snmp.h ospf_opaque.h \ + ospf_te.h ospf_vty.h + + +ospfd_SOURCES = \ + ospf_main.c $(libospf_a_SOURCES) + + +ospfd_LDADD = ../lib/libzebra.a + +sysconf_DATA = ospfd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) OSPF-MIB.txt OSPF-TRAP-MIB.txt ChangeLog.opaque.txt +subdir = ospfd +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libospf_a_AR = $(AR) cru +libospf_a_LIBADD = +am_libospf_a_OBJECTS = ospfd.$(OBJEXT) ospf_zebra.$(OBJEXT) \ + ospf_interface.$(OBJEXT) ospf_ism.$(OBJEXT) \ + ospf_neighbor.$(OBJEXT) ospf_nsm.$(OBJEXT) ospf_dump.$(OBJEXT) \ + ospf_network.$(OBJEXT) ospf_packet.$(OBJEXT) ospf_lsa.$(OBJEXT) \ + ospf_spf.$(OBJEXT) ospf_route.$(OBJEXT) ospf_ase.$(OBJEXT) \ + ospf_abr.$(OBJEXT) ospf_ia.$(OBJEXT) ospf_flood.$(OBJEXT) \ + ospf_lsdb.$(OBJEXT) ospf_asbr.$(OBJEXT) ospf_routemap.$(OBJEXT) \ + ospf_snmp.$(OBJEXT) ospf_opaque.$(OBJEXT) ospf_te.$(OBJEXT) \ + ospf_vty.$(OBJEXT) +libospf_a_OBJECTS = $(am_libospf_a_OBJECTS) +sbin_PROGRAMS = ospfd$(EXEEXT) +PROGRAMS = $(sbin_PROGRAMS) + +am__objects_1 = ospfd.$(OBJEXT) ospf_zebra.$(OBJEXT) \ + ospf_interface.$(OBJEXT) ospf_ism.$(OBJEXT) \ + ospf_neighbor.$(OBJEXT) ospf_nsm.$(OBJEXT) ospf_dump.$(OBJEXT) \ + ospf_network.$(OBJEXT) ospf_packet.$(OBJEXT) ospf_lsa.$(OBJEXT) \ + ospf_spf.$(OBJEXT) ospf_route.$(OBJEXT) ospf_ase.$(OBJEXT) \ + ospf_abr.$(OBJEXT) ospf_ia.$(OBJEXT) ospf_flood.$(OBJEXT) \ + ospf_lsdb.$(OBJEXT) ospf_asbr.$(OBJEXT) ospf_routemap.$(OBJEXT) \ + ospf_snmp.$(OBJEXT) ospf_opaque.$(OBJEXT) ospf_te.$(OBJEXT) \ + ospf_vty.$(OBJEXT) +am_ospfd_OBJECTS = ospf_main.$(OBJEXT) $(am__objects_1) +ospfd_OBJECTS = $(am_ospfd_OBJECTS) +ospfd_DEPENDENCIES = ../lib/libzebra.a +ospfd_LDFLAGS = +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ospf_abr.Po ./$(DEPDIR)/ospf_asbr.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_ase.Po ./$(DEPDIR)/ospf_dump.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_flood.Po ./$(DEPDIR)/ospf_ia.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_interface.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_ism.Po ./$(DEPDIR)/ospf_lsa.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_lsdb.Po ./$(DEPDIR)/ospf_main.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_neighbor.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_network.Po ./$(DEPDIR)/ospf_nsm.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_opaque.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_packet.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_route.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_routemap.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_snmp.Po ./$(DEPDIR)/ospf_spf.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_te.Po ./$(DEPDIR)/ospf_vty.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ospf_zebra.Po ./$(DEPDIR)/ospfd.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CFLAGS = @CFLAGS@ +DIST_SOURCES = $(libospf_a_SOURCES) $(ospfd_SOURCES) +DATA = $(sysconf_DATA) + +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in +SOURCES = $(libospf_a_SOURCES) $(ospfd_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign ospfd/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libospf.a: $(libospf_a_OBJECTS) $(libospf_a_DEPENDENCIES) + -rm -f libospf.a + $(libospf_a_AR) libospf.a $(libospf_a_OBJECTS) $(libospf_a_LIBADD) + $(RANLIB) libospf.a +sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \ + rm -f $(DESTDIR)$(sbindir)/$$f; \ + done + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) +ospfd$(EXEEXT): $(ospfd_OBJECTS) $(ospfd_DEPENDENCIES) + @rm -f ospfd$(EXEEXT) + $(LINK) $(ospfd_LDFLAGS) $(ospfd_OBJECTS) $(ospfd_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_abr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_asbr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ase.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_dump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_flood.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ia.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_interface.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ism.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_lsa.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_lsdb.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_neighbor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_network.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_nsm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_opaque.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_packet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_route.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_routemap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_snmp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_spf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_te.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_vty.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_zebra.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospfd.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `cygpath -w $<` +CCDEPMODE = @CCDEPMODE@ +uninstall-info-am: +sysconfDATA_INSTALL = $(INSTALL_DATA) + +uninstall-sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(sysconf_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \ + rm -f $(DESTDIR)$(sysconfdir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-sbinPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-sbinPROGRAMS install-sysconfDATA + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \ + uninstall-sysconfDATA + +.PHONY: GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES clean-sbinPROGRAMS distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-sbinPROGRAMS install-strip install-sysconfDATA \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic tags uninstall uninstall-am \ + uninstall-info-am uninstall-sbinPROGRAMS uninstall-sysconfDATA + + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/ospfd/OSPF-MIB.txt b/ospfd/OSPF-MIB.txt new file mode 100644 index 0000000..de7d03f --- /dev/null +++ b/ospfd/OSPF-MIB.txt @@ -0,0 +1,2723 @@ +OSPF-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Counter32, Gauge32, + Integer32, IpAddress + FROM SNMPv2-SMI + TEXTUAL-CONVENTION, TruthValue, RowStatus + FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF + mib-2 FROM RFC1213-MIB; + +-- This MIB module uses the extended OBJECT-TYPE macro as +-- defined in [9]. + +ospf MODULE-IDENTITY + LAST-UPDATED "9501201225Z" -- Fri Jan 20 12:25:50 PST 1995 + ORGANIZATION "IETF OSPF Working Group" + CONTACT-INFO + " Fred Baker + Postal: Cisco Systems + 519 Lado Drive + Santa Barbara, California 93111 + Tel: +1 805 681 0115 + E-Mail: fred@cisco.com + + Rob Coltun + Postal: RainbowBridge Communications + Tel: (301) 340-9416 + E-Mail: rcoltun@rainbow-bridge.com" + DESCRIPTION + "The MIB module to describe the OSPF Version 2 + Protocol" + ::= { mib-2 14 } + +-- The Area ID, in OSPF, has the same format as an IP Address, +-- but has the function of defining a summarization point for +-- Link State Advertisements + +AreaID ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "An OSPF Area Identifier." + SYNTAX IpAddress + + +-- The Router ID, in OSPF, has the same format as an IP Address, +-- but identifies the router independent of its IP Address. + +RouterID ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A OSPF Router Identifier." + SYNTAX IpAddress + + +-- The OSPF Metric is defined as an unsigned value in the range + +Metric ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The OSPF Internal Metric." + SYNTAX Integer32 (0..'FFFF'h) + +BigMetric ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The OSPF External Metric." + SYNTAX Integer32 (0..'FFFFFF'h) + +-- Status Values + +Status ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The status of an interface: 'enabled' indicates that + it is willing to communicate with other OSPF Routers, + while 'disabled' indicates that it is not." + SYNTAX INTEGER { enabled (1), disabled (2) } + +-- Time Durations measured in seconds + +PositiveInteger ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A positive integer. Values in excess are precluded as + unnecessary and prone to interoperability issues." + SYNTAX Integer32 (0..'7FFFFFFF'h) + +HelloRange ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The range of intervals on which hello messages are + exchanged." + SYNTAX Integer32 (1..'FFFF'h) + +UpToMaxAge ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The values that one might find or configure for + variables bounded by the maximum age of an LSA." + SYNTAX Integer32 (0..3600) + + +-- The range of ifIndex + +InterfaceIndex ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The range of ifIndex." + SYNTAX Integer32 + + +-- Potential Priorities for the Designated Router Election + +DesignatedRouterPriority ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The values defined for the priority of a system for + becoming the designated router." + SYNTAX Integer32 (0..'FF'h) + +TOSType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Type of Service is defined as a mapping to the IP Type of + Service Flags as defined in the IP Forwarding Table MIB + + +-----+-----+-----+-----+-----+-----+-----+-----+ + | | | | + | PRECEDENCE | TYPE OF SERVICE | 0 | + | | | | + +-----+-----+-----+-----+-----+-----+-----+-----+ + + IP TOS IP TOS + Field Policy Field Policy + + Contents Code Contents Code + 0 0 0 0 ==> 0 0 0 0 1 ==> 2 + 0 0 1 0 ==> 4 0 0 1 1 ==> 6 + 0 1 0 0 ==> 8 0 1 0 1 ==> 10 + 0 1 1 0 ==> 12 0 1 1 1 ==> 14 + 1 0 0 0 ==> 16 1 0 0 1 ==> 18 + 1 0 1 0 ==> 20 1 0 1 1 ==> 22 + 1 1 0 0 ==> 24 1 1 0 1 ==> 26 + 1 1 1 0 ==> 28 1 1 1 1 ==> 30 + + The remaining values are left for future definition." + SYNTAX Integer32 (0..30) + + +-- OSPF General Variables + +-- These parameters apply globally to the Router's +-- OSPF Process. + +ospfGeneralGroup OBJECT IDENTIFIER ::= { ospf 1 } + + + ospfRouterId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying the + router in the Autonomous System. + + By convention, to ensure uniqueness, this + should default to the value of one of the + router's IP interface addresses." + REFERENCE + "OSPF Version 2, C.1 Global parameters" + ::= { ospfGeneralGroup 1 } + + + ospfAdminStat OBJECT-TYPE + SYNTAX Status + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The administrative status of OSPF in the + router. The value 'enabled' denotes that the + OSPF Process is active on at least one inter- + face; 'disabled' disables it on all inter- + faces." + ::= { ospfGeneralGroup 2 } + + ospfVersionNumber OBJECT-TYPE + SYNTAX INTEGER { version2 (2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current version number of the OSPF proto- + col is 2." + REFERENCE + "OSPF Version 2, Title" + ::= { ospfGeneralGroup 3 } + + + ospfAreaBdrRtrStatus OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A flag to note whether this router is an area + border router." + REFERENCE + "OSPF Version 2, Section 3 Splitting the AS into + Areas" + ::= { ospfGeneralGroup 4 } + + + ospfASBdrRtrStatus OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A flag to note whether this router is config- + ured as an Autonomous System border router." + REFERENCE + "OSPF Version 2, Section 3.3 Classification of + routers" + ::= { ospfGeneralGroup 5 } + + ospfExternLsaCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of external (LS type 5) link-state + advertisements in the link-state database." + REFERENCE + "OSPF Version 2, Appendix A.4.5 AS external link + advertisements" + ::= { ospfGeneralGroup 6 } + + + ospfExternLsaCksumSum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32-bit unsigned sum of the LS checksums of + the external link-state advertisements con- + tained in the link-state database. This sum + can be used to determine if there has been a + change in a router's link state database, and + to compare the link-state database of two + routers." + ::= { ospfGeneralGroup 7 } + + + ospfTOSSupport OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The router's support for type-of-service rout- + ing." + REFERENCE + "OSPF Version 2, Appendix F.1.2 Optional TOS + support" + ::= { ospfGeneralGroup 8 } + + ospfOriginateNewLsas OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of new link-state advertisements + that have been originated. This number is in- + cremented each time the router originates a new + LSA." + ::= { ospfGeneralGroup 9 } + + + ospfRxNewLsas OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of link-state advertisements re- + ceived determined to be new instantiations. + This number does not include newer instantia- + tions of self-originated link-state advertise- + ments." + ::= { ospfGeneralGroup 10 } + + ospfExtLsdbLimit OBJECT-TYPE + SYNTAX Integer32 (-1..'7FFFFFFF'h) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The maximum number of non-default AS- + external-LSAs entries that can be stored in the + link-state database. If the value is -1, then + there is no limit. + + When the number of non-default AS-external-LSAs + in a router's link-state database reaches + ospfExtLsdbLimit, the router enters Overflow- + State. The router never holds more than + ospfExtLsdbLimit non-default AS-external-LSAs + in its database. OspfExtLsdbLimit MUST be set + identically in all routers attached to the OSPF + backbone and/or any regular OSPF area. (i.e., + OSPF stub areas and NSSAs are excluded)." + DEFVAL { -1 } + ::= { ospfGeneralGroup 11 } + + ospfMulticastExtensions OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A Bit Mask indicating whether the router is + forwarding IP multicast (Class D) datagrams + based on the algorithms defined in the Multi- + cast Extensions to OSPF. + + Bit 0, if set, indicates that the router can + forward IP multicast datagrams in the router's + directly attached areas (called intra-area mul- + ticast routing). + + Bit 1, if set, indicates that the router can + forward IP multicast datagrams between OSPF + areas (called inter-area multicast routing). + + Bit 2, if set, indicates that the router can + forward IP multicast datagrams between Auto- + nomous Systems (called inter-AS multicast rout- + ing). + + Only certain combinations of bit settings are + allowed, namely: 0 (no multicast forwarding is + enabled), 1 (intra-area multicasting only), 3 + (intra-area and inter-area multicasting), 5 + (intra-area and inter-AS multicasting) and 7 + (multicasting everywhere). By default, no mul- + ticast forwarding is enabled." + DEFVAL { 0 } + ::= { ospfGeneralGroup 12 } + + ospfExitOverflowInterval OBJECT-TYPE + SYNTAX PositiveInteger + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The number of seconds that, after entering + OverflowState, a router will attempt to leave + OverflowState. This allows the router to again + originate non-default AS-external-LSAs. When + set to 0, the router will not leave Overflow- + State until restarted." + DEFVAL { 0 } + ::= { ospfGeneralGroup 13 } + + + ospfDemandExtensions OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The router's support for demand routing." + REFERENCE + "OSPF Version 2, Appendix on Demand Routing" + ::= { ospfGeneralGroup 14 } + + +-- The OSPF Area Data Structure contains information +-- regarding the various areas. The interfaces and +-- virtual links are configured as part of these areas. +-- Area 0.0.0.0, by definition, is the Backbone Area + + + ospfAreaTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfAreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information describing the configured parame- + ters and cumulative statistics of the router's + attached areas." + REFERENCE + "OSPF Version 2, Section 6 The Area Data Struc- + ture" + ::= { ospf 2 } + + + ospfAreaEntry OBJECT-TYPE + SYNTAX OspfAreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information describing the configured parame- + ters and cumulative statistics of one of the + router's attached areas." + INDEX { ospfAreaId } + ::= { ospfAreaTable 1 } + +OspfAreaEntry ::= + SEQUENCE { + ospfAreaId + AreaID, + ospfAuthType + Integer32, + ospfImportAsExtern + INTEGER, + ospfSpfRuns + Counter32, + ospfAreaBdrRtrCount + Gauge32, + ospfAsBdrRtrCount + Gauge32, + ospfAreaLsaCount + Gauge32, + ospfAreaLsaCksumSum + Integer32, + ospfAreaSummary + INTEGER, + ospfAreaStatus + RowStatus + } + + ospfAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying an area. + Area ID 0.0.0.0 is used for the OSPF backbone." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaEntry 1 } + + + ospfAuthType OBJECT-TYPE + SYNTAX Integer32 + -- none (0), + -- simplePassword (1) + -- md5 (2) + -- reserved for specification by IANA (> 2) + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "The authentication type specified for an area. + Additional authentication types may be assigned + locally on a per Area basis." + REFERENCE + "OSPF Version 2, Appendix E Authentication" + DEFVAL { 0 } -- no authentication, by default + ::= { ospfAreaEntry 2 } + + ospfImportAsExtern OBJECT-TYPE + SYNTAX INTEGER { + importExternal (1), + importNoExternal (2), + importNssa (3) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The area's support for importing AS external + link- state advertisements." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + DEFVAL { importExternal } + ::= { ospfAreaEntry 3 } + + + ospfSpfRuns OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times that the intra-area route + table has been calculated using this area's + link-state database. This is typically done + using Dijkstra's algorithm." + ::= { ospfAreaEntry 4 } + + + ospfAreaBdrRtrCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of area border routers reach- + able within this area. This is initially zero, + and is calculated in each SPF Pass." + ::= { ospfAreaEntry 5 } + + ospfAsBdrRtrCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Autonomous System border + routers reachable within this area. This is + initially zero, and is calculated in each SPF + Pass." + ::= { ospfAreaEntry 6 } + + + ospfAreaLsaCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of link-state advertisements + in this area's link-state database, excluding + AS External LSA's." + ::= { ospfAreaEntry 7 } + + + ospfAreaLsaCksumSum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32-bit unsigned sum of the link-state ad- + vertisements' LS checksums contained in this + area's link-state database. This sum excludes + external (LS type 5) link-state advertisements. + The sum can be used to determine if there has + been a change in a router's link state data- + base, and to compare the link-state database of + two routers." + DEFVAL { 0 } + ::= { ospfAreaEntry 8 } + + ospfAreaSummary OBJECT-TYPE + SYNTAX INTEGER { + noAreaSummary (1), + sendAreaSummary (2) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The variable ospfAreaSummary controls the im- + port of summary LSAs into stub areas. It has + no effect on other areas. + + If it is noAreaSummary, the router will neither + originate nor propagate summary LSAs into the + stub area. It will rely entirely on its de- + fault route. + + If it is sendAreaSummary, the router will both + summarize and propagate summary LSAs." + DEFVAL { noAreaSummary } + ::= { ospfAreaEntry 9 } + + + ospfAreaStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfAreaEntry 10 } + + +-- OSPF Area Default Metric Table + +-- The OSPF Area Default Metric Table describes the metrics +-- that a default Area Border Router will advertise into a +-- Stub area. + + + ospfStubAreaTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfStubAreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The set of metrics that will be advertised by + a default Area Border Router into a stub area." + REFERENCE + "OSPF Version 2, Appendix C.2, Area Parameters" + ::= { ospf 3 } + + + ospfStubAreaEntry OBJECT-TYPE + SYNTAX OspfStubAreaEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The metric for a given Type of Service that + will be advertised by a default Area Border + Router into a stub area." + REFERENCE + "OSPF Version 2, Appendix C.2, Area Parameters" + INDEX { ospfStubAreaId, ospfStubTOS } + ::= { ospfStubAreaTable 1 } + +OspfStubAreaEntry ::= + SEQUENCE { + ospfStubAreaId + AreaID, + ospfStubTOS + TOSType, + ospfStubMetric + BigMetric, + ospfStubStatus + RowStatus, + ospfStubMetricType + INTEGER + } + + ospfStubAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32 bit identifier for the Stub Area. On + creation, this can be derived from the in- + stance." + ::= { ospfStubAreaEntry 1 } + + + ospfStubTOS OBJECT-TYPE + SYNTAX TOSType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Type of Service associated with the + metric. On creation, this can be derived from + the instance." + ::= { ospfStubAreaEntry 2 } + + + ospfStubMetric OBJECT-TYPE + SYNTAX BigMetric + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The metric value applied at the indicated type + of service. By default, this equals the least + metric at the type of service among the inter- + faces to other areas." + ::= { ospfStubAreaEntry 3 } + + + ospfStubStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfStubAreaEntry 4 } + + ospfStubMetricType OBJECT-TYPE + SYNTAX INTEGER { + ospfMetric (1), -- OSPF Metric + comparableCost (2), -- external type 1 + nonComparable (3) -- external type 2 + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the type of metric ad- + vertised as a default route." + DEFVAL { ospfMetric } + ::= { ospfStubAreaEntry 5 } + +-- OSPF Link State Database + +-- The Link State Database contains the Link State +-- Advertisements from throughout the areas that the +-- device is attached to. + + + ospfLsdbTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPF Process's Link State Database." + REFERENCE + "OSPF Version 2, Section 12 Link State Adver- + tisements" + ::= { ospf 4 } + + + ospfLsdbEntry OBJECT-TYPE + SYNTAX OspfLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A single Link State Advertisement." + INDEX { ospfLsdbAreaId, ospfLsdbType, + ospfLsdbLsid, ospfLsdbRouterId } + ::= { ospfLsdbTable 1 } + +OspfLsdbEntry ::= + SEQUENCE { + ospfLsdbAreaId + AreaID, + ospfLsdbType + INTEGER, + ospfLsdbLsid + IpAddress, + ospfLsdbRouterId + RouterID, + ospfLsdbSequence + Integer32, + ospfLsdbAge + Integer32, + ospfLsdbChecksum + Integer32, + ospfLsdbAdvertisement + OCTET STRING + } + ospfLsdbAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32 bit identifier of the Area from which + the LSA was received." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfLsdbEntry 1 } + +-- External Link State Advertisements are permitted +-- for backward compatibility, but should be displayed in +-- the ospfExtLsdbTable rather than here. + + ospfLsdbType OBJECT-TYPE + SYNTAX INTEGER { + routerLink (1), + networkLink (2), + summaryLink (3), + asSummaryLink (4), + asExternalLink (5), -- but see ospfExtLsdbTable + multicastLink (6), + nssaExternalLink (7) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of the link state advertisement. + Each link state type has a separate advertise- + ment format." + REFERENCE + "OSPF Version 2, Appendix A.4.1 The Link State + Advertisement header" + ::= { ospfLsdbEntry 2 } + + ospfLsdbLsid OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Link State ID is an LS Type Specific field + containing either a Router ID or an IP Address; + it identifies the piece of the routing domain + that is being described by the advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.4 Link State ID" + ::= { ospfLsdbEntry 3 } + ospfLsdbRouterId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32 bit number that uniquely identifies the + originating router in the Autonomous System." + REFERENCE + "OSPF Version 2, Appendix C.1 Global parameters" + ::= { ospfLsdbEntry 4 } + +-- Note that the OSPF Sequence Number is a 32 bit signed +-- integer. It starts with the value '80000001'h, +-- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h +-- Thus, a typical sequence number will be very negative. + + ospfLsdbSequence OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The sequence number field is a signed 32-bit + integer. It is used to detect old and dupli- + cate link state advertisements. The space of + sequence numbers is linearly ordered. The + larger the sequence number the more recent the + advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.6 LS sequence + number" + ::= { ospfLsdbEntry 5 } + + + ospfLsdbAge OBJECT-TYPE + SYNTAX Integer32 -- Should be 0..MaxAge + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the age of the link state adver- + tisement in seconds." + REFERENCE + "OSPF Version 2, Section 12.1.1 LS age" + ::= { ospfLsdbEntry 6 } + + ospfLsdbChecksum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the checksum of the complete + contents of the advertisement, excepting the + age field. The age field is excepted so that + an advertisement's age can be incremented + without updating the checksum. The checksum + used is the same that is used for ISO connec- + tionless datagrams; it is commonly referred to + as the Fletcher checksum." + REFERENCE + "OSPF Version 2, Section 12.1.7 LS checksum" + ::= { ospfLsdbEntry 7 } + + + ospfLsdbAdvertisement OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..65535)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The entire Link State Advertisement, including + its header." + REFERENCE + "OSPF Version 2, Section 12 Link State Adver- + tisements" + ::= { ospfLsdbEntry 8 } + + +-- Address Range Table + +-- The Address Range Table acts as an adjunct to the Area +-- Table; It describes those Address Range Summaries that +-- are configured to be propagated from an Area to reduce +-- the amount of information about it which is known beyond +-- its borders. + + ospfAreaRangeTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfAreaRangeEntry + MAX-ACCESS not-accessible + STATUS obsolete + DESCRIPTION + "A range if IP addresses specified by an IP + address/IP network mask pair. For example, + class B address range of X.X.X.X with a network + mask of 255.255.0.0 includes all IP addresses + from X.X.0.0 to X.X.255.255" + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospf 5 } + ospfAreaRangeEntry OBJECT-TYPE + SYNTAX OspfAreaRangeEntry + MAX-ACCESS not-accessible + STATUS obsolete + DESCRIPTION + "A range if IP addresses specified by an IP + address/IP network mask pair. For example, + class B address range of X.X.X.X with a network + mask of 255.255.0.0 includes all IP addresses + from X.X.0.0 to X.X.255.255" + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + INDEX { ospfAreaRangeAreaId, ospfAreaRangeNet } + ::= { ospfAreaRangeTable 1 } + +OspfAreaRangeEntry ::= + SEQUENCE { + ospfAreaRangeAreaId + AreaID, + ospfAreaRangeNet + IpAddress, + ospfAreaRangeMask + IpAddress, + ospfAreaRangeStatus + RowStatus, + ospfAreaRangeEffect + INTEGER + } + + ospfAreaRangeAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The Area the Address Range is to be found + within." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaRangeEntry 1 } + + + ospfAreaRangeNet OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS obsolete + DESCRIPTION + "The IP Address of the Net or Subnet indicated + by the range." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaRangeEntry 2 } + + + ospfAreaRangeMask OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "The Subnet Mask that pertains to the Net or + Subnet." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaRangeEntry 3 } + + ospfAreaRangeStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfAreaRangeEntry 4 } + + + ospfAreaRangeEffect OBJECT-TYPE + SYNTAX INTEGER { + advertiseMatching (1), + doNotAdvertiseMatching (2) + } + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "Subnets subsumed by ranges either trigger the + advertisement of the indicated summary (adver- + tiseMatching), or result in the subnet's not + being advertised at all outside the area." + DEFVAL { advertiseMatching } + ::= { ospfAreaRangeEntry 5 } + + + +-- OSPF Host Table + +-- The Host/Metric Table indicates what hosts are directly +-- attached to the Router, and what metrics and types of +-- service should be advertised for them. + + ospfHostTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfHostEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The list of Hosts, and their metrics, that the + router will advertise as host routes." + REFERENCE + "OSPF Version 2, Appendix C.6 Host route param- + eters" + ::= { ospf 6 } + + + ospfHostEntry OBJECT-TYPE + SYNTAX OspfHostEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A metric to be advertised, for a given type of + service, when a given host is reachable." + INDEX { ospfHostIpAddress, ospfHostTOS } + ::= { ospfHostTable 1 } + +OspfHostEntry ::= + SEQUENCE { + ospfHostIpAddress + IpAddress, + ospfHostTOS + TOSType, + ospfHostMetric + Metric, + ospfHostStatus + RowStatus, + ospfHostAreaID + AreaID + } + + ospfHostIpAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of the Host." + REFERENCE + "OSPF Version 2, Appendix C.6 Host route parame- + ters" + ::= { ospfHostEntry 1 } + + + ospfHostTOS OBJECT-TYPE + SYNTAX TOSType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Type of Service of the route being config- + ured." + REFERENCE + "OSPF Version 2, Appendix C.6 Host route parame- + ters" + ::= { ospfHostEntry 2 } + + + ospfHostMetric OBJECT-TYPE + SYNTAX Metric + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The Metric to be advertised." + REFERENCE + "OSPF Version 2, Appendix C.6 Host route parame- + ters" + ::= { ospfHostEntry 3 } + + ospfHostStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfHostEntry 4 } + + + ospfHostAreaID OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Area the Host Entry is to be found within. + By default, the area that a subsuming OSPF in- + terface is in, or 0.0.0.0" + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfHostEntry 5 } + + +-- OSPF Interface Table + +-- The OSPF Interface Table augments the ipAddrTable +-- with OSPF specific information. + + ospfIfTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPF Interface Table describes the inter- + faces from the viewpoint of OSPF." + REFERENCE + "OSPF Version 2, Appendix C.3 Router interface + parameters" + ::= { ospf 7 } + + + ospfIfEntry OBJECT-TYPE + SYNTAX OspfIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPF Interface Entry describes one inter- + face from the viewpoint of OSPF." + INDEX { ospfIfIpAddress, ospfAddressLessIf } + ::= { ospfIfTable 1 } + +OspfIfEntry ::= + SEQUENCE { + ospfIfIpAddress + IpAddress, + ospfAddressLessIf + Integer32, + ospfIfAreaId + AreaID, + ospfIfType + INTEGER, + ospfIfAdminStat + Status, + ospfIfRtrPriority + DesignatedRouterPriority, + ospfIfTransitDelay + UpToMaxAge, + ospfIfRetransInterval + UpToMaxAge, + ospfIfHelloInterval + HelloRange, + ospfIfRtrDeadInterval + PositiveInteger, + ospfIfPollInterval + PositiveInteger, + ospfIfState + INTEGER, + ospfIfDesignatedRouter + IpAddress, + ospfIfBackupDesignatedRouter + IpAddress, + ospfIfEvents + Counter32, + ospfIfAuthType + INTEGER, + ospfIfAuthKey + OCTET STRING, + ospfIfStatus + RowStatus, + ospfIfMulticastForwarding + INTEGER, + ospfIfDemand + TruthValue + } + + ospfIfIpAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of this OSPF interface." + ::= { ospfIfEntry 1 } + + ospfAddressLessIf OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "For the purpose of easing the instancing of + addressed and addressless interfaces; This + variable takes the value 0 on interfaces with + IP Addresses, and the corresponding value of + ifIndex for interfaces having no IP Address." + ::= { ospfIfEntry 2 } + ospfIfAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying the area + to which the interface connects. Area ID + 0.0.0.0 is used for the OSPF backbone." + DEFVAL { '00000000'H } -- 0.0.0.0 + ::= { ospfIfEntry 3 } + + ospfIfType OBJECT-TYPE + SYNTAX INTEGER { + broadcast (1), + nbma (2), + pointToPoint (3), + pointToMultipoint (5) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The OSPF interface type. + + By way of a default, this field may be intuited + from the corresponding value of ifType. Broad- + cast LANs, such as Ethernet and IEEE 802.5, + take the value 'broadcast', X.25 and similar + technologies take the value 'nbma', and links + that are definitively point to point take the + value 'pointToPoint'." + ::= { ospfIfEntry 4 } + + + ospfIfAdminStat OBJECT-TYPE + SYNTAX Status + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The OSPF interface's administrative status. + The value formed on the interface, and the in- + terface will be advertised as an internal route + to some area. The value 'disabled' denotes + that the interface is external to OSPF." + DEFVAL { enabled } + ::= { ospfIfEntry 5 } + + ospfIfRtrPriority OBJECT-TYPE + SYNTAX DesignatedRouterPriority + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The priority of this interface. Used in + multi-access networks, this field is used in + the designated router election algorithm. The + value 0 signifies that the router is not eligi- + ble to become the designated router on this + particular network. In the event of a tie in + this value, routers will use their Router ID as + a tie breaker." + DEFVAL { 1 } + ::= { ospfIfEntry 6 } + + + ospfIfTransitDelay OBJECT-TYPE + SYNTAX UpToMaxAge + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The estimated number of seconds it takes to + transmit a link state update packet over this + interface." + DEFVAL { 1 } + ::= { ospfIfEntry 7 } + + + ospfIfRetransInterval OBJECT-TYPE + SYNTAX UpToMaxAge + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds between link-state ad- + vertisement retransmissions, for adjacencies + belonging to this interface. This value is + also used when retransmitting database descrip- + tion and link-state request packets." + DEFVAL { 5 } + ::= { ospfIfEntry 8 } + + + ospfIfHelloInterval OBJECT-TYPE + SYNTAX HelloRange + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The length of time, in seconds, between the + Hello packets that the router sends on the in- + terface. This value must be the same for all + routers attached to a common network." + DEFVAL { 10 } + ::= { ospfIfEntry 9 } + + + ospfIfRtrDeadInterval OBJECT-TYPE + SYNTAX PositiveInteger + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds that a router's Hello + packets have not been seen before it's neigh- + bors declare the router down. This should be + some multiple of the Hello interval. This + value must be the same for all routers attached + to a common network." + DEFVAL { 40 } + ::= { ospfIfEntry 10 } + + + ospfIfPollInterval OBJECT-TYPE + SYNTAX PositiveInteger + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The larger time interval, in seconds, between + the Hello packets sent to an inactive non- + broadcast multi- access neighbor." + DEFVAL { 120 } + ::= { ospfIfEntry 11 } + + + ospfIfState OBJECT-TYPE + SYNTAX INTEGER { + down (1), + loopback (2), + waiting (3), + pointToPoint (4), + designatedRouter (5), + backupDesignatedRouter (6), + otherDesignatedRouter (7) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The OSPF Interface State." + DEFVAL { down } + ::= { ospfIfEntry 12 } + + + ospfIfDesignatedRouter OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of the Designated Router." + DEFVAL { '00000000'H } -- 0.0.0.0 + ::= { ospfIfEntry 13 } + + + ospfIfBackupDesignatedRouter OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of the Backup Designated + Router." + DEFVAL { '00000000'H } -- 0.0.0.0 + ::= { ospfIfEntry 14 } + + ospfIfEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times this OSPF interface has + changed its state, or an error has occurred." + ::= { ospfIfEntry 15 } + + + ospfIfAuthKey OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (0..256)) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The Authentication Key. If the Area's Author- + ization Type is simplePassword, and the key + length is shorter than 8 octets, the agent will + left adjust and zero fill to 8 octets. + + Note that unauthenticated interfaces need no + authentication key, and simple password authen- + tication cannot use a key of more than 8 oc- + tets. Larger keys are useful only with authen- + tication mechanisms not specified in this docu- + ment. + + When read, ospfIfAuthKey always returns an Oc- + tet String of length zero." + REFERENCE + "OSPF Version 2, Section 9 The Interface Data + Structure" + DEFVAL { '0000000000000000'H } -- 0.0.0.0.0.0.0.0 + ::= { ospfIfEntry 16 } + + ospfIfStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfIfEntry 17 } + + + ospfIfMulticastForwarding OBJECT-TYPE + SYNTAX INTEGER { + blocked (1), -- no multicast forwarding + multicast (2), -- using multicast address + unicast (3) -- to each OSPF neighbor + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The way multicasts should forwarded on this + interface; not forwarded, forwarded as data + link multicasts, or forwarded as data link uni- + casts. Data link multicasting is not meaning- + ful on point to point and NBMA interfaces, and + setting ospfMulticastForwarding to 0 effective- + ly disables all multicast forwarding." + DEFVAL { blocked } + ::= { ospfIfEntry 18 } + + + ospfIfDemand OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Indicates whether Demand OSPF procedures (hel- + lo supression to FULL neighbors and setting the + DoNotAge flag on proogated LSAs) should be per- + formed on this interface." + DEFVAL { false } + ::= { ospfIfEntry 19 } + + + ospfIfAuthType OBJECT-TYPE + SYNTAX INTEGER (0..255) + -- none (0), + -- simplePassword (1) + -- md5 (2) + -- reserved for specification by IANA (> 2) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The authentication type specified for an in- + terface. Additional authentication types may + be assigned locally." + REFERENCE + "OSPF Version 2, Appendix E Authentication" + DEFVAL { 0 } -- no authentication, by default + ::= { ospfIfEntry 20 } + + +-- OSPF Interface Metric Table + +-- The Metric Table describes the metrics to be advertised +-- for a specified interface at the various types of service. +-- As such, this table is an adjunct of the OSPF Interface +-- Table. + +-- Types of service, as defined by RFC 791, have the ability +-- to request low delay, high bandwidth, or reliable linkage. + +-- For the purposes of this specification, the measure of +-- bandwidth + +-- Metric = 10^8 / ifSpeed + +-- is the default value. For multiple link interfaces, note +-- that ifSpeed is the sum of the individual link speeds. +-- This yields a number having the following typical values: + +-- Network Type/bit rate Metric + +-- >= 100 MBPS 1 +-- Ethernet/802.3 10 +-- E1 48 +-- T1 (ESF) 65 +-- 64 KBPS 1562 +-- 56 KBPS 1785 +-- 19.2 KBPS 5208 +-- 9.6 KBPS 10416 + +-- Routes that are not specified use the default (TOS 0) metric + + ospfIfMetricTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfIfMetricEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The TOS metrics for a non-virtual interface + identified by the interface index." + REFERENCE + "OSPF Version 2, Appendix C.3 Router interface + parameters" + ::= { ospf 8 } + + ospfIfMetricEntry OBJECT-TYPE + SYNTAX OspfIfMetricEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A particular TOS metric for a non-virtual in- + terface identified by the interface index." + REFERENCE + "OSPF Version 2, Appendix C.3 Router interface + parameters" + INDEX { ospfIfMetricIpAddress, + ospfIfMetricAddressLessIf, + ospfIfMetricTOS } + ::= { ospfIfMetricTable 1 } + +OspfIfMetricEntry ::= + SEQUENCE { + ospfIfMetricIpAddress + IpAddress, + ospfIfMetricAddressLessIf + Integer32, + ospfIfMetricTOS + TOSType, + ospfIfMetricValue + Metric, + ospfIfMetricStatus + RowStatus + } + + ospfIfMetricIpAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of this OSPF interface. On row + creation, this can be derived from the in- + stance." + ::= { ospfIfMetricEntry 1 } + + ospfIfMetricAddressLessIf OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "For the purpose of easing the instancing of + addressed and addressless interfaces; This + variable takes the value 0 on interfaces with + IP Addresses, and the value of ifIndex for in- + terfaces having no IP Address. On row crea- + tion, this can be derived from the instance." + ::= { ospfIfMetricEntry 2 } + + + ospfIfMetricTOS OBJECT-TYPE + SYNTAX TOSType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of service metric being referenced. + On row creation, this can be derived from the + instance." + ::= { ospfIfMetricEntry 3 } + + + ospfIfMetricValue OBJECT-TYPE + SYNTAX Metric + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The metric of using this type of service on + this interface. The default value of the TOS 0 + Metric is 10^8 / ifSpeed." + ::= { ospfIfMetricEntry 4 } + + ospfIfMetricStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfIfMetricEntry 5 } + + +-- OSPF Virtual Interface Table + +-- The Virtual Interface Table describes the virtual +-- links that the OSPF Process is configured to +-- carry on. + + ospfVirtIfTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfVirtIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information about this router's virtual inter- + faces." + REFERENCE + "OSPF Version 2, Appendix C.4 Virtual link + parameters" + ::= { ospf 9 } + + + ospfVirtIfEntry OBJECT-TYPE + SYNTAX OspfVirtIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information about a single Virtual Interface." + INDEX { ospfVirtIfAreaId, ospfVirtIfNeighbor } + ::= { ospfVirtIfTable 1 } + +OspfVirtIfEntry ::= + SEQUENCE { + ospfVirtIfAreaId + AreaID, + ospfVirtIfNeighbor + RouterID, + ospfVirtIfTransitDelay + UpToMaxAge, + ospfVirtIfRetransInterval + UpToMaxAge, + ospfVirtIfHelloInterval + HelloRange, + ospfVirtIfRtrDeadInterval + PositiveInteger, + ospfVirtIfState + INTEGER, + ospfVirtIfEvents + Counter32, + ospfVirtIfAuthType + INTEGER, + ospfVirtIfAuthKey + OCTET STRING, + ospfVirtIfStatus + RowStatus + } + + ospfVirtIfAreaId OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Transit Area that the Virtual Link + traverses. By definition, this is not 0.0.0.0" + ::= { ospfVirtIfEntry 1 } + + + ospfVirtIfNeighbor OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Router ID of the Virtual Neighbor." + ::= { ospfVirtIfEntry 2 } + + + ospfVirtIfTransitDelay OBJECT-TYPE + SYNTAX UpToMaxAge + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The estimated number of seconds it takes to + transmit a link- state update packet over this + interface." + DEFVAL { 1 } + ::= { ospfVirtIfEntry 3 } + + + ospfVirtIfRetransInterval OBJECT-TYPE + SYNTAX UpToMaxAge + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds between link-state ad- + vertisement retransmissions, for adjacencies + belonging to this interface. This value is + also used when retransmitting database descrip- + tion and link-state request packets. This + value should be well over the expected round- + trip time." + DEFVAL { 5 } + ::= { ospfVirtIfEntry 4 } + + + ospfVirtIfHelloInterval OBJECT-TYPE + SYNTAX HelloRange + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The length of time, in seconds, between the + Hello packets that the router sends on the in- + terface. This value must be the same for the + virtual neighbor." + DEFVAL { 10 } + ::= { ospfVirtIfEntry 5 } + + + ospfVirtIfRtrDeadInterval OBJECT-TYPE + SYNTAX PositiveInteger + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The number of seconds that a router's Hello + packets have not been seen before it's neigh- + bors declare the router down. This should be + some multiple of the Hello interval. This + value must be the same for the virtual neigh- + bor." + DEFVAL { 60 } + ::= { ospfVirtIfEntry 6 } + + + ospfVirtIfState OBJECT-TYPE + SYNTAX INTEGER { + down (1), -- these use the same encoding + pointToPoint (4) -- as the ospfIfTable + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "OSPF virtual interface states." + DEFVAL { down } + ::= { ospfVirtIfEntry 7 } + + + ospfVirtIfEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of state changes or error events on + this Virtual Link" + ::= { ospfVirtIfEntry 8 } + + + ospfVirtIfAuthKey OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(0..256)) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "If Authentication Type is simplePassword, the + device will left adjust and zero fill to 8 oc- + tets. + + Note that unauthenticated interfaces need no + authentication key, and simple password authen- + tication cannot use a key of more than 8 oc- + tets. Larger keys are useful only with authen- + tication mechanisms not specified in this docu- + ment. + + When read, ospfVifAuthKey always returns a + string of length zero." + REFERENCE + "OSPF Version 2, Section 9 The Interface Data + Structure" + DEFVAL { '0000000000000000'H } -- 0.0.0.0.0.0.0.0 + ::= { ospfVirtIfEntry 9 } + + + ospfVirtIfStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfVirtIfEntry 10 } + + + ospfVirtIfAuthType OBJECT-TYPE + SYNTAX INTEGER (0..255) + -- none (0), + -- simplePassword (1) + -- md5 (2) + -- reserved for specification by IANA (> 2) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The authentication type specified for a virtu- + al interface. Additional authentication types + may be assigned locally." + REFERENCE + "OSPF Version 2, Appendix E Authentication" + DEFVAL { 0 } -- no authentication, by default + ::= { ospfVirtIfEntry 11 } + + +-- OSPF Neighbor Table + +-- The OSPF Neighbor Table describes all neighbors in +-- the locality of the subject router. + + ospfNbrTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table of non-virtual neighbor information." + REFERENCE + "OSPF Version 2, Section 10 The Neighbor Data + Structure" + ::= { ospf 10 } + + + ospfNbrEntry OBJECT-TYPE + SYNTAX OspfNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The information regarding a single neighbor." + REFERENCE + "OSPF Version 2, Section 10 The Neighbor Data + Structure" + INDEX { ospfNbrIpAddr, ospfNbrAddressLessIndex } + ::= { ospfNbrTable 1 } + +OspfNbrEntry ::= + SEQUENCE { + ospfNbrIpAddr + IpAddress, + ospfNbrAddressLessIndex + InterfaceIndex, + ospfNbrRtrId + RouterID, + ospfNbrOptions + Integer32, + ospfNbrPriority + DesignatedRouterPriority, + ospfNbrState + INTEGER, + ospfNbrEvents + Counter32, + ospfNbrLsRetransQLen + Gauge32, + ospfNbmaNbrStatus + RowStatus, + ospfNbmaNbrPermanence + INTEGER, + ospfNbrHelloSuppressed + TruthValue + } + + ospfNbrIpAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address this neighbor is using in its + IP Source Address. Note that, on addressless + links, this will not be 0.0.0.0, but the ad- + dress of another of the neighbor's interfaces." + ::= { ospfNbrEntry 1 } + + + ospfNbrAddressLessIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "On an interface having an IP Address, zero. + On addressless interfaces, the corresponding + value of ifIndex in the Internet Standard MIB. + On row creation, this can be derived from the + instance." + ::= { ospfNbrEntry 2 } + + + ospfNbrRtrId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A 32-bit integer (represented as a type IpAd- + dress) uniquely identifying the neighboring + router in the Autonomous System." + DEFVAL { '00000000'H } -- 0.0.0.0 + ::= { ospfNbrEntry 3 } + + + ospfNbrOptions OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A Bit Mask corresponding to the neighbor's op- + tions field. + + Bit 0, if set, indicates that the system will + operate on Type of Service metrics other than + TOS 0. If zero, the neighbor will ignore all + metrics except the TOS 0 metric. + + Bit 1, if set, indicates that the associated + area accepts and operates on external informa- + tion; if zero, it is a stub area. + + Bit 2, if set, indicates that the system is ca- + pable of routing IP Multicast datagrams; i.e., + that it implements the Multicast Extensions to + OSPF. + + Bit 3, if set, indicates that the associated + area is an NSSA. These areas are capable of + carrying type 7 external advertisements, which + are translated into type 5 external advertise- + ments at NSSA borders." + REFERENCE + "OSPF Version 2, Section 12.1.2 Options" + DEFVAL { 0 } + ::= { ospfNbrEntry 4 } + + + ospfNbrPriority OBJECT-TYPE + SYNTAX DesignatedRouterPriority + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The priority of this neighbor in the designat- + ed router election algorithm. The value 0 sig- + nifies that the neighbor is not eligible to be- + come the designated router on this particular + network." + DEFVAL { 1 } + ::= { ospfNbrEntry 5 } + + + ospfNbrState OBJECT-TYPE + SYNTAX INTEGER { + down (1), + attempt (2), + init (3), + twoWay (4), + exchangeStart (5), + exchange (6), + loading (7), + full (8) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The State of the relationship with this Neigh- + bor." + REFERENCE + "OSPF Version 2, Section 10.1 Neighbor States" + DEFVAL { down } + ::= { ospfNbrEntry 6 } + + + ospfNbrEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times this neighbor relationship + has changed state, or an error has occurred." + ::= { ospfNbrEntry 7 } + + + ospfNbrLsRetransQLen OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current length of the retransmission + queue." + ::= { ospfNbrEntry 8 } + + + ospfNbmaNbrStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfNbrEntry 9 } + + + ospfNbmaNbrPermanence OBJECT-TYPE + SYNTAX INTEGER { + dynamic (1), -- learned through protocol + permanent (2) -- configured address + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. 'dynamic' and 'permanent' refer to how + the neighbor became known." + DEFVAL { permanent } + ::= { ospfNbrEntry 10 } + + + ospfNbrHelloSuppressed OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates whether Hellos are being suppressed + to the neighbor" + ::= { ospfNbrEntry 11 } + + +-- OSPF Virtual Neighbor Table + +-- This table describes all virtual neighbors. +-- Since Virtual Links are configured in the +-- virtual interface table, this table is read-only. + + ospfVirtNbrTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfVirtNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table of virtual neighbor information." + REFERENCE + "OSPF Version 2, Section 15 Virtual Links" + ::= { ospf 11 } + + + ospfVirtNbrEntry OBJECT-TYPE + SYNTAX OspfVirtNbrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Virtual neighbor information." + INDEX { ospfVirtNbrArea, ospfVirtNbrRtrId } + ::= { ospfVirtNbrTable 1 } + +OspfVirtNbrEntry ::= + SEQUENCE { + ospfVirtNbrArea + AreaID, + ospfVirtNbrRtrId + RouterID, + ospfVirtNbrIpAddr + IpAddress, + ospfVirtNbrOptions + Integer32, + ospfVirtNbrState + INTEGER, + ospfVirtNbrEvents + Counter32, + ospfVirtNbrLsRetransQLen + Gauge32, + ospfVirtNbrHelloSuppressed + TruthValue + } + + ospfVirtNbrArea OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Transit Area Identifier." + ::= { ospfVirtNbrEntry 1 } + + + ospfVirtNbrRtrId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A 32-bit integer uniquely identifying the + neighboring router in the Autonomous System." + ::= { ospfVirtNbrEntry 2 } + + + ospfVirtNbrIpAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address this Virtual Neighbor is us- + ing." + ::= { ospfVirtNbrEntry 3 } + + + ospfVirtNbrOptions OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A Bit Mask corresponding to the neighbor's op- + tions field. + + Bit 1, if set, indicates that the system will + operate on Type of Service metrics other than + TOS 0. If zero, the neighbor will ignore all + metrics except the TOS 0 metric. + + Bit 2, if set, indicates that the system is + Network Multicast capable; ie, that it imple- + ments OSPF Multicast Routing." + ::= { ospfVirtNbrEntry 4 } + ospfVirtNbrState OBJECT-TYPE + SYNTAX INTEGER { + down (1), + attempt (2), + init (3), + twoWay (4), + exchangeStart (5), + exchange (6), + loading (7), + full (8) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The state of the Virtual Neighbor Relation- + ship." + ::= { ospfVirtNbrEntry 5 } + + + ospfVirtNbrEvents OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times this virtual link has + changed its state, or an error has occurred." + ::= { ospfVirtNbrEntry 6 } + + + ospfVirtNbrLsRetransQLen OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current length of the retransmission + queue." + ::= { ospfVirtNbrEntry 7 } + + + ospfVirtNbrHelloSuppressed OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates whether Hellos are being suppressed + to the neighbor" + ::= { ospfVirtNbrEntry 8 } + +-- OSPF Link State Database, External + +-- The Link State Database contains the Link State +-- Advertisements from throughout the areas that the +-- device is attached to. + +-- This table is identical to the OSPF LSDB Table in +-- format, but contains only External Link State +-- Advertisements. The purpose is to allow external +-- LSAs to be displayed once for the router rather +-- than once in each non-stub area. + + ospfExtLsdbTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfExtLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The OSPF Process's Links State Database." + REFERENCE + "OSPF Version 2, Section 12 Link State Adver- + tisements" + ::= { ospf 12 } + + + ospfExtLsdbEntry OBJECT-TYPE + SYNTAX OspfExtLsdbEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A single Link State Advertisement." + INDEX { ospfExtLsdbType, ospfExtLsdbLsid, ospfExtLsdbRouterId } + ::= { ospfExtLsdbTable 1 } + +OspfExtLsdbEntry ::= + SEQUENCE { + ospfExtLsdbType + INTEGER, + ospfExtLsdbLsid + IpAddress, + ospfExtLsdbRouterId + RouterID, + ospfExtLsdbSequence + Integer32, + ospfExtLsdbAge + Integer32, + ospfExtLsdbChecksum + Integer32, + ospfExtLsdbAdvertisement + OCTET STRING + } + + ospfExtLsdbType OBJECT-TYPE + SYNTAX INTEGER { + asExternalLink (5) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of the link state advertisement. + Each link state type has a separate advertise- + ment format." + REFERENCE + "OSPF Version 2, Appendix A.4.1 The Link State + Advertisement header" + ::= { ospfExtLsdbEntry 1 } + + + ospfExtLsdbLsid OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Link State ID is an LS Type Specific field + containing either a Router ID or an IP Address; + it identifies the piece of the routing domain + that is being described by the advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.4 Link State ID" + ::= { ospfExtLsdbEntry 2 } + + + ospfExtLsdbRouterId OBJECT-TYPE + SYNTAX RouterID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The 32 bit number that uniquely identifies the + originating router in the Autonomous System." + REFERENCE + "OSPF Version 2, Appendix C.1 Global parameters" + ::= { ospfExtLsdbEntry 3 } + +-- Note that the OSPF Sequence Number is a 32 bit signed +-- integer. It starts with the value '80000001'h, +-- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h +-- Thus, a typical sequence number will be very negative. + ospfExtLsdbSequence OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The sequence number field is a signed 32-bit + integer. It is used to detect old and dupli- + cate link state advertisements. The space of + sequence numbers is linearly ordered. The + larger the sequence number the more recent the + advertisement." + REFERENCE + "OSPF Version 2, Section 12.1.6 LS sequence + number" + ::= { ospfExtLsdbEntry 4 } + + + ospfExtLsdbAge OBJECT-TYPE + SYNTAX Integer32 -- Should be 0..MaxAge + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the age of the link state adver- + tisement in seconds." + REFERENCE + "OSPF Version 2, Section 12.1.1 LS age" + ::= { ospfExtLsdbEntry 5 } + + + ospfExtLsdbChecksum OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is the checksum of the complete + contents of the advertisement, excepting the + age field. The age field is excepted so that + an advertisement's age can be incremented + without updating the checksum. The checksum + used is the same that is used for ISO connec- + tionless datagrams; it is commonly referred to + as the Fletcher checksum." + REFERENCE + "OSPF Version 2, Section 12.1.7 LS checksum" + ::= { ospfExtLsdbEntry 6 } + + + ospfExtLsdbAdvertisement OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(36)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The entire Link State Advertisement, including + its header." + REFERENCE + "OSPF Version 2, Section 12 Link State Adver- + tisements" + ::= { ospfExtLsdbEntry 7 } + + +-- OSPF Use of the CIDR Route Table + +ospfRouteGroup OBJECT IDENTIFIER ::= { ospf 13 } + +-- The IP Forwarding Table defines a number of objects for use by +-- the routing protocol to externalize its information. Most of +-- the variables (ipForwardDest, ipForwardMask, ipForwardPolicy, +-- ipForwardNextHop, ipForwardIfIndex, ipForwardType, +-- ipForwardProto, ipForwardAge, and ipForwardNextHopAS) are +-- defined there. + +-- Those that leave some discretion are defined here. + +-- ipCidrRouteProto is, of course, ospf (13). + +-- ipCidrRouteAge is the time since the route was first calculated, +-- as opposed to the time since the last SPF run. + +-- ipCidrRouteInfo is an OBJECT IDENTIFIER for use by the routing +-- protocol. The following values shall be found there depending +-- on the way the route was calculated. + +ospfIntraArea OBJECT IDENTIFIER ::= { ospfRouteGroup 1 } +ospfInterArea OBJECT IDENTIFIER ::= { ospfRouteGroup 2 } +ospfExternalType1 OBJECT IDENTIFIER ::= { ospfRouteGroup 3 } +ospfExternalType2 OBJECT IDENTIFIER ::= { ospfRouteGroup 4 } + +-- ipCidrRouteMetric1 is, by definition, the primary routing +-- metric. Therefore, it should be the metric that route +-- selection is based on. For intra-area and inter-area routes, +-- it is an OSPF metric. For External Type 1 (comparable value) +-- routes, it is an OSPF metric plus the External Metric. For +-- external Type 2 (non-comparable value) routes, it is the +-- external metric. + +-- ipCidrRouteMetric2 is, by definition, a secondary routing +-- metric. Therefore, it should be the metric that breaks a tie +-- among routes having equal metric1 values and the same +-- calculation rule. For intra-area, inter-area routes, and +-- External Type 1 (comparable value) routes, it is unused. For +-- external Type 2 (non-comparable value) routes, it is the metric +-- to the AS border router. + +-- ipCidrRouteMetric3, ipCidrRouteMetric4, and ipCidrRouteMetric5 are +-- unused. + +-- +-- The OSPF Area Aggregate Table +-- +-- This table replaces the OSPF Area Summary Table, being an +-- extension of that for CIDR routers. + + ospfAreaAggregateTable OBJECT-TYPE + SYNTAX SEQUENCE OF OspfAreaAggregateEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A range of IP addresses specified by an IP + address/IP network mask pair. For example, + class B address range of X.X.X.X with a network + mask of 255.255.0.0 includes all IP addresses + from X.X.0.0 to X.X.255.255. Note that if + ranges are configured such that one range sub- + sumes another range (e.g., 10.0.0.0 mask + 255.0.0.0 and 10.1.0.0 mask 255.255.0.0), the + most specific match is the preferred one." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospf 14 } + + + ospfAreaAggregateEntry OBJECT-TYPE + SYNTAX OspfAreaAggregateEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A range of IP addresses specified by an IP + address/IP network mask pair. For example, + class B address range of X.X.X.X with a network + mask of 255.255.0.0 includes all IP addresses + from X.X.0.0 to X.X.255.255. Note that if + ranges are range configured such that one range + subsumes another range (e.g., 10.0.0.0 mask + 255.0.0.0 and 10.1.0.0 mask 255.255.0.0), the + most specific match is the preferred one." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + INDEX { ospfAreaAggregateAreaID, ospfAreaAggregateLsdbType, + ospfAreaAggregateNet, ospfAreaAggregateMask } + ::= { ospfAreaAggregateTable 1 } + + +OspfAreaAggregateEntry ::= + SEQUENCE { + ospfAreaAggregateAreaID + AreaID, + ospfAreaAggregateLsdbType + INTEGER, + ospfAreaAggregateNet + IpAddress, + ospfAreaAggregateMask + IpAddress, + ospfAreaAggregateStatus + RowStatus, + ospfAreaAggregateEffect + INTEGER + } + + ospfAreaAggregateAreaID OBJECT-TYPE + SYNTAX AreaID + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Area the Address Aggregate is to be found + within." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaAggregateEntry 1 } + + + ospfAreaAggregateLsdbType OBJECT-TYPE + SYNTAX INTEGER { + summaryLink (3), + nssaExternalLink (7) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of the Address Aggregate. This field + specifies the Lsdb type that this Address Ag- + gregate applies to." + REFERENCE + "OSPF Version 2, Appendix A.4.1 The Link State + Advertisement header" + ::= { ospfAreaAggregateEntry 2 } + + + ospfAreaAggregateNet OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of the Net or Subnet indicated + by the range." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaAggregateEntry 3 } + + + ospfAreaAggregateMask OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Subnet Mask that pertains to the Net or + Subnet." + REFERENCE + "OSPF Version 2, Appendix C.2 Area parameters" + ::= { ospfAreaAggregateEntry 4 } + + + ospfAreaAggregateStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable displays the status of the en- + try. Setting it to 'invalid' has the effect of + rendering it inoperative. The internal effect + (row removal) is implementation dependent." + ::= { ospfAreaAggregateEntry 5 } + + + ospfAreaAggregateEffect OBJECT-TYPE + SYNTAX INTEGER { + advertiseMatching (1), + doNotAdvertiseMatching (2) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Subnets subsumed by ranges either trigger the + advertisement of the indicated aggregate (ad- + vertiseMatching), or result in the subnet's not + being advertised at all outside the area." + DEFVAL { advertiseMatching } + ::= { ospfAreaAggregateEntry 6 } + + +-- conformance information + +ospfConformance OBJECT IDENTIFIER ::= { ospf 15 } + +ospfGroups OBJECT IDENTIFIER ::= { ospfConformance 1 } +ospfCompliances OBJECT IDENTIFIER ::= { ospfConformance 2 } + +-- compliance statements + + ospfCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement " + MODULE -- this module + MANDATORY-GROUPS { + ospfBasicGroup, + ospfAreaGroup, + ospfStubAreaGroup, + ospfIfGroup, + ospfIfMetricGroup, + ospfVirtIfGroup, + ospfNbrGroup, + ospfVirtNbrGroup, + ospfAreaAggregateGroup + } + ::= { ospfCompliances 1 } + + +-- units of conformance + + ospfBasicGroup OBJECT-GROUP + OBJECTS { + ospfRouterId, + ospfAdminStat, + ospfVersionNumber, + ospfAreaBdrRtrStatus, + ospfASBdrRtrStatus, + ospfExternLsaCount, + ospfExternLsaCksumSum, + ospfTOSSupport, + ospfOriginateNewLsas, + ospfRxNewLsas, + ospfExtLsdbLimit, + ospfMulticastExtensions, + ospfExitOverflowInterval, + ospfDemandExtensions + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 1 } + + + ospfAreaGroup OBJECT-GROUP + OBJECTS { + ospfAreaId, + ospfImportAsExtern, + ospfSpfRuns, + ospfAreaBdrRtrCount, + ospfAsBdrRtrCount, + ospfAreaLsaCount, + ospfAreaLsaCksumSum, + ospfAreaSummary, + ospfAreaStatus + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + supporting areas." + ::= { ospfGroups 2 } + + + ospfStubAreaGroup OBJECT-GROUP + OBJECTS { + ospfStubAreaId, + ospfStubTOS, + ospfStubMetric, + ospfStubStatus, + ospfStubMetricType + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + supporting stub areas." + ::= { ospfGroups 3 } + + + ospfLsdbGroup OBJECT-GROUP + OBJECTS { + ospfLsdbAreaId, + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId, + ospfLsdbSequence, + ospfLsdbAge, + ospfLsdbChecksum, + ospfLsdbAdvertisement + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + that display their link state database." + ::= { ospfGroups 4 } + + + ospfAreaRangeGroup OBJECT-GROUP + OBJECTS { + ospfAreaRangeAreaId, + ospfAreaRangeNet, + ospfAreaRangeMask, + ospfAreaRangeStatus, + ospfAreaRangeEffect + } + STATUS obsolete + DESCRIPTION + "These objects are required for non-CIDR OSPF + systems that support multiple areas." + ::= { ospfGroups 5 } + + + ospfHostGroup OBJECT-GROUP + OBJECTS { + ospfHostIpAddress, + ospfHostTOS, + ospfHostMetric, + ospfHostStatus, + ospfHostAreaID + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + that support attached hosts." + ::= { ospfGroups 6 } + + + ospfIfGroup OBJECT-GROUP + OBJECTS { + ospfIfIpAddress, + ospfAddressLessIf, + ospfIfAreaId, + ospfIfType, + ospfIfAdminStat, + ospfIfRtrPriority, + ospfIfTransitDelay, + ospfIfRetransInterval, + ospfIfHelloInterval, + ospfIfRtrDeadInterval, + ospfIfPollInterval, + ospfIfState, + ospfIfDesignatedRouter, + ospfIfBackupDesignatedRouter, + ospfIfEvents, + ospfIfAuthType, + ospfIfAuthKey, + ospfIfStatus, + ospfIfMulticastForwarding, + ospfIfDemand + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 7 } + + + ospfIfMetricGroup OBJECT-GROUP + OBJECTS { + ospfIfMetricIpAddress, + ospfIfMetricAddressLessIf, + ospfIfMetricTOS, + ospfIfMetricValue, + ospfIfMetricStatus + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 8 } + + + ospfVirtIfGroup OBJECT-GROUP + OBJECTS { + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfVirtIfTransitDelay, + ospfVirtIfRetransInterval, + ospfVirtIfHelloInterval, + ospfVirtIfRtrDeadInterval, + ospfVirtIfState, + ospfVirtIfEvents, + ospfVirtIfAuthType, + ospfVirtIfAuthKey, + ospfVirtIfStatus + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 9 } + + + ospfNbrGroup OBJECT-GROUP + OBJECTS { + ospfNbrIpAddr, + ospfNbrAddressLessIndex, + ospfNbrRtrId, + ospfNbrOptions, + ospfNbrPriority, + ospfNbrState, + ospfNbrEvents, + ospfNbrLsRetransQLen, + ospfNbmaNbrStatus, + ospfNbmaNbrPermanence, + ospfNbrHelloSuppressed + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 10 } + + + ospfVirtNbrGroup OBJECT-GROUP + OBJECTS { + ospfVirtNbrArea, + ospfVirtNbrRtrId, + ospfVirtNbrIpAddr, + ospfVirtNbrOptions, + ospfVirtNbrState, + ospfVirtNbrEvents, + ospfVirtNbrLsRetransQLen, + ospfVirtNbrHelloSuppressed + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 11 } + + + ospfExtLsdbGroup OBJECT-GROUP + OBJECTS { + ospfExtLsdbType, + ospfExtLsdbLsid, + ospfExtLsdbRouterId, + ospfExtLsdbSequence, + ospfExtLsdbAge, + ospfExtLsdbChecksum, + ospfExtLsdbAdvertisement + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems + that display their link state database." + ::= { ospfGroups 12 } + + + ospfAreaAggregateGroup OBJECT-GROUP + OBJECTS { + ospfAreaAggregateAreaID, + ospfAreaAggregateLsdbType, + ospfAreaAggregateNet, + ospfAreaAggregateMask, + ospfAreaAggregateStatus, + ospfAreaAggregateEffect + } + STATUS current + DESCRIPTION + "These objects are required for OSPF systems." + ::= { ospfGroups 13 } + +END diff --git a/ospfd/OSPF-TRAP-MIB.txt b/ospfd/OSPF-TRAP-MIB.txt new file mode 100644 index 0000000..8a3ab99 --- /dev/null +++ b/ospfd/OSPF-TRAP-MIB.txt @@ -0,0 +1,443 @@ +OSPF-TRAP-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, IpAddress + FROM SNMPv2-SMI + MODULE-COMPLIANCE, OBJECT-GROUP + FROM SNMPv2-CONF + ospfRouterId, ospfIfIpAddress, ospfAddressLessIf, ospfIfState, + ospfVirtIfAreaId, ospfVirtIfNeighbor, ospfVirtIfState, + ospfNbrIpAddr, ospfNbrAddressLessIndex, ospfNbrRtrId, + ospfNbrState, ospfVirtNbrArea, ospfVirtNbrRtrId, ospfVirtNbrState, + ospfLsdbType, ospfLsdbLsid, ospfLsdbRouterId, ospfLsdbAreaId, + ospfExtLsdbLimit, ospf + FROM OSPF-MIB; + + ospfTrap MODULE-IDENTITY + LAST-UPDATED "9501201225Z" -- Fri Jan 20 12:25:50 PST 1995 + ORGANIZATION "IETF OSPF Working Group" + CONTACT-INFO + " Fred Baker + Postal: Cisco Systems + 519 Lado Drive + Santa Barbara, California 93111 + Tel: +1 805 681 0115 + E-Mail: fred@cisco.com + + Rob Coltun + Postal: RainbowBridge Communications + Tel: (301) 340-9416 + E-Mail: rcoltun@rainbow-bridge.com" + DESCRIPTION + "The MIB module to describe traps for the OSPF + Version 2 Protocol." + ::= { ospf 16 } + +-- Trap Support Objects + +-- The following are support objects for the OSPF traps. + +ospfTrapControl OBJECT IDENTIFIER ::= { ospfTrap 1 } +ospfTraps OBJECT IDENTIFIER ::= { ospfTrap 2 } + + ospfSetTrap OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(4)) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "A four-octet string serving as a bit map for + the trap events defined by the OSPF traps. This + object is used to enable and disable specific + OSPF traps where a 1 in the bit field + represents enabled. The right-most bit (least + significant) represents trap 0." + ::= { ospfTrapControl 1 } + + + ospfConfigErrorType OBJECT-TYPE + SYNTAX INTEGER { + badVersion (1), + areaMismatch (2), + unknownNbmaNbr (3), -- Router is Dr eligible + unknownVirtualNbr (4), + authTypeMismatch(5), + authFailure (6), + netMaskMismatch (7), + helloIntervalMismatch (8), + deadIntervalMismatch (9), + optionMismatch (10) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Potential types of configuration conflicts. + Used by the ospfConfigError and ospfConfigVir- + tError traps." + ::= { ospfTrapControl 2 } + + + ospfPacketType OBJECT-TYPE + SYNTAX INTEGER { + hello (1), + dbDescript (2), + lsReq (3), + lsUpdate (4), + lsAck (5) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "OSPF packet types." + ::= { ospfTrapControl 3 } + + + ospfPacketSrc OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of an inbound packet that can- + not be identified by a neighbor instance." + ::= { ospfTrapControl 4 } + + +-- Traps + + + ospfIfStateChange NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfIfState -- The new state + } + STATUS current + DESCRIPTION + "An ospfIfStateChange trap signifies that there + has been a change in the state of a non-virtual + OSPF interface. This trap should be generated + when the interface state regresses (e.g., goes + from Dr to Down) or progresses to a terminal + state (i.e., Point-to-Point, DR Other, Dr, or + Backup)." + ::= { ospfTraps 16 } + + + ospfVirtIfStateChange NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfVirtIfState -- The new state + } + STATUS current + DESCRIPTION + "An ospfIfStateChange trap signifies that there + has been a change in the state of an OSPF vir- + tual interface. + This trap should be generated when the inter- + face state regresses (e.g., goes from Point- + to-Point to Down) or progresses to a terminal + state (i.e., Point-to-Point)." + ::= { ospfTraps 1 } + + + ospfNbrStateChange NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfNbrIpAddr, + ospfNbrAddressLessIndex, + ospfNbrRtrId, + ospfNbrState -- The new state + } + STATUS current + DESCRIPTION + "An ospfNbrStateChange trap signifies that + there has been a change in the state of a non- + virtual OSPF neighbor. This trap should be + generated when the neighbor state regresses + (e.g., goes from Attempt or Full to 1-Way or + Down) or progresses to a terminal state (e.g., + 2-Way or Full). When an neighbor transitions + from or to Full on non-broadcast multi-access + and broadcast networks, the trap should be gen- + erated by the designated router. A designated + router transitioning to Down will be noted by + ospfIfStateChange." + ::= { ospfTraps 2 } + + + ospfVirtNbrStateChange NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtNbrArea, + ospfVirtNbrRtrId, + ospfVirtNbrState -- The new state + } + STATUS current + DESCRIPTION + "An ospfIfStateChange trap signifies that there + has been a change in the state of an OSPF vir- + tual neighbor. This trap should be generated + when the neighbor state regresses (e.g., goes + from Attempt or Full to 1-Way or Down) or + progresses to a terminal state (e.g., Full)." + ::= { ospfTraps 3 } + ospfIfConfigError NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfPacketSrc, -- The source IP address + ospfConfigErrorType, -- Type of error + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfIfConfigError trap signifies that a + packet has been received on a non-virtual in- + terface from a router whose configuration + parameters conflict with this router's confi- + guration parameters. Note that the event op- + tionMismatch should cause a trap only if it + prevents an adjacency from forming." + ::= { ospfTraps 4 } + + + ospfVirtIfConfigError NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfConfigErrorType, -- Type of error + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfConfigError trap signifies that a pack- + et has been received on a virtual interface + from a router whose configuration parameters + conflict with this router's configuration + parameters. Note that the event optionMismatch + should cause a trap only if it prevents an ad- + jacency from forming." + ::= { ospfTraps 5 } + + + ospfIfAuthFailure NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfPacketSrc, -- The source IP address + ospfConfigErrorType, -- authTypeMismatch or + -- authFailure + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfIfAuthFailure trap signifies that a + packet has been received on a non-virtual in- + terface from a router whose authentication key + or authentication type conflicts with this + router's authentication key or authentication + type." + ::= { ospfTraps 6 } + + + ospfVirtIfAuthFailure NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfConfigErrorType, -- authTypeMismatch or + -- authFailure + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfVirtIfAuthFailure trap signifies that a + packet has been received on a virtual interface + from a router whose authentication key or au- + thentication type conflicts with this router's + authentication key or authentication type." + ::= { ospfTraps 7 } + + + ospfIfRxBadPacket NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfPacketSrc, -- The source IP address + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfIfRxBadPacket trap signifies that an + OSPF packet has been received on a non-virtual + interface that cannot be parsed." + ::= { ospfTraps 8 } + + ospfVirtIfRxBadPacket NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfPacketType + } + STATUS current + DESCRIPTION + "An ospfRxBadPacket trap signifies that an OSPF + packet has been received on a virtual interface + that cannot be parsed." + ::= { ospfTraps 9 } + + + ospfTxRetransmit NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfIfIpAddress, + ospfAddressLessIf, + ospfNbrRtrId, -- Destination + ospfPacketType, + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId + } + STATUS current + DESCRIPTION + "An ospfTxRetransmit trap signifies than an + OSPF packet has been retransmitted on a non- + virtual interface. All packets that may be re- + transmitted are associated with an LSDB entry. + The LS type, LS ID, and Router ID are used to + identify the LSDB entry." + ::= { ospfTraps 10 } + + + ospfVirtIfTxRetransmit NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfVirtIfAreaId, + ospfVirtIfNeighbor, + ospfPacketType, + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId + } + STATUS current + DESCRIPTION + "An ospfTxRetransmit trap signifies than an + OSPF packet has been retransmitted on a virtual + interface. All packets that may be retransmit- + ted are associated with an LSDB entry. The LS + type, LS ID, and Router ID are used to identify + the LSDB entry." + ::= { ospfTraps 11 } + + + ospfOriginateLsa NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfLsdbAreaId, -- 0.0.0.0 for AS Externals + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId + } + STATUS current + DESCRIPTION + "An ospfOriginateLsa trap signifies that a new + LSA has been originated by this router. This + trap should not be invoked for simple refreshes + of LSAs (which happesn every 30 minutes), but + instead will only be invoked when an LSA is + (re)originated due to a topology change. Addi- + tionally, this trap does not include LSAs that + are being flushed because they have reached + MaxAge." + ::= { ospfTraps 12 } + + + ospfMaxAgeLsa NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfLsdbAreaId, -- 0.0.0.0 for AS Externals + ospfLsdbType, + ospfLsdbLsid, + ospfLsdbRouterId + } + STATUS current + DESCRIPTION + "An ospfMaxAgeLsa trap signifies that one of + the LSA in the router's link-state database has + aged to MaxAge." + ::= { ospfTraps 13 } + + + ospfLsdbOverflow NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfExtLsdbLimit + } + STATUS current + DESCRIPTION + "An ospfLsdbOverflow trap signifies that the + number of LSAs in the router's link-state data- + base has exceeded ospfExtLsdbLimit." + ::= { ospfTraps 14 } + + + ospfLsdbApproachingOverflow NOTIFICATION-TYPE + OBJECTS { + ospfRouterId, -- The originator of the trap + ospfExtLsdbLimit + } + STATUS current + DESCRIPTION + "An ospfLsdbApproachingOverflow trap signifies + that the number of LSAs in the router's link- + state database has exceeded ninety percent of + ospfExtLsdbLimit." + ::= { ospfTraps 15 } + + +-- conformance information + +ospfTrapConformance OBJECT IDENTIFIER ::= { ospfTrap 3 } + +ospfTrapGroups OBJECT IDENTIFIER ::= { ospfTrapConformance 1 } +ospfTrapCompliances OBJECT IDENTIFIER ::= { ospfTrapConformance 2 } + +-- compliance statements + + ospfTrapCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement " + MODULE -- this module + MANDATORY-GROUPS { ospfTrapControlGroup } + + + GROUP ospfTrapControlGroup + DESCRIPTION + "This group is optional but recommended for all + OSPF systems" + ::= { ospfTrapCompliances 1 } + + +-- units of conformance + + ospfTrapControlGroup OBJECT-GROUP + OBJECTS { + ospfSetTrap, + ospfConfigErrorType, + ospfPacketType, + ospfPacketSrc + } + STATUS current + DESCRIPTION + "These objects are required to control traps + from OSPF systems." + ::= { ospfTrapGroups 1 } + + +END diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c new file mode 100644 index 0000000..75d8b8e --- /dev/null +++ b/ospfd/ospf_abr.c @@ -0,0 +1,1728 @@ +/* + * OSPF ABR functions. + * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + + +#include + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "vty.h" +#include "filter.h" +#include "plist.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ia.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + + +struct ospf_area_range * +ospf_area_range_new (struct prefix_ipv4 *p) +{ + struct ospf_area_range *range; + + range = XCALLOC (MTYPE_OSPF_AREA_RANGE, sizeof (struct ospf_area_range)); + range->addr = p->prefix; + range->masklen = p->prefixlen; + range->cost_config = OSPF_AREA_RANGE_COST_UNSPEC; + + return range; +} + +void +ospf_area_range_free (struct ospf_area_range *range) +{ + XFREE (MTYPE_OSPF_AREA_RANGE, range); +} + +void +ospf_area_range_add (struct ospf_area *area, struct ospf_area_range *range) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefixlen = range->masklen; + p.prefix = range->addr; + + rn = route_node_get (area->ranges, (struct prefix *)&p); + if (rn->info) + route_unlock_node (rn); + else + rn->info = range; +} + +void +ospf_area_range_delete (struct ospf_area *area, struct ospf_area_range *range) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefixlen = range->masklen; + p.prefix = range->addr; + + rn = route_node_lookup (area->ranges, (struct prefix *)&p); + if (rn) + { + ospf_area_range_free (rn->info); + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + } +} + +struct ospf_area_range * +ospf_area_range_lookup (struct ospf_area *area, struct prefix_ipv4 *p) +{ + struct route_node *rn; + + rn = route_node_lookup (area->ranges, (struct prefix *)p); + if (rn) + { + route_unlock_node (rn); + return rn->info; + } + return NULL; +} + +struct ospf_area_range * +ospf_area_range_lookup_next (struct ospf_area *area, struct in_addr *range_net, + int first) +{ + struct route_node *rn; + struct prefix_ipv4 p; + struct ospf_area_range *find; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.prefix = *range_net; + + if (first) + rn = route_top (area->ranges); + else + { + rn = route_node_get (area->ranges, (struct prefix *) &p); + rn = route_next (rn); + } + + for (; rn; rn = route_next (rn)) + if (rn->info) + break; + + if (rn && rn->info) + { + find = rn->info; + *range_net = rn->p.u.prefix4; + route_unlock_node (rn); + return find; + } + return NULL; +} + +struct ospf_area_range * +ospf_area_range_match (struct ospf_area *area, struct prefix_ipv4 *p) +{ + struct route_node *node; + + node = route_node_match (area->ranges, (struct prefix *) p); + if (node) + { + route_unlock_node (node); + return node->info; + } + return NULL; +} + +struct ospf_area_range * +ospf_area_range_match_any (struct ospf *ospf, struct prefix_ipv4 *p) +{ + struct ospf_area_range *range; + listnode node; + + for (node = listhead (ospf->areas); node; nextnode (node)) + if ((range = ospf_area_range_match (node->data, p))) + return range; + + return NULL; +} + +int +ospf_area_range_active (struct ospf_area_range *range) +{ + return range->specifics; +} + +int +ospf_area_actively_attached (struct ospf_area *area) +{ + return area->act_ints; +} + +int +ospf_area_range_set (struct ospf *ospf, struct in_addr area_id, + struct prefix_ipv4 *p, int advertise) +{ + struct ospf_area *area; + struct ospf_area_range *range; + int ret = OSPF_AREA_ID_FORMAT_ADDRESS; + + area = ospf_area_get (ospf, area_id, ret); + if (area == NULL) + return 0; + + range = ospf_area_range_lookup (area, p); + if (range != NULL) + { + if ((CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE) + && !CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE)) + || (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE) + && CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE))) + ospf_schedule_abr_task (ospf); + } + else + { + range = ospf_area_range_new (p); + ospf_area_range_add (area, range); + ospf_schedule_abr_task (ospf); + } + + if (CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE)) + SET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE); + else + UNSET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE); + + return 1; +} + +int +ospf_area_range_cost_set (struct ospf *ospf, struct in_addr area_id, + struct prefix_ipv4 *p, u_int32_t cost) +{ + struct ospf_area *area; + struct ospf_area_range *range; + int ret = OSPF_AREA_ID_FORMAT_ADDRESS; + + area = ospf_area_get (ospf, area_id, ret); + if (area == NULL) + return 0; + + range = ospf_area_range_new (p); + if (range == NULL) + return 0; + + if (range->cost_config != cost) + { + range->cost_config = cost; + if (ospf_area_range_active (range)) + ospf_schedule_abr_task (ospf); + } + + return 1; +} + +int +ospf_area_range_unset (struct ospf *ospf, struct in_addr area_id, + struct prefix_ipv4 *p) +{ + struct ospf_area *area; + struct ospf_area_range *range; + + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (area == NULL) + return 0; + + range = ospf_area_range_lookup (area, p); + if (range == NULL) + return 0; + + if (ospf_area_range_active (range)) + ospf_schedule_abr_task (ospf); + + ospf_area_range_delete (area, range); + + return 1; +} + +int +ospf_area_range_substitute_set (struct ospf *ospf, struct in_addr area_id, + struct prefix_ipv4 *p, struct prefix_ipv4 *s) +{ + struct ospf_area *area; + struct ospf_area_range *range; + int ret = OSPF_AREA_ID_FORMAT_ADDRESS; + + area = ospf_area_get (ospf, area_id, ret); + range = ospf_area_range_lookup (area, p); + + if (range != NULL) + { + if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE) || + !CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) + ospf_schedule_abr_task (ospf); + } + else + { + range = ospf_area_range_new (p); + ospf_area_range_add (area, range); + ospf_schedule_abr_task (ospf); + } + + SET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE); + SET_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE); + range->subst_addr = s->prefix; + range->subst_masklen = s->prefixlen; + + return 1; +} + +int +ospf_area_range_substitute_unset (struct ospf *ospf, struct in_addr area_id, + struct prefix_ipv4 *p) +{ + struct ospf_area *area; + struct ospf_area_range *range; + + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (area == NULL) + return 0; + + range = ospf_area_range_lookup (area, p); + if (range == NULL) + return 0; + + if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) + if (ospf_area_range_active (range)) + ospf_schedule_abr_task (ospf); + + UNSET_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE); + range->subst_addr.s_addr = 0; + range->subst_masklen = 0; + + return 1; +} + +int +ospf_act_bb_connection (struct ospf *ospf) +{ + if (ospf->backbone == NULL) + return 0; + + return ospf->backbone->full_nbrs; +} + +/* Check area border router status. */ +void +ospf_check_abr_status (struct ospf *ospf) +{ + struct ospf_area *area; + listnode node; + int bb_configured = 0; + int bb_act_attached = 0; + int areas_configured = 0; + int areas_act_attached = 0; + u_char new_flags = ospf->flags; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_check_abr_status(): Start"); + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + + if (listcount (area->oiflist)) + { + areas_configured++; + + if (OSPF_IS_AREA_BACKBONE (area)) + bb_configured = 1; + } + + if (ospf_area_actively_attached (area)) + { + areas_act_attached++; + + if (OSPF_IS_AREA_BACKBONE (area)) + bb_act_attached = 1; + } + } + + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_check_abr_status(): looked through areas"); + zlog_info ("ospf_check_abr_status(): bb_configured: %d", bb_configured); + zlog_info ("ospf_check_abr_status(): bb_act_attached: %d", + bb_act_attached); + zlog_info ("ospf_check_abr_status(): areas_configured: %d", + areas_configured); + zlog_info ("ospf_check_abr_status(): areas_act_attached: %d", + areas_act_attached); + } + + switch (ospf->abr_type) + { + case OSPF_ABR_SHORTCUT: + case OSPF_ABR_STAND: + if (areas_act_attached > 1) + SET_FLAG (new_flags, OSPF_FLAG_ABR); + else + UNSET_FLAG (new_flags, OSPF_FLAG_ABR); + break; + + case OSPF_ABR_IBM: + if ((areas_act_attached > 1) && bb_configured) + SET_FLAG (new_flags, OSPF_FLAG_ABR); + else + UNSET_FLAG (new_flags, OSPF_FLAG_ABR); + break; + + case OSPF_ABR_CISCO: + if ((areas_configured > 1) && bb_act_attached) + SET_FLAG (new_flags, OSPF_FLAG_ABR); + else + UNSET_FLAG (new_flags, OSPF_FLAG_ABR); + break; + default: + break; + } + + if (new_flags != ospf->flags) + { + ospf_spf_calculate_schedule (ospf); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_check_abr_status(): new router flags: %x",new_flags); + ospf->flags = new_flags; + OSPF_TIMER_ON (ospf->t_router_lsa_update, + ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY); + } +} + +void +ospf_abr_update_aggregate (struct ospf_area_range *range, + struct ospf_route *or) +{ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_update_aggregate(): Start"); + + if (range->cost_config != -1) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_update_aggregate(): use configured cost %d", + range->cost_config); + + range->cost = range->cost_config; + } + else + { + if (range->specifics == 0) + range->cost = or->cost; /* 1st time get 1st cost */ + + if (or->cost > range->cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_update_aggregate(): largest cost, update"); + + range->cost = or->cost; + } + } + + range->specifics++; +} + +static void +set_metric (struct ospf_lsa *lsa, u_int32_t metric) +{ + struct summary_lsa *header; + u_char *mp; + metric = htonl (metric); + mp = (char *) &metric; + mp++; + header = (struct summary_lsa *) lsa->data; + memcpy(header->metric, mp, 3); +} + +#ifdef HAVE_NSSA +int +ospf_abr_check_nssa_range (struct prefix_ipv4 *p, u_int32_t cost, + struct ospf_area *area) +{ + /* The Type-7 is tested against the aggregated prefix and forwarded + for lsa installation and flooding */ + return 0; +} + +/* ospf_abr_translate_nssa */ +int +ospf_abr_translate_nssa (struct ospf_area *area, struct ospf_lsa *lsa) +{ + /* Incoming Type-7 or later aggregated Type-7 + + LSA is skipped if P-bit is off. + LSA is aggregated if within range. + + The Type-7 is translated, Installed/Approved as a Type-5 into + global LSDB, then Flooded through AS + + Later, any Unapproved Translated Type-5's are flushed/discarded */ + + struct ospf_lsa *dup; + + if (! CHECK_FLAG (lsa->data->options, OSPF_OPTION_NP)) + { + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa(): P-bit off, NO Translation"); + return 0; + } + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa(): TRANSLATING 7 to 5"); + + /* No more P-bit. */ + /* UNSET_FLAG (lsa->data->options, OSPF_OPTION_NP); */ + + /* Area where Aggregate testing will be inserted, just like summary + advertisements */ + /* ospf_abr_check_nssa_range (p_arg, lsa-> cost, lsa -> area); */ + + /* Follow thru here means no aggregation */ + dup = ospf_lsa_dup (lsa); /* keep LSDB intact, lock = 1 */ + + SET_FLAG (dup->flags, OSPF_LSA_LOCAL_XLT); /* Translated from 7 */ + SET_FLAG (dup->flags, OSPF_LSA_APPROVED); /* So, do not remove it */ + + dup->data->type = OSPF_AS_EXTERNAL_LSA; /* make Type-5 */ + + ospf_lsa_checksum (dup->data); + + ospf_lsa_install (area->ospf, NULL, dup); /* Install this Type-5 into LSDB, Lock = 2. */ + + ospf_flood_through_as (area->ospf, NULL, dup); /* flood non-NSSA/STUB areas */ + + /* This translated Type-5 will go to all non-NSSA areas connected to + this ABR; The Type-5 could come from any of the NSSA's connected + to this ABR. */ + + return 0; +} + +void +ospf_abr_translate_nssa_range (struct prefix_ipv4 *p, u_int32_t cost) +{ + /* The Type-7 is created from the aggregated prefix and forwarded + for lsa installation and flooding... to be added... */ +} +#endif /* HAVE_NSSA */ + +void +ospf_abr_announce_network_to_area (struct prefix_ipv4 *p, u_int32_t cost, + struct ospf_area *area) +{ + struct ospf_lsa *lsa, *old = NULL; + struct summary_lsa *sl = NULL; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): Start"); + + old = ospf_lsa_lookup_by_prefix (area->lsdb, OSPF_SUMMARY_LSA, p, + area->ospf->router_id); + if (old) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): old summary found"); + sl = (struct summary_lsa *) old->data; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): " + "old metric: %d, new metric: %d", + GET_METRIC (sl->metric), cost); + } + + if (old && (GET_METRIC (sl->metric) == cost)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): " + "old summary approved"); + SET_FLAG (old->flags, OSPF_LSA_APPROVED); + } + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): " + "creating new summary"); + if (old) + { + + set_metric (old, cost); + lsa = ospf_summary_lsa_refresh (area->ospf, old); + /* This will flood through area. */ + } + else + { + lsa = ospf_summary_lsa_originate (p, cost, area); + /* This will flood through area. */ + } + + + SET_FLAG (lsa->flags, OSPF_LSA_APPROVED); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): " + "flooding new version of summary"); + +#ifndef HAVE_NSSA + ospf_flood_through_area (area, NULL, lsa); +#endif /* ! HAVE_NSSA */ + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): Stop"); +} + +int +ospf_abr_nexthops_belong_to_area (struct ospf_route *or, + struct ospf_area *area) +{ + listnode node; + + for (node = listhead (or->path); node; nextnode (node)) + { + struct ospf_path *path = node->data; + struct ospf_interface *oi = path->oi; + + if (oi != NULL) + if (oi->area == area) + return 1; + } + + return 0; +} + +int +ospf_abr_should_accept (struct prefix *p, struct ospf_area *area) +{ + if (IMPORT_NAME (area)) + { + if (IMPORT_LIST (area) == NULL) + IMPORT_LIST (area) = access_list_lookup (AFI_IP, IMPORT_NAME (area)); + + if (IMPORT_LIST (area)) + if (access_list_apply (IMPORT_LIST (area), p) == FILTER_DENY) + return 0; + } + + return 1; +} + +int +ospf_abr_plist_in_check (struct ospf_area *area, struct ospf_route *or, + struct prefix *p) +{ + if (PREFIX_NAME_IN (area)) + { + if (PREFIX_LIST_IN (area) == NULL) + PREFIX_LIST_IN (area) = prefix_list_lookup (AFI_IP, + PREFIX_NAME_IN (area)); + if (PREFIX_LIST_IN (area)) + if (prefix_list_apply (PREFIX_LIST_IN (area), p) != PREFIX_PERMIT) + return 0; + } + return 1; +} + +int +ospf_abr_plist_out_check (struct ospf_area *area, struct ospf_route *or, + struct prefix *p) +{ + if (PREFIX_NAME_OUT (area)) + { + if (PREFIX_LIST_OUT (area) == NULL) + PREFIX_LIST_OUT (area) = prefix_list_lookup (AFI_IP, + PREFIX_NAME_OUT (area)); + if (PREFIX_LIST_OUT (area)) + if (prefix_list_apply (PREFIX_LIST_OUT (area), p) != PREFIX_PERMIT) + return 0; + } + return 1; +} + +void +ospf_abr_announce_network (struct ospf *ospf, + struct route_node *n, struct ospf_route *or) +{ + struct ospf_area_range *range; + struct ospf_area *area, *or_area; + struct prefix_ipv4 *p; + listnode node; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): Start"); + p = (struct prefix_ipv4 *) &n->p; + + or_area = ospf_area_lookup_by_area_id (ospf, or->u.std.area_id); + assert (or_area); + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): looking at area %s", + inet_ntoa (area->area_id)); + + if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)) + continue; + + if (ospf_abr_nexthops_belong_to_area (or, area)) + continue; + + if (!ospf_abr_should_accept (&n->p, area)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): " + "prefix %s/%d was denied by import-list", + inet_ntoa (p->prefix), p->prefixlen); + continue; + } + + if (!ospf_abr_plist_in_check (area, or, &n->p)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): " + "prefix %s/%d was denied by prefix-list", + inet_ntoa (p->prefix), p->prefixlen); + continue; + } + + if (area->external_routing != OSPF_AREA_DEFAULT && area->no_summary) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): " + "area %s is stub and no_summary", + inet_ntoa (area->area_id)); + continue; + } + + if (or->path_type == OSPF_PATH_INTER_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): this is " + "inter-area route to %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + + if (!OSPF_IS_AREA_BACKBONE (area)) + ospf_abr_announce_network_to_area (p, or->cost, area); + } + + if (or->path_type == OSPF_PATH_INTRA_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): " + "this is intra-area route to %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + if ((range = ospf_area_range_match (or_area, p)) && + !ospf_area_is_transit (area)) + ospf_abr_update_aggregate (range, or); + else + ospf_abr_announce_network_to_area (p, or->cost, area); + } + } +} + +int +ospf_abr_should_announce (struct ospf *ospf, + struct prefix *p, struct ospf_route *or) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (ospf, or->u.std.area_id); + + assert (area); + + if (EXPORT_NAME (area)) + { + if (EXPORT_LIST (area) == NULL) + EXPORT_LIST (area) = access_list_lookup (AFI_IP, EXPORT_NAME (area)); + + if (EXPORT_LIST (area)) + if (access_list_apply (EXPORT_LIST (area), p) == FILTER_DENY) + return 0; + } + + return 1; +} + +#ifdef HAVE_NSSA +void +ospf_abr_process_nssa_translates (struct ospf *ospf) +{ + /* Scan through all NSSA_LSDB records for all areas; + + If P-bit is on, translate all Type-7's to 5's and aggregate or + flood install as approved in Type-5 LSDB with XLATE Flag on + later, do same for all aggregates... At end, DISCARD all + remaining UNAPPROVED Type-5's (Aggregate is for future ) */ + listnode node; + struct ospf_area *area; + struct route_node *rn; + struct ospf_lsa *lsa; + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_process_nssa_translates(): Start"); + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + + if (! area->NSSATranslator) + continue; /* skip if not translator */ + + if (area->external_routing != OSPF_AREA_NSSA) + continue; /* skip if not Nssa Area */ + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_process_nssa_translates(): " + "looking at area %s", inet_ntoa (area->area_id)); + + LSDB_LOOP (NSSA_LSDB (area), rn, lsa) + ospf_abr_translate_nssa (area, lsa); + } + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_process_nssa_translates(): Stop"); + +} +#endif /* HAVE_NSSA */ + +void +ospf_abr_process_network_rt (struct ospf *ospf, + struct route_table *rt) +{ + struct ospf_area *area; + struct ospf_route *or; + struct route_node *rn; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): Start"); + + for (rn = route_top (rt); rn; rn = route_next (rn)) + { + if ((or = rn->info) == NULL) + continue; + + if (!(area = ospf_area_lookup_by_area_id (ospf, or->u.std.area_id))) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): area %s no longer exists", + inet_ntoa (or->u.std.area_id)); + continue; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): this is a route to %s/%d", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); + if (or->path_type >= OSPF_PATH_TYPE1_EXTERNAL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): " + "this is an External router, skipping"); + continue; + } + + if (or->cost >= OSPF_LS_INFINITY) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt():" + " this route's cost is infinity, skipping"); + continue; + } + + if (or->type == OSPF_DESTINATION_DISCARD) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt():" + " this is a discard entry, skipping"); + continue; + } + + if (or->path_type == OSPF_PATH_INTRA_AREA && + !ospf_abr_should_announce (ospf, &rn->p, or)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_abr_process_network_rt(): denied by export-list"); + continue; + } + + if (or->path_type == OSPF_PATH_INTRA_AREA && + !ospf_abr_plist_out_check (area, or, &rn->p)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_abr_process_network_rt(): denied by prefix-list"); + continue; + } + + if ((or->path_type == OSPF_PATH_INTER_AREA) && + !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt():" + " this is route is not backbone one, skipping"); + continue; + } + + + if ((ospf->abr_type == OSPF_ABR_CISCO) || + (ospf->abr_type == OSPF_ABR_IBM)) + + if (!ospf_act_bb_connection (ospf) && + or->path_type != OSPF_PATH_INTRA_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): ALT ABR: " + "No BB connection, skip not intra-area routes"); + continue; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): announcing"); + ospf_abr_announce_network (ospf, rn, or); + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_network_rt(): Stop"); +} + +void +ospf_abr_announce_rtr_to_area (struct prefix_ipv4 *p, u_int32_t cost, + struct ospf_area *area) +{ + struct ospf_lsa *lsa, *old = NULL; + struct summary_lsa *slsa = NULL; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr_to_area(): Start"); + + old = ospf_lsa_lookup_by_prefix (area->lsdb, OSPF_ASBR_SUMMARY_LSA, + p, area->ospf->router_id); + if (old) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr_to_area(): old summary found"); + slsa = (struct summary_lsa *) old->data; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network_to_area(): " + "old metric: %d, new metric: %d", + GET_METRIC (slsa->metric), cost); + } + + if (old && (GET_METRIC (slsa->metric) == cost)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr_to_area(): old summary approved"); + SET_FLAG (old->flags, OSPF_LSA_APPROVED); + } + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr_to_area(): 2.2"); + + if (old) + { + set_metric (old, cost); + lsa = ospf_summary_asbr_lsa_refresh (area->ospf, old); + } + else + lsa = ospf_summary_asbr_lsa_originate (p, cost, area); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr_to_area(): " + "flooding new version of summary"); + /* + zlog_info ("ospf_abr_announce_rtr_to_area(): creating new summary"); + lsa = ospf_summary_asbr_lsa (p, cost, area, old); */ + + SET_FLAG (lsa->flags, OSPF_LSA_APPROVED); + /* ospf_flood_through_area (area, NULL, lsa);*/ + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr_to_area(): Stop"); +} + + +void +ospf_abr_announce_rtr (struct ospf *ospf, + struct prefix_ipv4 *p, struct ospf_route *or) +{ + listnode node; + struct ospf_area *area; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr(): Start"); + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr(): looking at area %s", + inet_ntoa (area->area_id)); + + if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)) + continue; + + if (ospf_abr_nexthops_belong_to_area (or, area)) + continue; + + if (area->external_routing != OSPF_AREA_DEFAULT) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_network(): " + "area %s doesn't support external routing", + inet_ntoa(area->area_id)); + continue; + } + + if (or->path_type == OSPF_PATH_INTER_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr(): " + "this is inter-area route to %s", inet_ntoa (p->prefix)); + if (!OSPF_IS_AREA_BACKBONE (area)) + ospf_abr_announce_rtr_to_area (p, or->cost, area); + } + + if (or->path_type == OSPF_PATH_INTRA_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr(): " + "this is intra-area route to %s", inet_ntoa (p->prefix)); + ospf_abr_announce_rtr_to_area (p, or->cost, area); + } + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_rtr(): Stop"); +} + +void +ospf_abr_process_router_rt (struct ospf *ospf, struct route_table *rt) +{ + struct ospf_route *or; + struct route_node *rn; + struct list *l; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): Start"); + + for (rn = route_top (rt); rn; rn = route_next (rn)) + { + listnode node; + char flag = 0; + struct ospf_route *best = NULL; + + if (rn->info == NULL) + continue; + + l = rn->info; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): this is a route to %s", + inet_ntoa (rn->p.u.prefix4)); + + for (node = listhead (l); node; nextnode (node)) + { + or = getdata (node); + if (or == NULL) + continue; + + if (!ospf_area_lookup_by_area_id (ospf, or->u.std.area_id)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): area %s no longer exists", + inet_ntoa (or->u.std.area_id)); + continue; + } + + + if (!CHECK_FLAG (or->u.std.flags, ROUTER_LSA_EXTERNAL)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): " + "This is not an ASBR, skipping"); + continue; + } + + if (!flag) + { + best = ospf_find_asbr_route (ospf, rt, + (struct prefix_ipv4 *) &rn->p); + flag = 1; + } + + if (best == NULL) + continue; + + if (or != best) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): " + "This route is not the best among possible, skipping"); + continue; + } + + if (or->path_type == OSPF_PATH_INTER_AREA && + !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): " + "This route is not a backbone one, skipping"); + continue; + } + + if (or->cost >= OSPF_LS_INFINITY) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): " + "This route has LS_INFINITY metric, skipping"); + continue; + } + + if (ospf->abr_type == OSPF_ABR_CISCO + || ospf->abr_type == OSPF_ABR_IBM) + if (!ospf_act_bb_connection (ospf) + && or->path_type != OSPF_PATH_INTRA_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_abr_process_network_rt(): ALT ABR: " + "No BB connection, skip not intra-area routes"); + continue; + } + + ospf_abr_announce_rtr (ospf, (struct prefix_ipv4 *) &rn->p, or); + + } + + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_process_router_rt(): Stop"); +} + +#ifdef HAVE_NSSA +void +ospf_abr_unapprove_translates (struct ospf *ospf) /* For NSSA Translations */ +{ + struct ospf_lsa *lsa; + struct route_node *rn; + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_unapprove_translates(): Start"); + + /* NSSA Translator is not checked, because it may have gone away, + and we would want to flush any residuals anyway */ + + LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) + UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED); + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_unapprove_translates(): Stop"); +} +#endif /* HAVE_NSSA */ + +void +ospf_abr_unapprove_summaries (struct ospf *ospf) +{ + listnode node; + struct ospf_area *area; + struct route_node *rn; + struct ospf_lsa *lsa; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_unapprove_summaries(): Start"); + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) + if (ospf_lsa_is_self_originated (ospf, lsa)) + UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED); + + LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) + if (ospf_lsa_is_self_originated (ospf, lsa)) + UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED); + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_unapprove_summaries(): Stop"); +} + +void +ospf_abr_prepare_aggregates (struct ospf *ospf) +{ + listnode node; + struct route_node *rn; + struct ospf_area_range *range; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_prepare_aggregates(): Start"); + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + struct ospf_area *area = getdata (node); + + for (rn = route_top (area->ranges); rn; rn = route_next (rn)) + if ((range = rn->info) != NULL) + { + range->cost = 0; + range->specifics = 0; + } + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_prepare_aggregates(): Stop"); +} + +void +ospf_abr_announce_aggregates (struct ospf *ospf) +{ + struct ospf_area *area, *ar; + struct ospf_area_range *range; + struct route_node *rn; + struct prefix_ipv4 p; + listnode node, n; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates(): Start"); + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates(): looking at area %s", + inet_ntoa (area->area_id)); + + for (rn = route_top (area->ranges); rn; rn = route_next (rn)) + if ((range = rn->info)) + { + if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates():" + " discarding suppress-ranges"); + continue; + } + + p.family = AF_INET; + p.prefix = range->addr; + p.prefixlen = range->masklen; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates():" + " this is range: %s/%d", + inet_ntoa (p.prefix), p.prefixlen); + + if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) + { + p.family = AF_INET; + p.prefix = range->subst_addr; + p.prefixlen = range->subst_masklen; + } + + if (range->specifics) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates(): active range"); + + for (n = listhead (ospf->areas); n; nextnode (n)) + { + ar = getdata (n); + if (ar == area) + continue; + + /* We do not check nexthops here, because + intra-area routes can be associated with + one area only */ + + /* backbone routes are not summarized + when announced into transit areas */ + + if (ospf_area_is_transit (ar) && + OSPF_IS_AREA_BACKBONE (area)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates(): Skipping " + "announcement of BB aggregate into" + " a transit area"); + continue; + } + ospf_abr_announce_network_to_area (&p, range->cost, ar); + } + } + } + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_aggregates(): Stop"); +} + +#ifdef HAVE_NSSA +void +ospf_abr_send_nssa_aggregates (struct ospf *ospf) /* temporarily turned off */ +{ + listnode node; /*, n; */ + struct ospf_area *area; /*, *ar; */ + struct route_node *rn; + struct ospf_area_range *range; + struct prefix_ipv4 p; + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_send_nssa_aggregates(): Start"); + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + + if (! area->NSSATranslator) + continue; + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_send_nssa_aggregates(): looking at area %s", + inet_ntoa (area->area_id)); + + for (rn = route_top (area->ranges); rn; rn = route_next (rn)) + { + if (rn->info == NULL) + continue; + + range = rn->info; + + if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) + { + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_send_nssa_aggregates():" + " discarding suppress-ranges"); + continue; + } + + p.family = AF_INET; + p.prefix = range->addr; + p.prefixlen = range->masklen; + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_send_nssa_aggregates():" + " this is range: %s/%d", + inet_ntoa (p.prefix), p.prefixlen); + + if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) + { + p.family = AF_INET; + p.prefix = range->subst_addr; + p.prefixlen = range->subst_masklen; + } + + if (range->specifics) + { + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_send_nssa_aggregates(): active range"); + + /* Fetch LSA-Type-7 from aggregate prefix, and then + translate, Install (as Type-5), Approve, and Flood */ + ospf_abr_translate_nssa_range (&p, range->cost); + } /* if (range->specifics)*/ + } /* all area ranges*/ + } /* all areas */ + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_send_nssa_aggregates(): Stop"); +} + +void +ospf_abr_announce_nssa_defaults (struct ospf *ospf) /* By ABR-Translator */ +{ + listnode node; + struct ospf_area *area; + struct prefix_ipv4 p; + + if (! IS_OSPF_ABR (ospf)) + return; + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_announce_stub_defaults(): Start"); + + p.family = AF_INET; + p.prefix.s_addr = OSPF_DEFAULT_DESTINATION; + p.prefixlen = 0; + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_announce_nssa_defaults(): looking at area %s", + inet_ntoa (area->area_id)); + + if (area->external_routing != OSPF_AREA_NSSA) + continue; + + if (OSPF_IS_AREA_BACKBONE (area)) + continue; /* Sanity Check */ + + /* if (!TranslatorRole continue V 1.0 look for "always" conf */ + if (area->NSSATranslator) + { + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_announce_nssa_defaults(): " + "announcing 0.0.0.0/0 to this nssa"); + /* ospf_abr_announce_nssa_asbr_to_as (&p, area->default_cost, area); */ + } + } +} +#endif /* HAVE_NSSA */ + +void +ospf_abr_announce_stub_defaults (struct ospf *ospf) +{ + listnode node; + struct ospf_area *area; + struct prefix_ipv4 p; + + if (! IS_OSPF_ABR (ospf)) + return; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_stub_defaults(): Start"); + + p.family = AF_INET; + p.prefix.s_addr = OSPF_DEFAULT_DESTINATION; + p.prefixlen = 0; + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_stub_defaults(): looking at area %s", + inet_ntoa (area->area_id)); + +#ifdef HAVE_NSSA + if (area->external_routing != OSPF_AREA_STUB) +#else /* ! HAVE_NSSA */ + if (area->external_routing == OSPF_AREA_DEFAULT) +#endif /* HAVE_NSSA */ + continue; + + if (OSPF_IS_AREA_BACKBONE (area)) + continue; /* Sanity Check */ + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_stub_defaults(): " + "announcing 0.0.0.0/0 to this area"); + ospf_abr_announce_network_to_area (&p, area->default_cost, area); + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_announce_stub_defaults(): Stop"); +} + +#ifdef HAVE_NSSA +int +ospf_abr_remove_unapproved_translates_apply (struct ospf *ospf, + struct ospf_lsa *lsa) +{ + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT) + && ! CHECK_FLAG (lsa->flags, OSPF_LSA_APPROVED)) + { + zlog_info ("ospf_abr_remove_unapproved_translates(): " + "removing unapproved translates, ID: %s", + inet_ntoa (lsa->data->id)); + + /* FLUSH THROUGHOUT AS */ + ospf_lsa_flush_as (ospf, lsa); + + /* DISCARD from LSDB */ + } + return 0; +} + +void +ospf_abr_remove_unapproved_translates (struct ospf *ospf) +{ + struct route_node *rn; + struct ospf_lsa *lsa; + + /* All AREA PROCESS should have APPROVED necessary LSAs */ + /* Remove any left over and not APPROVED */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_remove_unapproved_translates(): Start"); + + LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) + ospf_abr_remove_unapproved_translates_apply (ospf, lsa); + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_remove_unapproved_translates(): Stop"); +} +#endif /* HAVE_NSSA */ + +void +ospf_abr_remove_unapproved_summaries (struct ospf *ospf) +{ + listnode node; + struct ospf_area *area; + struct route_node *rn; + struct ospf_lsa *lsa; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_remove_unapproved_summaries(): Start"); + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_remove_unapproved_summaries(): " + "looking at area %s", inet_ntoa (area->area_id)); + + LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) + if (ospf_lsa_is_self_originated (ospf, lsa)) + if (!CHECK_FLAG (lsa->flags, OSPF_LSA_APPROVED)) + ospf_lsa_flush_area (lsa, area); + + LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) + if (ospf_lsa_is_self_originated (ospf, lsa)) + if (!CHECK_FLAG (lsa->flags, OSPF_LSA_APPROVED)) + ospf_lsa_flush_area (lsa, area); + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_remove_unapproved_summaries(): Stop"); +} + +void +ospf_abr_manage_discard_routes (struct ospf *ospf) +{ + listnode node; + struct route_node *rn; + struct ospf_area *area; + struct ospf_area_range *range; + + for (node = listhead (ospf->areas); node; nextnode (node)) + if ((area = node->data) != NULL) + for (rn = route_top (area->ranges); rn; rn = route_next (rn)) + if ((range = rn->info) != NULL) + if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) + { + if (range->specifics) + ospf_add_discard_route (ospf->new_table, area, + (struct prefix_ipv4 *) &rn->p); + else + ospf_delete_discard_route ((struct prefix_ipv4 *) &rn->p); + } +} + +#ifdef HAVE_NSSA +/* This is the function taking care about ABR NSSA, i.e. NSSA + Translator, -LSA aggregation and flooding. For all NSSAs + + Any SELF-AS-LSA is in the Type-5 LSDB and Type-7 LSDB. These LSA's + are refreshed from the Type-5 LSDB, installed into the Type-7 LSDB + with the P-bit set. + + Any received Type-5s are legal for an ABR, else illegal for IR. + Received Type-7s are installed, by area, with incoming P-bit. They + are flooded; if the Elected NSSA Translator, then P-bit off. + + Additionally, this ABR will place "translated type-7's" into the + Type-5 LSDB in order to keep track of APPROVAL or not. + + It will scan through every area, looking for Type-7 LSAs with P-Bit + SET. The Type-7's are either AS-FLOODED & 5-INSTALLED or + AGGREGATED. Later, the AGGREGATED LSAs are AS-FLOODED & + 5-INSTALLED. + + 5-INSTALLED is into the Type-5 LSDB; Any UNAPPROVED Type-5 LSAs + left over are FLUSHED and DISCARDED. + + For External Calculations, any NSSA areas use the Type-7 AREA-LSDB, + any ABR-non-NSSA areas use the Type-5 GLOBAL-LSDB. */ + +void +ospf_abr_nssa_task (struct ospf *ospf) /* called only if any_nssa */ +{ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("Check for NSSA-ABR Tasks():"); + + if (! IS_OSPF_ABR (ospf)) + return; + + if (! ospf->anyNSSA) + return; + + /* Each area must confirm TranslatorRole */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): Start"); + + /* For all Global Entries flagged "local-translate", unset APPROVED */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): unapprove translates"); + + ospf_abr_unapprove_translates (ospf); + + /* RESET all Ranges in every Area, same as summaries */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): NSSA initialize aggregates"); + + /* ospf_abr_prepare_aggregates (); TURNED OFF just for now */ + + /* For all NSSAs, Type-7s, translate to 5's, INSTALL/FLOOD, or + Aggregate as Type-7 */ + /* Install or Approve in Type-5 Global LSDB */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): process translates"); + + ospf_abr_process_nssa_translates (ospf); + + /* Translate/Send any "ranged" aggregates, and also 5-Install and + Approve */ + /* Scan Type-7's for aggregates, translate to Type-5's, + Install/Flood/Approve */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info("ospf_abr_nssa_task(): send NSSA aggregates"); + /* ospf_abr_send_nssa_aggregates (); TURNED OFF FOR NOW */ + + /* Send any NSSA defaults as Type-5 */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): announce nssa defaults"); + ospf_abr_announce_nssa_defaults (ospf); + + /* Flush any unapproved previous translates from Global Data Base */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): remove unapproved translates"); + ospf_abr_remove_unapproved_translates (ospf); + + ospf_abr_manage_discard_routes (ospf); /* same as normal...discard */ + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_abr_nssa_task(): Stop"); +} +#endif /* HAVE_NSSA */ + +/* This is the function taking care about ABR stuff, i.e. + summary-LSA origination and flooding. */ +void +ospf_abr_task (struct ospf *ospf) +{ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): Start"); + + if (ospf->new_table == NULL || ospf->new_rtrs == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): Routing tables are not yet ready"); + return; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): unapprove summaries"); + ospf_abr_unapprove_summaries (ospf); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): prepare aggregates"); + ospf_abr_prepare_aggregates (ospf); + + if (IS_OSPF_ABR (ospf)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): process network RT"); + ospf_abr_process_network_rt (ospf, ospf->new_table); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): process router RT"); + ospf_abr_process_router_rt (ospf, ospf->new_rtrs); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): announce aggregates"); + ospf_abr_announce_aggregates (ospf); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): announce stub defaults"); + ospf_abr_announce_stub_defaults (ospf); + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): remove unapproved summaries"); + ospf_abr_remove_unapproved_summaries (ospf); + + ospf_abr_manage_discard_routes (ospf); + +#ifdef HAVE_NSSA + ospf_abr_nssa_task (ospf); /* if nssa-abr, then scan Type-7 LSDB */ +#endif /* HAVE_NSSA */ + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_abr_task(): Stop"); +} + + +int +ospf_abr_task_timer (struct thread *thread) +{ + struct ospf *ospf = THREAD_ARG (thread); + + ospf->t_abr_task = 0; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Running ABR task on timer"); + + ospf_check_abr_status (ospf); + + ospf_abr_task (ospf); + + return 0; +} + +void +ospf_schedule_abr_task (struct ospf *ospf) +{ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Scheduling ABR task"); + + if (ospf->t_abr_task == NULL) + ospf->t_abr_task = thread_add_timer (master, ospf_abr_task_timer, + ospf, OSPF_ABR_TASK_DELAY); +} diff --git a/ospfd/ospf_abr.h b/ospfd/ospf_abr.h new file mode 100644 index 0000000..c025f51 --- /dev/null +++ b/ospfd/ospf_abr.h @@ -0,0 +1,84 @@ +/* + * OSPF ABR functions. + * Copyright (C) 1999 Alex Zinin + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ABR_H +#define _ZEBRA_OSPF_ABR_H + +#define OSPF_ABR_TASK_DELAY 7 + +#define OSPF_AREA_RANGE_ADVERTISE (1 << 0) +#define OSPF_AREA_RANGE_SUBSTITUTE (1 << 1) + +/* Area range. */ +struct ospf_area_range +{ + /* Area range address. */ + struct in_addr addr; + + /* Area range masklen. */ + u_char masklen; + + /* Flags. */ + u_char flags; + + /* Number of more specific prefixes. */ + int specifics; + + /* Addr and masklen to substitute. */ + struct in_addr subst_addr; + u_char subst_masklen; + + /* Range cost. */ + u_int32_t cost; + + /* Configured range cost. */ + u_int32_t cost_config; +#define OSPF_AREA_RANGE_COST_UNSPEC -1 +}; + +/* Prototypes. */ +struct ospf_area_range *ospf_area_range_lookup (struct ospf_area *, + struct prefix_ipv4 *); +struct ospf_area_range *ospf_some_area_range_match (struct prefix_ipv4 *); +struct ospf_area_range *ospf_area_range_lookup_next (struct ospf_area *, + struct in_addr *, int); +int ospf_area_range_set (struct ospf *, struct in_addr, struct prefix_ipv4 *, + int); +int ospf_area_range_cost_set (struct ospf *, struct in_addr, + struct prefix_ipv4 *, u_int32_t); +int ospf_area_range_unset (struct ospf *, struct in_addr, + struct prefix_ipv4 *); +int ospf_area_range_substitute_set (struct ospf *, struct in_addr, + struct prefix_ipv4 *, + struct prefix_ipv4 *); +int ospf_area_range_substitute_unset (struct ospf *, struct in_addr, + struct prefix_ipv4 *); +struct ospf_area_range *ospf_area_range_match_any (struct ospf *, + struct prefix_ipv4 *); +int ospf_area_range_active (struct ospf_area_range *); +int ospf_act_bb_connection (struct ospf *); + +void ospf_check_abr_status (struct ospf *); +void ospf_abr_task (struct ospf *); +void ospf_schedule_abr_task (struct ospf *); + +#endif /* _ZEBRA_OSPF_ABR_H */ diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c new file mode 100644 index 0000000..fda32ae --- /dev/null +++ b/ospfd/ospf_asbr.c @@ -0,0 +1,293 @@ +/* + * OSPF AS Boundary Router functions. + * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "vty.h" +#include "filter.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + + +/* Remove external route. */ +void +ospf_external_route_remove (struct ospf *ospf, struct prefix_ipv4 *p) +{ + struct route_node *rn; + struct ospf_route *or; + + rn = route_node_lookup (ospf->old_external_route, (struct prefix *) p); + if (rn) + if ((or = rn->info)) + { + zlog_info ("Route[%s/%d]: external path deleted", + inet_ntoa (p->prefix), p->prefixlen); + + /* Remove route from zebra. */ + if (or->type == OSPF_DESTINATION_NETWORK) + ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); + + ospf_route_free (or); + rn->info = NULL; + + route_unlock_node (rn); + route_unlock_node (rn); + return; + } + + zlog_info ("Route[%s/%d]: no such external path", + inet_ntoa (p->prefix), p->prefixlen); +} + +/* Lookup external route. */ +struct ospf_route * +ospf_external_route_lookup (struct ospf *ospf, + struct prefix_ipv4 *p) +{ + struct route_node *rn; + + rn = route_node_lookup (ospf->old_external_route, (struct prefix *) p); + if (rn) + { + route_unlock_node (rn); + if (rn->info) + return rn->info; + } + + zlog_warn ("Route[%s/%d]: lookup, no such prefix", + inet_ntoa (p->prefix), p->prefixlen); + + return NULL; +} + + +/* Add an External info for AS-external-LSA. */ +struct external_info * +ospf_external_info_new (u_char type) +{ + struct external_info *new; + + new = (struct external_info *) + XMALLOC (MTYPE_OSPF_EXTERNAL_INFO, sizeof (struct external_info)); + memset (new, 0, sizeof (struct external_info)); + new->type = type; + + ospf_reset_route_map_set_values (&new->route_map_set); + return new; +} + +void +ospf_external_info_free (struct external_info *ei) +{ + XFREE (MTYPE_OSPF_EXTERNAL_INFO, ei); +} + +void +ospf_reset_route_map_set_values (struct route_map_set_values *values) +{ + values->metric = -1; + values->metric_type = -1; +} + +int +ospf_route_map_set_compare (struct route_map_set_values *values1, + struct route_map_set_values *values2) +{ + return values1->metric == values2->metric && + values1->metric_type == values2->metric_type; +} + +/* Add an External info for AS-external-LSA. */ +struct external_info * +ospf_external_info_add (u_char type, struct prefix_ipv4 p, + unsigned int ifindex, struct in_addr nexthop) +{ + struct external_info *new; + struct route_node *rn; + + /* Initialize route table. */ + if (EXTERNAL_INFO (type) == NULL) + EXTERNAL_INFO (type) = route_table_init (); + + rn = route_node_get (EXTERNAL_INFO (type), (struct prefix *) &p); + /* If old info exists, -- discard new one or overwrite with new one? */ + if (rn) + if (rn->info) + { + route_unlock_node (rn); + zlog_warn ("Redistribute[%s]: %s/%d already exists, discard.", + LOOKUP (ospf_redistributed_proto, type), + inet_ntoa (p.prefix), p.prefixlen); + /* XFREE (MTYPE_OSPF_TMP, rn->info); */ + return rn->info; + } + + /* Create new External info instance. */ + new = ospf_external_info_new (type); + new->p = p; + new->ifindex = ifindex; + new->nexthop = nexthop; + new->tag = 0; + + rn->info = new; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("Redistribute[%s]: %s/%d external info created.", + LOOKUP (ospf_redistributed_proto, type), + inet_ntoa (p.prefix), p.prefixlen); + return new; +} + +void +ospf_external_info_delete (u_char type, struct prefix_ipv4 p) +{ + struct route_node *rn; + + rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) &p); + if (rn) + { + ospf_external_info_free (rn->info); + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + } +} + +struct external_info * +ospf_external_info_lookup (u_char type, struct prefix_ipv4 *p) +{ + struct route_node *rn; + rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) p); + if (rn) + { + route_unlock_node (rn); + if (rn->info) + return rn->info; + } + + return NULL; +} + +struct ospf_lsa * +ospf_external_info_find_lsa (struct ospf *ospf, + struct prefix_ipv4 *p) +{ + struct ospf_lsa *lsa; + struct as_external_lsa *al; + struct in_addr mask, id; + + lsa = ospf_lsdb_lookup_by_id (ospf->lsdb, OSPF_AS_EXTERNAL_LSA, + p->prefix, ospf->router_id); + + if (!lsa) + return NULL; + + al = (struct as_external_lsa *) lsa->data; + + masklen2ip (p->prefixlen, &mask); + + if (mask.s_addr != al->mask.s_addr) + { + id.s_addr = p->prefix.s_addr | (~mask.s_addr); + lsa = ospf_lsdb_lookup_by_id (ospf->lsdb, OSPF_AS_EXTERNAL_LSA, + id, ospf->router_id); + if (!lsa) + return NULL; + } + + return lsa; +} + + +/* Update ASBR status. */ +void +ospf_asbr_status_update (struct ospf *ospf, u_char status) +{ + zlog_info ("ASBR[Status:%d]: Update", status); + + /* ASBR on. */ + if (status) + { + /* Already ASBR. */ + if (IS_OSPF_ASBR (ospf)) + { + zlog_info ("ASBR[Status:%d]: Already ASBR", status); + return; + } + SET_FLAG (ospf->flags, OSPF_FLAG_ASBR); + } + else + { + /* Already non ASBR. */ + if (! IS_OSPF_ASBR (ospf)) + { + zlog_info ("ASBR[Status:%d]: Already non ASBR", status); + return; + } + UNSET_FLAG (ospf->flags, OSPF_FLAG_ASBR); + } + + /* Transition from/to status ASBR, schedule timer. */ + ospf_spf_calculate_schedule (ospf); + OSPF_TIMER_ON (ospf->t_router_lsa_update, + ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY); +} + +void +ospf_redistribute_withdraw (u_char type) +{ + struct ospf *ospf; + struct route_node *rn; + struct external_info *ei; + + ospf = ospf_lookup (); + + /* Delete external info for specified type. */ + if (EXTERNAL_INFO (type)) + for (rn = route_top (EXTERNAL_INFO (type)); rn; rn = route_next (rn)) + if ((ei = rn->info)) + if (ospf_external_info_find_lsa (ospf, &ei->p)) + { + if (is_prefix_default (&ei->p) && + ospf->default_originate != DEFAULT_ORIGINATE_NONE) + continue; + ospf_external_lsa_flush (ospf, type, &ei->p, ei->ifindex, ei->nexthop); + ospf_external_info_delete (type, ei->p); + } +} diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h new file mode 100644 index 0000000..ddfa9fa --- /dev/null +++ b/ospfd/ospf_asbr.h @@ -0,0 +1,76 @@ +/* + * OSPF AS Boundary Router functions. + * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ASBR_H +#define _ZEBRA_OSPF_ASBR_H + +struct route_map_set_values +{ + int32_t metric; + int32_t metric_type; +}; + +/* Redistributed external information. */ +struct external_info +{ + /* Type of source protocol. */ + u_char type; + + /* Prefix. */ + struct prefix_ipv4 p; + + /* Interface index. */ + unsigned int ifindex; + + /* Nexthop address. */ + struct in_addr nexthop; + + /* Additional Route tag. */ + u_int32_t tag; + + struct route_map_set_values route_map_set; +#define ROUTEMAP_METRIC(E) (E)->route_map_set.metric +#define ROUTEMAP_METRIC_TYPE(E) (E)->route_map_set.metric_type +}; + +#define OSPF_ASBR_CHECK_DELAY 30 + +void ospf_external_route_remove (struct ospf *, struct prefix_ipv4 *); +struct external_info *ospf_external_info_new (u_char); +void ospf_reset_route_map_set_values (struct route_map_set_values *); +int ospf_route_map_set_compare (struct route_map_set_values *, + struct route_map_set_values *); +struct external_info *ospf_external_info_add (u_char, struct prefix_ipv4, + unsigned int, struct in_addr); +void ospf_external_info_delete (u_char, struct prefix_ipv4); +struct external_info *ospf_external_info_lookup (u_char, struct prefix_ipv4 *); + +void ospf_asbr_status_update (struct ospf *, u_char); + +void ospf_redistribute_withdraw (u_char); +void ospf_asbr_check (); +void ospf_schedule_asbr_check (); +void ospf_asbr_route_install_lsa (struct ospf_lsa *); +struct ospf_lsa *ospf_external_info_find_lsa (struct ospf *, + struct prefix_ipv4 *p); + +#endif /* _ZEBRA_OSPF_ASBR_H */ diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c new file mode 100644 index 0000000..b3b54fa --- /dev/null +++ b/ospfd/ospf_ase.c @@ -0,0 +1,833 @@ +/* + * OSPF AS external route calculation. + * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "memory.h" +#include "hash.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "vty.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + +#define DEBUG + +struct ospf_route * +ospf_find_asbr_route (struct ospf *ospf, + struct route_table *rtrs, struct prefix_ipv4 *asbr) +{ + struct route_node *rn; + struct ospf_route *or, *best = NULL; + listnode node; + list chosen; + + /* Sanity check. */ + if (rtrs == NULL) + return NULL; + + rn = route_node_lookup (rtrs, (struct prefix *) asbr); + if (! rn) + return NULL; + + route_unlock_node (rn); + + chosen = list_new (); + + /* First try to find intra-area non-bb paths. */ + if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) + for (node = listhead ((list) rn->info); node; nextnode (node)) + if ((or = getdata (node)) != NULL) + if (or->cost < OSPF_LS_INFINITY) + if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id) && + or->path_type == OSPF_PATH_INTRA_AREA) + listnode_add (chosen, or); + + /* If none is found -- look through all. */ + if (listcount (chosen) == 0) + { + list_free (chosen); + chosen = rn->info; + } + + /* Now find the route with least cost. */ + for (node = listhead (chosen); node; nextnode (node)) + if ((or = getdata (node)) != NULL) + if (or->cost < OSPF_LS_INFINITY) + { + if (best == NULL) + best = or; + else if (best->cost > or->cost) + best = or; + else if (best->cost == or->cost && + IPV4_ADDR_CMP (&best->u.std.area_id, + &or->u.std.area_id) < 0) + best = or; + } + + if (chosen != rn->info) + list_delete (chosen); + + return best; +} + +struct ospf_route * +ospf_find_asbr_route_through_area (struct route_table *rtrs, + struct prefix_ipv4 *asbr, + struct ospf_area *area) +{ + struct route_node *rn; + + /* Sanity check. */ + if (rtrs == NULL) + return NULL; + + rn = route_node_lookup (rtrs, (struct prefix *) asbr); + + if (rn) + { + listnode node; + struct ospf_route *or; + + route_unlock_node (rn); + + for (node = listhead ((list) rn->info); node; nextnode (node)) + if ((or = getdata (node)) != NULL) + if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)) + return or; + } + + return NULL; +} + +void +ospf_ase_complete_direct_routes (struct ospf_route *ro, struct in_addr nexthop) +{ + listnode node; + struct ospf_path *op; + + for (node = listhead (ro->path); node; nextnode (node)) + if ((op = getdata (node)) != NULL) + if (op->nexthop.s_addr == 0) + op->nexthop.s_addr = nexthop.s_addr; +} + +int +ospf_ase_forward_address_check (struct ospf *ospf, struct in_addr fwd_addr) +{ + listnode ifn; + struct ospf_interface *oi; + + for (ifn = listhead (ospf->oiflist); ifn; nextnode (ifn)) + if ((oi = getdata (ifn)) != NULL) + if (if_is_up (oi->ifp)) + if (oi->type != OSPF_IFTYPE_VIRTUALLINK) + if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &fwd_addr)) + return 0; + + return 1; +} + +/* Calculate ASBR route. */ +struct ospf_route * +ospf_ase_calculate_asbr_route (struct ospf *ospf, + struct route_table *rt_network, + struct route_table *rt_router, + struct as_external_lsa *al) +{ + struct prefix_ipv4 asbr; + struct ospf_route *asbr_route; + struct route_node *rn; + + /* Find ASBR route from Router routing table. */ + asbr.family = AF_INET; + asbr.prefix = al->header.adv_router; + asbr.prefixlen = IPV4_MAX_BITLEN; + apply_mask_ipv4 (&asbr); + + asbr_route = ospf_find_asbr_route (ospf, rt_router, &asbr); + + if (asbr_route == NULL) + { + zlog_info ("ospf_ase_calculate(): Route to ASBR %s not found", + inet_ntoa (asbr.prefix)); + return NULL; + } + + if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) + { + zlog_info ("ospf_ase_calculate(): Originating router is not an ASBR"); + return NULL; + } + + if (al->e[0].fwd_addr.s_addr != 0) + { + zlog_info ("ospf_ase_calculate(): " + "Forwarding address is not 0.0.0.0."); + + if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr)) + { + zlog_info ("ospf_ase_calculate(): " + "Forwarding address is one of our addresses, Ignore."); + return NULL; + } + + zlog_info ("ospf_ase_calculate(): " + "Looking up in the Network Routing Table."); + + /* Looking up the path to the fwd_addr from Network route. */ + asbr.family = AF_INET; + asbr.prefix = al->e[0].fwd_addr; + asbr.prefixlen = IPV4_MAX_BITLEN; + + rn = route_node_match (rt_network, (struct prefix *) &asbr); + + if (rn == NULL) + { + zlog_info ("ospf_ase_calculate(): " + "Couldn't find a route to the forwarding address."); + return NULL; + } + + route_unlock_node (rn); + + if ((asbr_route = rn->info) == NULL) + { + zlog_info ("ospf_ase_calculate(): " + "Somehow OSPF route to ASBR is lost"); + return NULL; + } + } + + return asbr_route; +} + +struct ospf_route * +ospf_ase_calculate_new_route (struct ospf_lsa *lsa, + struct ospf_route *asbr_route, u_int32_t metric) +{ + struct as_external_lsa *al; + struct ospf_route *new; + + al = (struct as_external_lsa *) lsa->data; + + new = ospf_route_new (); + + /* Set redistributed type -- does make sense? */ + /* new->type = type; */ + new->id = al->header.id; + new->mask = al->mask; + + if (!IS_EXTERNAL_METRIC (al->e[0].tos)) + { + zlog_info ("Route[External]: type-1 created."); + new->path_type = OSPF_PATH_TYPE1_EXTERNAL; + new->cost = asbr_route->cost + metric; /* X + Y */ + } + else + { + zlog_info ("Route[External]: type-2 created."); + new->path_type = OSPF_PATH_TYPE2_EXTERNAL; + new->cost = asbr_route->cost; /* X */ + new->u.ext.type2_cost = metric; /* Y */ + } + + new->type = OSPF_DESTINATION_NETWORK; + new->path = list_new (); + new->u.ext.origin = lsa; + new->u.ext.tag = ntohl (al->e[0].route_tag); + new->u.ext.asbr = asbr_route; + + assert (new != asbr_route); + + return new; +} + +#define OSPF_ASE_CALC_INTERVAL 1 + +int +ospf_ase_calculate_route (struct ospf *ospf, struct ospf_lsa * lsa) +{ + u_int32_t metric; + struct as_external_lsa *al; + struct ospf_route *asbr_route; + struct prefix_ipv4 asbr, p; + struct route_node *rn; + struct ospf_route *new, *or; + int ret; + + assert (lsa); + al = (struct as_external_lsa *) lsa->data; + +#ifdef HAVE_NSSA + if (lsa->data->type == OSPF_AS_NSSA_LSA) + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_ase_calc(): Processing Type-7"); + + /* Stay away from any Local Translated Type-7 LSAs */ + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) + { + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_ase_calc(): Rejecting Local Xlt'd"); + return 0; + } +#endif /* HAVE_NSSA */ + + zlog_info ("Route[External]: Calculate AS-external-LSA to %s/%d", + inet_ntoa (al->header.id), ip_masklen (al->mask)); + /* (1) If the cost specified by the LSA is LSInfinity, or if the + LSA's LS age is equal to MaxAge, then examine the next LSA. */ + if ((metric = GET_METRIC (al->e[0].metric)) >= OSPF_LS_INFINITY) + { + zlog_info ("Route[External]: Metric is OSPF_LS_INFINITY"); + return 0; + } + if (IS_LSA_MAXAGE (lsa)) + { + zlog_info ("Route[External]: AS-external-LSA is MAXAGE"); + return 0; + } + + /* (2) If the LSA was originated by the calculating router itself, + examine the next LSA. */ + if (IS_LSA_SELF (lsa)) + { + zlog_info ("Route[External]: AS-external-LSA is self originated"); + return 0; + } + + /* (3) Call the destination described by the LSA N. N's address is + obtained by masking the LSA's Link State ID with the + network/subnet mask contained in the body of the LSA. Look + up the routing table entries (potentially one per attached + area) for the AS boundary router (ASBR) that originated the + LSA. If no entries exist for router ASBR (i.e., ASBR is + unreachable), do nothing with this LSA and consider the next + in the list. */ + + asbr.family = AF_INET; + asbr.prefix = al->header.adv_router; + asbr.prefixlen = IPV4_MAX_BITLEN; + apply_mask_ipv4 (&asbr); + + asbr_route = ospf_find_asbr_route (ospf, ospf->new_rtrs, &asbr); + if (asbr_route == NULL) + { + zlog_info ("Route[External]: Can't find originating ASBR route"); + return 0; + } + if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) + { + zlog_info ("Route[External]: Originating router is not an ASBR"); + return 0; + } + + /* Else, this LSA describes an AS external path to destination + N. Examine the forwarding address specified in the AS- + external-LSA. This indicates the IP address to which + packets for the destination should be forwarded. */ + + if (al->e[0].fwd_addr.s_addr == 0) + { + /* If the forwarding address is set to 0.0.0.0, packets should + be sent to the ASBR itself. Among the multiple routing table + entries for the ASBR, select the preferred entry as follows. + If RFC1583Compatibility is set to "disabled", prune the set + of routing table entries for the ASBR as described in + Section 16.4.1. In any case, among the remaining routing + table entries, select the routing table entry with the least + cost; when there are multiple least cost routing table + entries the entry whose associated area has the largest OSPF + Area ID (when considered as an unsigned 32-bit integer) is + chosen. */ + + /* asbr_route already contains the requested route */ + } + else + { + /* If the forwarding address is non-zero, look up the + forwarding address in the routing table.[24] The matching + routing table entry must specify an intra-area or inter-area + path; if no such path exists, do nothing with the LSA and + consider the next in the list. */ + if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr)) + { + zlog_info ("Route[External]: Forwarding address is our router address"); + return 0; + } + + asbr.family = AF_INET; + asbr.prefix = al->e[0].fwd_addr; + asbr.prefixlen = IPV4_MAX_BITLEN; + + rn = route_node_match (ospf->new_table, (struct prefix *) &asbr); + + if (rn == NULL || (asbr_route = rn->info) == NULL) + { + zlog_info ("Route[External]: Can't find route to forwarding address"); + if (rn) + route_unlock_node (rn); + return 0; + } + + route_unlock_node (rn); + } + + /* (4) Let X be the cost specified by the preferred routing table + entry for the ASBR/forwarding address, and Y the cost + specified in the LSA. X is in terms of the link state + metric, and Y is a type 1 or 2 external metric. */ + + + /* (5) Look up the routing table entry for the destination N. If + no entry exists for N, install the AS external path to N, + with next hop equal to the list of next hops to the + forwarding address, and advertising router equal to ASBR. + If the external metric type is 1, then the path-type is set + to type 1 external and the cost is equal to X+Y. If the + external metric type is 2, the path-type is set to type 2 + external, the link state component of the route's cost is X, + and the type 2 cost is Y. */ + new = ospf_ase_calculate_new_route (lsa, asbr_route, metric); + + /* (6) Compare the AS external path described by the LSA with the + existing paths in N's routing table entry, as follows. If + the new path is preferred, it replaces the present paths in + N's routing table entry. If the new path is of equal + preference, it is added to N's routing table entry's list of + paths. */ + + /* Set prefix. */ + p.family = AF_INET; + p.prefix = al->header.id; + p.prefixlen = ip_masklen (al->mask); + + /* if there is a Intra/Inter area route to the N + do not install external route */ + if ((rn = route_node_lookup (ospf->new_table, + (struct prefix *) &p)) != NULL + && (rn->info != NULL)) + { + if (new) + ospf_route_free (new); + return 0; + } + + /* Find a route to the same dest */ + /* If there is no route, create new one. */ + if ((rn = route_node_lookup (ospf->new_external_route, + (struct prefix *) &p)) == NULL + || (or = rn->info) == NULL) + { + zlog_info ("Route[External]: Adding a new route %s/%d", + inet_ntoa (p.prefix), p.prefixlen); + + ospf_route_add (ospf->new_external_route, &p, new, asbr_route); + + if (al->e[0].fwd_addr.s_addr) + ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr); + return 0; + } + else + { + /* (a) Intra-area and inter-area paths are always preferred + over AS external paths. + + (b) Type 1 external paths are always preferred over type 2 + external paths. When all paths are type 2 external + paths, the paths with the smallest advertised type 2 + metric are always preferred. */ + ret = ospf_route_cmp (ospf, new, or); + + /* (c) If the new AS external path is still indistinguishable + from the current paths in the N's routing table entry, + and RFC1583Compatibility is set to "disabled", select + the preferred paths based on the intra-AS paths to the + ASBR/forwarding addresses, as specified in Section + 16.4.1. + + (d) If the new AS external path is still indistinguishable + from the current paths in the N's routing table entry, + select the preferred path based on a least cost + comparison. Type 1 external paths are compared by + looking at the sum of the distance to the forwarding + address and the advertised type 1 metric (X+Y). Type 2 + external paths advertising equal type 2 metrics are + compared by looking at the distance to the forwarding + addresses. + */ + /* New route is better */ + if (ret < 0) + { + zlog_info ("Route[External]: New route is better"); + ospf_route_subst (rn, new, asbr_route); + if (al->e[0].fwd_addr.s_addr) + ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr); + or = new; + new = NULL; + } + /* Old route is better */ + else if (ret > 0) + { + zlog_info ("Route[External]: Old route is better"); + /* do nothing */ + } + /* Routes are equal */ + else + { + zlog_info ("Route[External]: Routes are equal"); + ospf_route_copy_nexthops (or, asbr_route->path); + if (al->e[0].fwd_addr.s_addr) + ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr); + } + } + /* Make sure setting newly calculated ASBR route.*/ + or->u.ext.asbr = asbr_route; + if (new) + ospf_route_free (new); + + lsa->route = or; + return 0; +} + +int +ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix, + struct ospf_route *newor) +{ + struct route_node *rn; + struct ospf_route *or; + struct ospf_path *op; + struct ospf_path *newop; + listnode n1; + listnode n2; + + if (! rt || ! prefix) + return 0; + + rn = route_node_lookup (rt, prefix); + if (! rn) + return 0; + + route_unlock_node (rn); + + or = rn->info; + if (or->path_type != newor->path_type) + return 0; + + switch (or->path_type) + { + case OSPF_PATH_TYPE1_EXTERNAL: + if (or->cost != newor->cost) + return 0; + break; + case OSPF_PATH_TYPE2_EXTERNAL: + if ((or->cost != newor->cost) || + (or->u.ext.type2_cost != newor->u.ext.type2_cost)) + return 0; + break; + default: + assert (0); + return 0; + } + + if (or->path->count != newor->path->count) + return 0; + + /* Check each path. */ + for (n1 = listhead (or->path), n2 = listhead (newor->path); + n1 && n2; nextnode (n1), nextnode (n2)) + { + op = getdata (n1); + newop = getdata (n2); + + if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop)) + return 0; + } + return 1; +} + +int +ospf_ase_compare_tables (struct route_table *new_external_route, + struct route_table *old_external_route) +{ + struct route_node *rn, *new_rn; + struct ospf_route *or; + + /* Remove deleted routes */ + for (rn = route_top (old_external_route); rn; rn = route_next (rn)) + if ((or = rn->info)) + { + if (! (new_rn = route_node_lookup (new_external_route, &rn->p))) + ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); + else + route_unlock_node (new_rn); + } + + + /* Install new routes */ + for (rn = route_top (new_external_route); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + if (! ospf_ase_route_match_same (old_external_route, &rn->p, or)) + ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or); + + return 0; +} + +int +ospf_ase_calculate_timer (struct thread *t) +{ + struct ospf *ospf; + struct ospf_lsa *lsa; + struct route_node *rn; +#ifdef HAVE_NSSA + listnode node; + struct ospf_area *area; +#endif /* HAVE_NSSA */ + + ospf = THREAD_ARG (t); + ospf->t_ase_calc = NULL; + + if (ospf->ase_calc) + { + ospf->ase_calc = 0; + + /* Calculate external route for each AS-external-LSA */ + LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) + ospf_ase_calculate_route (ospf, lsa); + +#ifdef HAVE_NSSA + /* This version simple adds to the table all NSSA areas */ + if (ospf->anyNSSA) + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_ase_calculate_timer(): looking at area %s", + inet_ntoa (area->area_id)); + + if (area->external_routing == OSPF_AREA_NSSA) + LSDB_LOOP (NSSA_LSDB (area), rn, lsa) + ospf_ase_calculate_route (ospf, lsa); + } +#endif /* HAVE_NSSA */ + + /* Compare old and new external routing table and install the + difference info zebra/kernel */ + ospf_ase_compare_tables (ospf->new_external_route, + ospf->old_external_route); + + /* Delete old external routing table */ + ospf_route_table_free (ospf->old_external_route); + ospf->old_external_route = ospf->new_external_route; + ospf->new_external_route = route_table_init (); + } + return 0; +} + +void +ospf_ase_calculate_schedule (struct ospf *ospf) +{ + if (ospf == NULL) + return; + + ospf->ase_calc = 1; +} + +void +ospf_ase_calculate_timer_add (struct ospf *ospf) +{ + if (ospf == NULL) + return; + + if (! ospf->t_ase_calc) + ospf->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer, + ospf, OSPF_ASE_CALC_INTERVAL); +} + +void +ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top) +{ + struct route_node *rn; + struct prefix_ipv4 p; + list lst; + struct as_external_lsa *al; + + al = (struct as_external_lsa *) lsa->data; + p.family = AF_INET; + p.prefix = lsa->data->id; + p.prefixlen = ip_masklen (al->mask); + apply_mask_ipv4 (&p); + + rn = route_node_get (top->external_lsas, (struct prefix *) &p); + if ((lst = rn->info) == NULL) + rn->info = lst = list_new(); + + /* We assume that if LSA is deleted from DB + is is also deleted from this RT */ + + listnode_add (lst, ospf_lsa_lock (lsa)); +} + +void +ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top) +{ + struct route_node *rn; + struct prefix_ipv4 p; + list lst; + struct as_external_lsa *al; + + al = (struct as_external_lsa *) lsa->data; + p.family = AF_INET; + p.prefix = lsa->data->id; + p.prefixlen = ip_masklen (al->mask); + apply_mask_ipv4 (&p); + + rn = route_node_get (top->external_lsas, (struct prefix *) &p); + lst = rn->info; + /* XXX lst can be NULL */ + if (lst) { + listnode_delete (lst, lsa); + ospf_lsa_unlock (lsa); + } +} + +void +ospf_ase_external_lsas_finish (struct route_table *rt) +{ + struct route_node *rn; + struct ospf_lsa *lsa; + list lst; + listnode node; + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((lst = rn->info) != NULL) + { + for (node = listhead (lst); node; node = nextnode (node)) + if ((lsa = getdata (node)) != NULL) + ospf_lsa_unlock (lsa); + list_delete (lst); + } + + route_table_finish (rt); +} + +void +ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa) +{ + list lsas; + listnode node; + struct route_node *rn, *rn2; + struct prefix_ipv4 p; + struct route_table *tmp_old; + struct as_external_lsa *al; + + al = (struct as_external_lsa *) lsa->data; + p.family = AF_INET; + p.prefix = lsa->data->id; + p.prefixlen = ip_masklen (al->mask); + apply_mask_ipv4 (&p); + + /* if new_table is NULL, there was no spf calculation, thus + incremental update is unneeded */ + if (!ospf->new_table) + return; + + /* If there is already an intra-area or inter-area route + to the destination, no recalculation is necessary + (internal routes take precedence). */ + + rn = route_node_lookup (ospf->new_table, (struct prefix *) &p); + if (rn && rn->info) + { + route_unlock_node (rn); + return; + } + + rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p); + assert (rn && rn->info); + lsas = rn->info; + + for (node = listhead (lsas); node; nextnode (node)) + if ((lsa = getdata (node)) != NULL) + ospf_ase_calculate_route (ospf, lsa); + + /* prepare temporary old routing table for compare */ + tmp_old = route_table_init (); + rn = route_node_lookup (ospf->old_external_route, (struct prefix *) &p); + if (rn && rn->info) + { + rn2 = route_node_get (tmp_old, (struct prefix *) &p); + rn2->info = rn->info; + } + + /* install changes to zebra */ + ospf_ase_compare_tables (ospf->new_external_route, tmp_old); + + /* update ospf->old_external_route table */ + if (rn && rn->info) + ospf_route_free ((struct ospf_route *) rn->info); + + rn2 = route_node_lookup (ospf->new_external_route, (struct prefix *) &p); + /* if new route exists, install it to ospf->old_external_route */ + if (rn2 && rn2->info) + { + if (!rn) + rn = route_node_get (ospf->old_external_route, (struct prefix *) &p); + rn->info = rn2->info; + } + else + { + /* remove route node from ospf->old_external_route */ + if (rn) + { + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + } + } + + if (rn2) + { + /* rn2->info is stored in route node of ospf->old_external_route */ + rn2->info = NULL; + route_unlock_node (rn2); + route_unlock_node (rn2); + } + + route_table_finish (tmp_old); +} diff --git a/ospfd/ospf_ase.h b/ospfd/ospf_ase.h new file mode 100644 index 0000000..d2fee1a --- /dev/null +++ b/ospfd/ospf_ase.h @@ -0,0 +1,42 @@ +/* + * OSPF AS External route calculation. + * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ASE_H +#define _ZEBRA_OSPF_ASE_H + + +struct ospf_route *ospf_find_asbr_route (struct ospf *, struct route_table *, + struct prefix_ipv4 *); +struct ospf_route *ospf_find_asbr_route_through_area(struct route_table *, + struct prefix_ipv4 *, + struct ospf_area *); + +int ospf_ase_calculate_route (struct ospf *, struct ospf_lsa *); +void ospf_ase_calculate_schedule (struct ospf *); +void ospf_ase_calculate_timer_add (struct ospf *); + +void ospf_ase_external_lsas_finish (struct route_table *); +void ospf_ase_incremental_update (struct ospf *, struct ospf_lsa *); +void ospf_ase_register_external_lsa (struct ospf_lsa *, struct ospf *); +void ospf_ase_unregister_external_lsa (struct ospf_lsa *, struct ospf *); + +#endif /* _ZEBRA_OSPF_ASE_H */ diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c new file mode 100644 index 0000000..38ec79e --- /dev/null +++ b/ospfd/ospf_dump.c @@ -0,0 +1,1673 @@ +/* + * OSPFd dump routine. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "thread.h" +#include "prefix.h" +#include "command.h" +#include "stream.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_network.h" + +struct message ospf_ism_state_msg[] = +{ + { ISM_DependUpon, "DependUpon" }, + { ISM_Down, "Down" }, + { ISM_Loopback, "Loopback" }, + { ISM_Waiting, "Waiting" }, + { ISM_PointToPoint, "Point-To-Point" }, + { ISM_DROther, "DROther" }, + { ISM_Backup, "Backup" }, + { ISM_DR, "DR" }, +}; +int ospf_ism_state_msg_max = OSPF_ISM_STATE_MAX; + +struct message ospf_nsm_state_msg[] = +{ + { NSM_DependUpon, "DependUpon" }, + { NSM_Down, "Down" }, + { NSM_Attempt, "Attempt" }, + { NSM_Init, "Init" }, + { NSM_TwoWay, "2-Way" }, + { NSM_ExStart, "ExStart" }, + { NSM_Exchange, "Exchange" }, + { NSM_Loading, "Loading" }, + { NSM_Full, "Full" }, +}; +int ospf_nsm_state_msg_max = OSPF_NSM_STATE_MAX; + +struct message ospf_lsa_type_msg[] = +{ + { OSPF_UNKNOWN_LSA, "unknown" }, + { OSPF_ROUTER_LSA, "router-LSA" }, + { OSPF_NETWORK_LSA, "network-LSA" }, + { OSPF_SUMMARY_LSA, "summary-LSA" }, + { OSPF_ASBR_SUMMARY_LSA, "summary-LSA" }, + { OSPF_AS_EXTERNAL_LSA, "AS-external-LSA" }, + { OSPF_GROUP_MEMBER_LSA, "GROUP MEMBER LSA" }, + { OSPF_AS_NSSA_LSA, "NSSA-LSA" }, + { 8, "Type-8 LSA" }, + { OSPF_OPAQUE_LINK_LSA, "Link-Local Opaque-LSA" }, + { OSPF_OPAQUE_AREA_LSA, "Area-Local Opaque-LSA" }, + { OSPF_OPAQUE_AS_LSA, "AS-external Opaque-LSA" }, +}; +int ospf_lsa_type_msg_max = OSPF_MAX_LSA; + +struct message ospf_link_state_id_type_msg[] = +{ + { OSPF_UNKNOWN_LSA, "(unknown)" }, + { OSPF_ROUTER_LSA, "" }, + { OSPF_NETWORK_LSA, "(address of Designated Router)" }, + { OSPF_SUMMARY_LSA, "(summary Network Number)" }, + { OSPF_ASBR_SUMMARY_LSA, "(AS Boundary Router address)" }, + { OSPF_AS_EXTERNAL_LSA, "(External Network Number)" }, + { OSPF_GROUP_MEMBER_LSA, "(Group membership information)" }, + { OSPF_AS_NSSA_LSA, "(External Network Number for NSSA)" }, + { 8, "(Type-8 LSID)" }, + { OSPF_OPAQUE_LINK_LSA, "(Link-Local Opaque-Type/ID)" }, + { OSPF_OPAQUE_AREA_LSA, "(Area-Local Opaque-Type/ID)" }, + { OSPF_OPAQUE_AS_LSA, "(AS-external Opaque-Type/ID)" }, +}; +int ospf_link_state_id_type_msg_max = OSPF_MAX_LSA; + +struct message ospf_redistributed_proto[] = +{ + { ZEBRA_ROUTE_SYSTEM, "System" }, + { ZEBRA_ROUTE_KERNEL, "Kernel" }, + { ZEBRA_ROUTE_CONNECT, "Connected" }, + { ZEBRA_ROUTE_STATIC, "Static" }, + { ZEBRA_ROUTE_RIP, "RIP" }, + { ZEBRA_ROUTE_RIPNG, "RIPng" }, + { ZEBRA_ROUTE_OSPF, "OSPF" }, + { ZEBRA_ROUTE_OSPF6, "OSPFv3" }, + { ZEBRA_ROUTE_BGP, "BGP" }, + { ZEBRA_ROUTE_MAX, "Default" }, +}; +int ospf_redistributed_proto_max = ZEBRA_ROUTE_MAX + 1; + +struct message ospf_network_type_msg[] = +{ + { OSPF_IFTYPE_NONE, "NONE" }, + { OSPF_IFTYPE_POINTOPOINT, "Point-to-Point" }, + { OSPF_IFTYPE_BROADCAST, "Broadcast" }, + { OSPF_IFTYPE_NBMA, "NBMA" }, + { OSPF_IFTYPE_POINTOMULTIPOINT, "Point-to-MultiPoint" }, + { OSPF_IFTYPE_VIRTUALLINK, "Virtual-Link" }, +}; +int ospf_network_type_msg_max = OSPF_IFTYPE_MAX; + +/* Configuration debug option variables. */ +unsigned long conf_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; +unsigned long conf_debug_ospf_event = 0; +unsigned long conf_debug_ospf_ism = 0; +unsigned long conf_debug_ospf_nsm = 0; +unsigned long conf_debug_ospf_lsa = 0; +unsigned long conf_debug_ospf_zebra = 0; +unsigned long conf_debug_ospf_nssa = 0; + +/* Enable debug option variables -- valid only session. */ +unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; +unsigned long term_debug_ospf_event = 0; +unsigned long term_debug_ospf_ism = 0; +unsigned long term_debug_ospf_nsm = 0; +unsigned long term_debug_ospf_lsa = 0; +unsigned long term_debug_ospf_zebra = 0; +unsigned long term_debug_ospf_nssa = 0; + + +#define OSPF_AREA_STRING_MAXLEN 16 +char * +ospf_area_name_string (struct ospf_area *area) +{ + static char buf[OSPF_AREA_STRING_MAXLEN] = ""; + u_int32_t area_id; + + if (!area) + return "-"; + + area_id = ntohl (area->area_id.s_addr); + snprintf (buf, OSPF_AREA_STRING_MAXLEN, "%d.%d.%d.%d", + (area_id >> 24) & 0xff, (area_id >> 16) & 0xff, + (area_id >> 8) & 0xff, area_id & 0xff); + return buf; +} + +#define OSPF_AREA_DESC_STRING_MAXLEN 23 +char * +ospf_area_desc_string (struct ospf_area *area) +{ + static char buf[OSPF_AREA_DESC_STRING_MAXLEN] = ""; + u_char type; + + if (!area) + return "(incomplete)"; + + type = area->external_routing; + switch (type) + { + case OSPF_AREA_NSSA: + snprintf (buf, OSPF_AREA_DESC_STRING_MAXLEN, "%s [NSSA]", + ospf_area_name_string (area)); + break; + case OSPF_AREA_STUB: + snprintf (buf, OSPF_AREA_DESC_STRING_MAXLEN, "%s [Stub]", + ospf_area_name_string (area)); + break; + default: + return ospf_area_name_string (area); + break; + } + + return buf; +} + +#define OSPF_IF_STRING_MAXLEN 40 +char * +ospf_if_name_string (struct ospf_interface *oi) +{ + static char buf[OSPF_IF_STRING_MAXLEN] = ""; + u_int32_t ifaddr; + + if (!oi) + return "inactive"; + + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + return oi->ifp->name; + + ifaddr = ntohl (oi->address->u.prefix4.s_addr); + snprintf (buf, OSPF_IF_STRING_MAXLEN, + "%s:%d.%d.%d.%d", oi->ifp->name, + (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, + (ifaddr >> 8) & 0xff, ifaddr & 0xff); + return buf; +} + + +void +ospf_nbr_state_message (struct ospf_neighbor *nbr, char *buf, size_t size) +{ + int state; + struct ospf_interface *oi = nbr->oi; + + if (IPV4_ADDR_SAME (&DR (oi), &nbr->address.u.prefix4)) + state = ISM_DR; + else if (IPV4_ADDR_SAME (&BDR (oi), &nbr->address.u.prefix4)) + state = ISM_Backup; + else + state = ISM_DROther; + + memset (buf, 0, size); + + snprintf (buf, size, "%s/%s", + LOOKUP (ospf_nsm_state_msg, nbr->state), + LOOKUP (ospf_ism_state_msg, state)); +} + +char * +ospf_timer_dump (struct thread *t, char *buf, size_t size) +{ + struct timeval now; + unsigned long h, m, s; + + if (!t) + return "inactive"; + + h = m = s = 0; + memset (buf, 0, size); + + gettimeofday (&now, NULL); + + s = t->u.sands.tv_sec - now.tv_sec; + if (s >= 3600) + { + h = s / 3600; + s -= h * 3600; + } + + if (s >= 60) + { + m = s / 60; + s -= m * 60; + } + + snprintf (buf, size, "%02ld:%02ld:%02ld", h, m, s); + + return buf; +} + +#define OSPF_OPTION_STR_MAXLEN 24 + +char * +ospf_options_dump (u_char options) +{ + static char buf[OSPF_OPTION_STR_MAXLEN]; + + snprintf (buf, OSPF_OPTION_STR_MAXLEN, "*|%s|%s|%s|%s|%s|%s|*", + (options & OSPF_OPTION_O) ? "O" : "-", + (options & OSPF_OPTION_DC) ? "DC" : "-", + (options & OSPF_OPTION_EA) ? "EA" : "-", + (options & OSPF_OPTION_NP) ? "N/P" : "-", + (options & OSPF_OPTION_MC) ? "MC" : "-", + (options & OSPF_OPTION_E) ? "E" : "-"); + + return buf; +} + +void +ospf_packet_hello_dump (struct stream *s, u_int16_t length) +{ + struct ospf_hello *hello; + int i; + + hello = (struct ospf_hello *) STREAM_PNT (s); + + zlog_info ("Hello"); + zlog_info (" NetworkMask %s", inet_ntoa (hello->network_mask)); + zlog_info (" HelloInterval %d", ntohs (hello->hello_interval)); + zlog_info (" Options %d (%s)", hello->options, + ospf_options_dump (hello->options)); + zlog_info (" RtrPriority %d", hello->priority); + zlog_info (" RtrDeadInterval %ld", (u_long)ntohl (hello->dead_interval)); + zlog_info (" DRouter %s", inet_ntoa (hello->d_router)); + zlog_info (" BDRouter %s", inet_ntoa (hello->bd_router)); + + length -= OSPF_HEADER_SIZE + OSPF_HELLO_MIN_SIZE; + zlog_info (" # Neighbors %d", length / 4); + for (i = 0; length > 0; i++, length -= sizeof (struct in_addr)) + zlog_info (" Neighbor %s", inet_ntoa (hello->neighbors[i])); +} + +char * +ospf_dd_flags_dump (u_char flags, char *buf, size_t size) +{ + memset (buf, 0, size); + + snprintf (buf, size, "%s|%s|%s", + (flags & OSPF_DD_FLAG_I) ? "I" : "-", + (flags & OSPF_DD_FLAG_M) ? "M" : "-", + (flags & OSPF_DD_FLAG_MS) ? "MS" : "-"); + + return buf; +} + +void +ospf_lsa_header_dump (struct lsa_header *lsah) +{ + zlog_info (" LSA Header"); + zlog_info (" LS age %d", ntohs (lsah->ls_age)); + zlog_info (" Options %d (%s)", lsah->options, + ospf_options_dump (lsah->options)); + zlog_info (" LS type %d (%s)", lsah->type, + LOOKUP (ospf_lsa_type_msg, lsah->type)); + zlog_info (" Link State ID %s", inet_ntoa (lsah->id)); + zlog_info (" Advertising Router %s", inet_ntoa (lsah->adv_router)); + zlog_info (" LS sequence number 0x%lx", (u_long)ntohl (lsah->ls_seqnum)); + zlog_info (" LS checksum 0x%x", ntohs (lsah->checksum)); + zlog_info (" length %d", ntohs (lsah->length)); +} + +char * +ospf_router_lsa_flags_dump (u_char flags, char *buf, size_t size) +{ + memset (buf, 0, size); + + snprintf (buf, size, "%s|%s|%s", + (flags & ROUTER_LSA_VIRTUAL) ? "V" : "-", + (flags & ROUTER_LSA_EXTERNAL) ? "E" : "-", + (flags & ROUTER_LSA_BORDER) ? "B" : "-"); + + return buf; +} + +void +ospf_router_lsa_dump (struct stream *s, u_int16_t length) +{ + char buf[BUFSIZ]; + struct router_lsa *rl; + int i, len; + + rl = (struct router_lsa *) STREAM_PNT (s); + + zlog_info (" Router-LSA"); + zlog_info (" flags %s", + ospf_router_lsa_flags_dump (rl->flags, buf, BUFSIZ)); + zlog_info (" # links %d", ntohs (rl->links)); + + len = ntohs (rl->header.length) - OSPF_LSA_HEADER_SIZE - 4; + for (i = 0; len > 0; i++) + { + zlog_info (" Link ID %s", inet_ntoa (rl->link[i].link_id)); + zlog_info (" Link Data %s", inet_ntoa (rl->link[i].link_data)); + zlog_info (" Type %d", (u_char) rl->link[i].type); + zlog_info (" TOS %d", (u_char) rl->link[i].tos); + zlog_info (" metric %d", ntohs (rl->link[i].metric)); + + len -= 12; + } +} + +void +ospf_network_lsa_dump (struct stream *s, u_int16_t length) +{ + struct network_lsa *nl; + int i, cnt; + + nl = (struct network_lsa *) STREAM_PNT (s); + cnt = (ntohs (nl->header.length) - (OSPF_LSA_HEADER_SIZE + 4)) / 4; + + zlog_info (" Network-LSA"); + /* + zlog_info ("LSA total size %d", ntohs (nl->header.length)); + zlog_info ("Network-LSA size %d", + ntohs (nl->header.length) - OSPF_LSA_HEADER_SIZE); + */ + zlog_info (" Network Mask %s", inet_ntoa (nl->mask)); + zlog_info (" # Attached Routers %d", cnt); + for (i = 0; i < cnt; i++) + zlog_info (" Attached Router %s", inet_ntoa (nl->routers[i])); +} + +void +ospf_summary_lsa_dump (struct stream *s, u_int16_t length) +{ + struct summary_lsa *sl; + int size; + int i; + + sl = (struct summary_lsa *) STREAM_PNT (s); + + zlog_info (" Summary-LSA"); + zlog_info (" Network Mask %s", inet_ntoa (sl->mask)); + + size = ntohs (sl->header.length) - OSPF_LSA_HEADER_SIZE - 4; + for (i = 0; size > 0; size -= 4, i++) + zlog_info (" TOS=%d metric %d", sl->tos, + GET_METRIC (sl->metric)); +} + +void +ospf_as_external_lsa_dump (struct stream *s, u_int16_t length) +{ + struct as_external_lsa *al; + int size; + int i; + + al = (struct as_external_lsa *) STREAM_PNT (s); + + zlog_info (" AS-external-LSA"); + zlog_info (" Network Mask %s", inet_ntoa (al->mask)); + + size = ntohs (al->header.length) - OSPF_LSA_HEADER_SIZE -4; + for (i = 0; size > 0; size -= 12, i++) + { + zlog_info (" bit %s TOS=%d metric %d", + IS_EXTERNAL_METRIC (al->e[i].tos) ? "E" : "-", + al->e[i].tos & 0x7f, GET_METRIC (al->e[i].metric)); + zlog_info (" Forwarding address %s", inet_ntoa (al->e[i].fwd_addr)); + zlog_info (" External Route Tag %d", al->e[i].route_tag); + } +} + +void +ospf_lsa_header_list_dump (struct stream *s, u_int16_t length) +{ + struct lsa_header *lsa; + + zlog_info (" # LSA Headers %d", length / OSPF_LSA_HEADER_SIZE); + + /* LSA Headers. */ + while (length > 0) + { + lsa = (struct lsa_header *) STREAM_PNT (s); + ospf_lsa_header_dump (lsa); + + stream_forward (s, OSPF_LSA_HEADER_SIZE); + length -= OSPF_LSA_HEADER_SIZE; + } +} + +void +ospf_packet_db_desc_dump (struct stream *s, u_int16_t length) +{ + struct ospf_db_desc *dd; + char dd_flags[8]; + + u_int32_t gp; + + gp = stream_get_getp (s); + dd = (struct ospf_db_desc *) STREAM_PNT (s); + + zlog_info ("Database Description"); + zlog_info (" Interface MTU %d", ntohs (dd->mtu)); + zlog_info (" Options %d (%s)", dd->options, + ospf_options_dump (dd->options)); + zlog_info (" Flags %d (%s)", dd->flags, + ospf_dd_flags_dump (dd->flags, dd_flags, sizeof dd_flags)); + zlog_info (" Sequence Number 0x%08lx", (u_long)ntohl (dd->dd_seqnum)); + + length -= OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE; + + stream_forward (s, OSPF_DB_DESC_MIN_SIZE); + + ospf_lsa_header_list_dump (s, length); + + stream_set_getp (s, gp); +} + +void +ospf_packet_ls_req_dump (struct stream *s, u_int16_t length) +{ + u_int32_t sp; + u_int32_t ls_type; + struct in_addr ls_id; + struct in_addr adv_router; + + sp = stream_get_getp (s); + + length -= OSPF_HEADER_SIZE; + + zlog_info ("Link State Request"); + zlog_info (" # Requests %d", length / 12); + + for (; length > 0; length -= 12) + { + ls_type = stream_getl (s); + ls_id.s_addr = stream_get_ipv4 (s); + adv_router.s_addr = stream_get_ipv4 (s); + + zlog_info (" LS type %d", ls_type); + zlog_info (" Link State ID %s", inet_ntoa (ls_id)); + zlog_info (" Advertising Router %s", + inet_ntoa (adv_router)); + } + + stream_set_getp (s, sp); +} + +void +ospf_packet_ls_upd_dump (struct stream *s, u_int16_t length) +{ + u_int32_t sp; + struct lsa_header *lsa; + int lsa_len; + u_int32_t count; + + length -= OSPF_HEADER_SIZE; + + sp = stream_get_getp (s); + + count = stream_getl (s); + length -= 4; + + zlog_info ("Link State Update"); + zlog_info (" # LSAs %d", count); + + while (length > 0 && count > 0) + { + if (length < OSPF_HEADER_SIZE || length % 4 != 0) + { + zlog_info (" Remaining %d bytes; Incorrect length.", length); + break; + } + + lsa = (struct lsa_header *) STREAM_PNT (s); + lsa_len = ntohs (lsa->length); + ospf_lsa_header_dump (lsa); + + switch (lsa->type) + { + case OSPF_ROUTER_LSA: + ospf_router_lsa_dump (s, length); + break; + case OSPF_NETWORK_LSA: + ospf_network_lsa_dump (s, length); + break; + case OSPF_SUMMARY_LSA: + case OSPF_ASBR_SUMMARY_LSA: + ospf_summary_lsa_dump (s, length); + break; + case OSPF_AS_EXTERNAL_LSA: + ospf_as_external_lsa_dump (s, length); + break; +#ifdef HAVE_NSSA + case OSPF_AS_NSSA_LSA: + /* XXX */ + break; +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + ospf_opaque_lsa_dump (s, length); + break; +#endif /* HAVE_OPAQUE_LSA */ + default: + break; + } + + stream_forward (s, lsa_len); + length -= lsa_len; + count--; + } + + stream_set_getp (s, sp); +} + +void +ospf_packet_ls_ack_dump (struct stream *s, u_int16_t length) +{ + u_int32_t sp; + + length -= OSPF_HEADER_SIZE; + sp = stream_get_getp (s); + + zlog_info ("Link State Acknowledgment"); + ospf_lsa_header_list_dump (s, length); + + stream_set_getp (s, sp); +} + +void +ospf_ip_header_dump (struct stream *s) +{ + u_int16_t length; + struct ip *iph; + + iph = (struct ip *) STREAM_PNT (s); + +#ifdef GNU_LINUX + length = ntohs (iph->ip_len); +#else /* GNU_LINUX */ + length = iph->ip_len; +#endif /* GNU_LINUX */ + + /* IP Header dump. */ + zlog_info ("ip_v %d", iph->ip_v); + zlog_info ("ip_hl %d", iph->ip_hl); + zlog_info ("ip_tos %d", iph->ip_tos); + zlog_info ("ip_len %d", length); + zlog_info ("ip_id %u", (u_int32_t) iph->ip_id); + zlog_info ("ip_off %u", (u_int32_t) iph->ip_off); + zlog_info ("ip_ttl %d", iph->ip_ttl); + zlog_info ("ip_p %d", iph->ip_p); + /* There is a report that Linux 2.0.37 does not have ip_sum. But + I'm not sure. Temporary commented out by kunihiro. */ + /* zlog_info ("ip_sum 0x%x", (u_int32_t) ntohs (iph->ip_sum)); */ + zlog_info ("ip_src %s", inet_ntoa (iph->ip_src)); + zlog_info ("ip_dst %s", inet_ntoa (iph->ip_dst)); +} + +void +ospf_header_dump (struct ospf_header *ospfh) +{ + char buf[9]; + + zlog_info ("Header"); + zlog_info (" Version %d", ospfh->version); + zlog_info (" Type %d (%s)", ospfh->type, + ospf_packet_type_str[ospfh->type]); + zlog_info (" Packet Len %d", ntohs (ospfh->length)); + zlog_info (" Router ID %s", inet_ntoa (ospfh->router_id)); + zlog_info (" Area ID %s", inet_ntoa (ospfh->area_id)); + zlog_info (" Checksum 0x%x", ntohs (ospfh->checksum)); + zlog_info (" AuType %d", ntohs (ospfh->auth_type)); + + switch (ntohs (ospfh->auth_type)) + { + case OSPF_AUTH_NULL: + break; + case OSPF_AUTH_SIMPLE: + memset (buf, 0, 9); + strncpy (buf, ospfh->u.auth_data, 8); + zlog_info (" Simple Password %s", buf); + break; + case OSPF_AUTH_CRYPTOGRAPHIC: + zlog_info (" Cryptographic Authentication"); + zlog_info (" Key ID %d", ospfh->u.crypt.key_id); + zlog_info (" Auth Data Len %d", ospfh->u.crypt.auth_data_len); + zlog_info (" Sequence number %ld", + (u_long)ntohl (ospfh->u.crypt.crypt_seqnum)); + break; + default: + zlog_info ("* This is not supported authentication type"); + break; + } + +} + +void +ospf_packet_dump (struct stream *s) +{ + struct ospf_header *ospfh; + unsigned long gp; + + /* Preserve pointer. */ + gp = stream_get_getp (s); + + /* OSPF Header dump. */ + ospfh = (struct ospf_header *) STREAM_PNT (s); + + /* Until detail flag is set, return. */ + if (!(term_debug_ospf_packet[ospfh->type - 1] & OSPF_DEBUG_DETAIL)) + return; + + /* Show OSPF header detail. */ + ospf_header_dump (ospfh); + stream_forward (s, OSPF_HEADER_SIZE); + + switch (ospfh->type) + { + case OSPF_MSG_HELLO: + ospf_packet_hello_dump (s, ntohs (ospfh->length)); + break; + case OSPF_MSG_DB_DESC: + ospf_packet_db_desc_dump (s, ntohs (ospfh->length)); + break; + case OSPF_MSG_LS_REQ: + ospf_packet_ls_req_dump (s, ntohs (ospfh->length)); + break; + case OSPF_MSG_LS_UPD: + ospf_packet_ls_upd_dump (s, ntohs (ospfh->length)); + break; + case OSPF_MSG_LS_ACK: + ospf_packet_ls_ack_dump (s, ntohs (ospfh->length)); + break; + default: + break; + } + + stream_set_getp (s, gp); +} + + +/* + [no] debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) + [send|recv [detail]] +*/ +DEFUN (debug_ospf_packet, + debug_ospf_packet_all_cmd, + "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", + DEBUG_STR + OSPF_STR + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n") +{ + int type = 0; + int flag = 0; + int i; + + assert (argc > 0); + + /* Check packet type. */ + if (strncmp (argv[0], "h", 1) == 0) + type = OSPF_DEBUG_HELLO; + else if (strncmp (argv[0], "d", 1) == 0) + type = OSPF_DEBUG_DB_DESC; + else if (strncmp (argv[0], "ls-r", 4) == 0) + type = OSPF_DEBUG_LS_REQ; + else if (strncmp (argv[0], "ls-u", 4) == 0) + type = OSPF_DEBUG_LS_UPD; + else if (strncmp (argv[0], "ls-a", 4) == 0) + type = OSPF_DEBUG_LS_ACK; + else if (strncmp (argv[0], "a", 1) == 0) + type = OSPF_DEBUG_ALL; + + /* Default, both send and recv. */ + if (argc == 1) + flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV; + + /* send or recv. */ + if (argc >= 2) + { + if (strncmp (argv[1], "s", 1) == 0) + flag = OSPF_DEBUG_SEND; + else if (strncmp (argv[1], "r", 1) == 0) + flag = OSPF_DEBUG_RECV; + else if (strncmp (argv[1], "d", 1) == 0) + flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL; + } + + /* detail. */ + if (argc == 3) + if (strncmp (argv[2], "d", 1) == 0) + flag |= OSPF_DEBUG_DETAIL; + + for (i = 0; i < 5; i++) + if (type & (0x01 << i)) + { + if (vty->node == CONFIG_NODE) + DEBUG_PACKET_ON (i, flag); + else + TERM_DEBUG_PACKET_ON (i, flag); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_packet, + debug_ospf_packet_send_recv_cmd, + "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail information\n"); + +ALIAS (debug_ospf_packet, + debug_ospf_packet_send_recv_detail_cmd, + "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail Information\n"); + + +DEFUN (no_debug_ospf_packet, + no_debug_ospf_packet_all_cmd, + "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n") +{ + int type = 0; + int flag = 0; + int i; + + assert (argc > 0); + + /* Check packet type. */ + if (strncmp (argv[0], "h", 1) == 0) + type = OSPF_DEBUG_HELLO; + else if (strncmp (argv[0], "d", 1) == 0) + type = OSPF_DEBUG_DB_DESC; + else if (strncmp (argv[0], "ls-r", 4) == 0) + type = OSPF_DEBUG_LS_REQ; + else if (strncmp (argv[0], "ls-u", 4) == 0) + type = OSPF_DEBUG_LS_UPD; + else if (strncmp (argv[0], "ls-a", 4) == 0) + type = OSPF_DEBUG_LS_ACK; + else if (strncmp (argv[0], "a", 1) == 0) + type = OSPF_DEBUG_ALL; + + /* Default, both send and recv. */ + if (argc == 1) + flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL ; + + /* send or recv. */ + if (argc == 2) + { + if (strncmp (argv[1], "s", 1) == 0) + flag = OSPF_DEBUG_SEND | OSPF_DEBUG_DETAIL; + else if (strncmp (argv[1], "r", 1) == 0) + flag = OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL; + else if (strncmp (argv[1], "d", 1) == 0) + flag = OSPF_DEBUG_DETAIL; + } + + /* detail. */ + if (argc == 3) + if (strncmp (argv[2], "d", 1) == 0) + flag = OSPF_DEBUG_DETAIL; + + for (i = 0; i < 5; i++) + if (type & (0x01 << i)) + { + if (vty->node == CONFIG_NODE) + DEBUG_PACKET_OFF (i, flag); + else + TERM_DEBUG_PACKET_OFF (i, flag); + } + +#ifdef DEBUG + for (i = 0; i < 5; i++) + zlog_info ("flag[%d] = %d", i, ospf_debug_packet[i]); +#endif /* DEBUG */ + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_packet, + no_debug_ospf_packet_send_recv_cmd, + "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", + NO_STR + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail Information\n"); + +ALIAS (no_debug_ospf_packet, + no_debug_ospf_packet_send_recv_detail_cmd, + "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", + NO_STR + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail Information\n"); + + +DEFUN (debug_ospf_ism, + debug_ospf_ism_cmd, + "debug ospf ism", + DEBUG_STR + OSPF_STR + "OSPF Interface State Machine\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_ON (ism, ISM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + DEBUG_ON (ism, ISM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + DEBUG_ON (ism, ISM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + DEBUG_ON (ism, ISM_TIMERS); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_ON (ism, ISM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + TERM_DEBUG_ON (ism, ISM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + TERM_DEBUG_ON (ism, ISM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + TERM_DEBUG_ON (ism, ISM_TIMERS); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_ism, + debug_ospf_ism_sub_cmd, + "debug ospf ism (status|events|timers)", + DEBUG_STR + OSPF_STR + "OSPF Interface State Machine\n" + "ISM Status Information\n" + "ISM Event Information\n" + "ISM TImer Information\n"); + +DEFUN (no_debug_ospf_ism, + no_debug_ospf_ism_cmd, + "no debug ospf ism", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Interface State Machine") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_OFF (ism, ISM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + DEBUG_OFF (ism, ISM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + DEBUG_OFF (ism, ISM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + DEBUG_OFF (ism, ISM_TIMERS); + } + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_OFF (ism, ISM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + TERM_DEBUG_OFF (ism, ISM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + TERM_DEBUG_OFF (ism, ISM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + TERM_DEBUG_OFF (ism, ISM_TIMERS); + } + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_ism, + no_debug_ospf_ism_sub_cmd, + "no debug ospf ism (status|events|timers)", + NO_STR + "Debugging functions\n" + "OSPF information\n" + "OSPF Interface State Machine\n" + "ISM Status Information\n" + "ISM Event Information\n" + "ISM Timer Information\n"); + + +DEFUN (debug_ospf_nsm, + debug_ospf_nsm_cmd, + "debug ospf nsm", + DEBUG_STR + OSPF_STR + "OSPF Neighbor State Machine\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_ON (nsm, NSM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + DEBUG_ON (nsm, NSM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + DEBUG_ON (nsm, NSM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + DEBUG_ON (nsm, NSM_TIMERS); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_ON (nsm, NSM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + TERM_DEBUG_ON (nsm, NSM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + TERM_DEBUG_ON (nsm, NSM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + TERM_DEBUG_ON (nsm, NSM_TIMERS); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_nsm, + debug_ospf_nsm_sub_cmd, + "debug ospf nsm (status|events|timers)", + DEBUG_STR + OSPF_STR + "OSPF Neighbor State Machine\n" + "NSM Status Information\n" + "NSM Event Information\n" + "NSM Timer Information\n"); + +DEFUN (no_debug_ospf_nsm, + no_debug_ospf_nsm_cmd, + "no debug ospf nsm", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Neighbor State Machine") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_OFF (nsm, NSM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + DEBUG_OFF (nsm, NSM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + DEBUG_OFF (nsm, NSM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + DEBUG_OFF (nsm, NSM_TIMERS); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_OFF (nsm, NSM); + else if (argc == 1) + { + if (strncmp (argv[0], "s", 1) == 0) + TERM_DEBUG_OFF (nsm, NSM_STATUS); + else if (strncmp (argv[0], "e", 1) == 0) + TERM_DEBUG_OFF (nsm, NSM_EVENTS); + else if (strncmp (argv[0], "t", 1) == 0) + TERM_DEBUG_OFF (nsm, NSM_TIMERS); + } + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_nsm, + no_debug_ospf_nsm_sub_cmd, + "no debug ospf nsm (status|events|timers)", + NO_STR + "Debugging functions\n" + "OSPF information\n" + "OSPF Interface State Machine\n" + "NSM Status Information\n" + "NSM Event Information\n" + "NSM Timer Information\n"); + + +DEFUN (debug_ospf_lsa, + debug_ospf_lsa_cmd, + "debug ospf lsa", + DEBUG_STR + OSPF_STR + "OSPF Link State Advertisement\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_ON (lsa, LSA); + else if (argc == 1) + { + if (strncmp (argv[0], "g", 1) == 0) + DEBUG_ON (lsa, LSA_GENERATE); + else if (strncmp (argv[0], "f", 1) == 0) + DEBUG_ON (lsa, LSA_FLOODING); + else if (strncmp (argv[0], "i", 1) == 0) + DEBUG_ON (lsa, LSA_INSTALL); + else if (strncmp (argv[0], "r", 1) == 0) + DEBUG_ON (lsa, LSA_REFRESH); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_ON (lsa, LSA); + else if (argc == 1) + { + if (strncmp (argv[0], "g", 1) == 0) + TERM_DEBUG_ON (lsa, LSA_GENERATE); + else if (strncmp (argv[0], "f", 1) == 0) + TERM_DEBUG_ON (lsa, LSA_FLOODING); + else if (strncmp (argv[0], "i", 1) == 0) + TERM_DEBUG_ON (lsa, LSA_INSTALL); + else if (strncmp (argv[0], "r", 1) == 0) + TERM_DEBUG_ON (lsa, LSA_REFRESH); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_lsa, + debug_ospf_lsa_sub_cmd, + "debug ospf lsa (generate|flooding|install|refresh)", + DEBUG_STR + OSPF_STR + "OSPF Link State Advertisement\n" + "LSA Generation\n" + "LSA Flooding\n" + "LSA Install/Delete\n" + "LSA Refresh\n"); + +DEFUN (no_debug_ospf_lsa, + no_debug_ospf_lsa_cmd, + "no debug ospf lsa", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Link State Advertisement\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_OFF (lsa, LSA); + else if (argc == 1) + { + if (strncmp (argv[0], "g", 1) == 0) + DEBUG_OFF (lsa, LSA_GENERATE); + else if (strncmp (argv[0], "f", 1) == 0) + DEBUG_OFF (lsa, LSA_FLOODING); + else if (strncmp (argv[0], "i", 1) == 0) + DEBUG_OFF (lsa, LSA_INSTALL); + else if (strncmp (argv[0], "r", 1) == 0) + DEBUG_OFF (lsa, LSA_REFRESH); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_OFF (lsa, LSA); + else if (argc == 1) + { + if (strncmp (argv[0], "g", 1) == 0) + TERM_DEBUG_OFF (lsa, LSA_GENERATE); + else if (strncmp (argv[0], "f", 1) == 0) + TERM_DEBUG_OFF (lsa, LSA_FLOODING); + else if (strncmp (argv[0], "i", 1) == 0) + TERM_DEBUG_OFF (lsa, LSA_INSTALL); + else if (strncmp (argv[0], "r", 1) == 0) + TERM_DEBUG_OFF (lsa, LSA_REFRESH); + } + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_lsa, + no_debug_ospf_lsa_sub_cmd, + "no debug ospf lsa (generate|flooding|install|refresh)", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Link State Advertisement\n" + "LSA Generation\n" + "LSA Flooding\n" + "LSA Install/Delete\n" + "LSA Refres\n"); + + +DEFUN (debug_ospf_zebra, + debug_ospf_zebra_cmd, + "debug ospf zebra", + DEBUG_STR + OSPF_STR + "OSPF Zebra information\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_ON (zebra, ZEBRA); + else if (argc == 1) + { + if (strncmp (argv[0], "i", 1) == 0) + DEBUG_ON (zebra, ZEBRA_INTERFACE); + else if (strncmp (argv[0], "r", 1) == 0) + DEBUG_ON (zebra, ZEBRA_REDISTRIBUTE); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_ON (zebra, ZEBRA); + else if (argc == 1) + { + if (strncmp (argv[0], "i", 1) == 0) + TERM_DEBUG_ON (zebra, ZEBRA_INTERFACE); + else if (strncmp (argv[0], "r", 1) == 0) + TERM_DEBUG_ON (zebra, ZEBRA_REDISTRIBUTE); + } + + return CMD_SUCCESS; +} + +ALIAS (debug_ospf_zebra, + debug_ospf_zebra_sub_cmd, + "debug ospf zebra (interface|redistribute)", + DEBUG_STR + OSPF_STR + "OSPF Zebra information\n" + "Zebra interface\n" + "Zebra redistribute\n"); + +DEFUN (no_debug_ospf_zebra, + no_debug_ospf_zebra_cmd, + "no debug ospf zebra", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Zebra information\n") +{ + if (vty->node == CONFIG_NODE) + { + if (argc == 0) + DEBUG_OFF (zebra, ZEBRA); + else if (argc == 1) + { + if (strncmp (argv[0], "i", 1) == 0) + DEBUG_OFF (zebra, ZEBRA_INTERFACE); + else if (strncmp (argv[0], "r", 1) == 0) + DEBUG_OFF (zebra, ZEBRA_REDISTRIBUTE); + } + + return CMD_SUCCESS; + } + + /* ENABLE_NODE. */ + if (argc == 0) + TERM_DEBUG_OFF (zebra, ZEBRA); + else if (argc == 1) + { + if (strncmp (argv[0], "i", 1) == 0) + TERM_DEBUG_OFF (zebra, ZEBRA_INTERFACE); + else if (strncmp (argv[0], "r", 1) == 0) + TERM_DEBUG_OFF (zebra, ZEBRA_REDISTRIBUTE); + } + + return CMD_SUCCESS; +} + +ALIAS (no_debug_ospf_zebra, + no_debug_ospf_zebra_sub_cmd, + "no debug ospf zebra (interface|redistribute)", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF Zebra information\n" + "Zebra interface\n" + "Zebra redistribute\n"); + +DEFUN (debug_ospf_event, + debug_ospf_event_cmd, + "debug ospf event", + DEBUG_STR + OSPF_STR + "OSPF event information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_ON (event, EVENT); + TERM_DEBUG_ON (event, EVENT); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf_event, + no_debug_ospf_event_cmd, + "no debug ospf event", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF event information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_OFF (event, EVENT); + TERM_DEBUG_OFF (event, EVENT); + return CMD_SUCCESS; +} + +DEFUN (debug_ospf_nssa, + debug_ospf_nssa_cmd, + "debug ospf nssa", + DEBUG_STR + OSPF_STR + "OSPF nssa information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_ON (nssa, NSSA); + TERM_DEBUG_ON (nssa, NSSA); + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf_nssa, + no_debug_ospf_nssa_cmd, + "no debug ospf nssa", + NO_STR + DEBUG_STR + OSPF_STR + "OSPF nssa information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_OFF (nssa, NSSA); + TERM_DEBUG_OFF (nssa, NSSA); + return CMD_SUCCESS; +} + + +DEFUN (show_debugging_ospf, + show_debugging_ospf_cmd, + "show debugging ospf", + SHOW_STR + DEBUG_STR + OSPF_STR) +{ + int i; + + vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE); + + /* Show debug status for ISM. */ + if (IS_DEBUG_OSPF (ism, ISM) == OSPF_DEBUG_ISM) + vty_out (vty, " OSPF ISM debugging is on%s", VTY_NEWLINE); + else + { + if (IS_DEBUG_OSPF (ism, ISM_STATUS)) + vty_out (vty, " OSPF ISM status debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) + vty_out (vty, " OSPF ISM event debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (ism, ISM_TIMERS)) + vty_out (vty, " OSPF ISM timer debugging is on%s", VTY_NEWLINE); + } + + /* Show debug status for NSM. */ + if (IS_DEBUG_OSPF (nsm, NSM) == OSPF_DEBUG_NSM) + vty_out (vty, " OSPF NSM debugging is on%s", VTY_NEWLINE); + else + { + if (IS_DEBUG_OSPF (nsm, NSM_STATUS)) + vty_out (vty, " OSPF NSM status debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) + vty_out (vty, " OSPF NSM event debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) + vty_out (vty, " OSPF NSM timer debugging is on%s", VTY_NEWLINE); + } + + /* Show debug status for OSPF Packets. */ + for (i = 0; i < 5; i++) + if (IS_DEBUG_OSPF_PACKET (i, SEND) && IS_DEBUG_OSPF_PACKET (i, RECV)) + { + vty_out (vty, " OSPF packet %s%s debugging is on%s", + ospf_packet_type_str[i + 1], + IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", + VTY_NEWLINE); + } + else + { + if (IS_DEBUG_OSPF_PACKET (i, SEND)) + vty_out (vty, " OSPF packet %s send%s debugging is on%s", + ospf_packet_type_str[i + 1], + IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", + VTY_NEWLINE); + if (IS_DEBUG_OSPF_PACKET (i, RECV)) + vty_out (vty, " OSPF packet %s receive%s debugging is on%s", + ospf_packet_type_str[i + 1], + IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", + VTY_NEWLINE); + } + + /* Show debug status for OSPF LSAs. */ + if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) + vty_out (vty, " OSPF LSA debugging is on%s", VTY_NEWLINE); + else + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + vty_out (vty, " OSPF LSA generation debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + vty_out (vty, " OSPF LSA flooding debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) + vty_out (vty, " OSPF LSA install debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + vty_out (vty, " OSPF LSA refresh debugging is on%s", VTY_NEWLINE); + } + + /* Show debug status for Zebra. */ + if (IS_DEBUG_OSPF (zebra, ZEBRA) == OSPF_DEBUG_ZEBRA) + vty_out (vty, " OSPF Zebra debugging is on%s", VTY_NEWLINE); + else + { + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + vty_out (vty, " OSPF Zebra interface debugging is on%s", VTY_NEWLINE); + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + vty_out (vty, " OSPF Zebra redistribute debugging is on%s", VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +/* Debug node. */ +struct cmd_node debug_node = +{ + DEBUG_NODE, + "" +}; + +int +config_write_debug (struct vty *vty) +{ + int write = 0; + int i, r; + + char *type_str[] = {"hello", "dd", "ls-request", "ls-update", "ls-ack"}; + char *detail_str[] = {"", " send", " recv", "", " detail", + " send detail", " recv detail", " detail"}; + + /* debug ospf ism (status|events|timers). */ + if (IS_CONF_DEBUG_OSPF (ism, ISM) == OSPF_DEBUG_ISM) + vty_out (vty, "debug ospf ism%s", VTY_NEWLINE); + else + { + if (IS_CONF_DEBUG_OSPF (ism, ISM_STATUS)) + vty_out (vty, "debug ospf ism status%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (ism, ISM_EVENTS)) + vty_out (vty, "debug ospf ism event%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (ism, ISM_TIMERS)) + vty_out (vty, "debug ospf ism timer%s", VTY_NEWLINE); + } + + /* debug ospf nsm (status|events|timers). */ + if (IS_CONF_DEBUG_OSPF (nsm, NSM) == OSPF_DEBUG_NSM) + vty_out (vty, "debug ospf nsm%s", VTY_NEWLINE); + else + { + if (IS_CONF_DEBUG_OSPF (nsm, NSM_STATUS)) + vty_out (vty, "debug ospf ism status%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (nsm, NSM_EVENTS)) + vty_out (vty, "debug ospf nsm event%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (nsm, NSM_TIMERS)) + vty_out (vty, "debug ospf nsm timer%s", VTY_NEWLINE); + } + + /* debug ospf lsa (generate|flooding|install|refresh). */ + if (IS_CONF_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) + vty_out (vty, "debug ospf lsa%s", VTY_NEWLINE); + else + { + if (IS_CONF_DEBUG_OSPF (lsa, LSA_GENERATE)) + vty_out (vty, "debug ospf lsa generate%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (lsa, LSA_FLOODING)) + vty_out (vty, "debug ospf lsa flooding%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (lsa, LSA_INSTALL)) + vty_out (vty, "debug ospf lsa install%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (lsa, LSA_REFRESH)) + vty_out (vty, "debug ospf lsa refresh%s", VTY_NEWLINE); + + write = 1; + } + + /* debug ospf zebra (interface|redistribute). */ + if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA) == OSPF_DEBUG_ZEBRA) + vty_out (vty, "debug ospf zebra%s", VTY_NEWLINE); + else + { + if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + vty_out (vty, "debug ospf zebra interface%s", VTY_NEWLINE); + if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + vty_out (vty, "debug ospf zebra redistribute%s", VTY_NEWLINE); + + write = 1; + } + + /* debug ospf event. */ + if (IS_CONF_DEBUG_OSPF (event, EVENT) == OSPF_DEBUG_EVENT) + { + vty_out (vty, "debug ospf event%s", VTY_NEWLINE); + write = 1; + } + + /* debug ospf nssa. */ + if (IS_CONF_DEBUG_OSPF (nssa, NSSA) == OSPF_DEBUG_NSSA) + { + vty_out (vty, "debug ospf nssa%s", VTY_NEWLINE); + write = 1; + } + + /* debug ospf packet all detail. */ + r = OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL; + for (i = 0; i < 5; i++) + r &= conf_debug_ospf_packet[i] & (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL); + if (r == (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL)) + { + vty_out (vty, "debug ospf packet all detail%s", VTY_NEWLINE); + return 1; + } + + /* debug ospf packet all. */ + r = OSPF_DEBUG_SEND_RECV; + for (i = 0; i < 5; i++) + r &= conf_debug_ospf_packet[i] & OSPF_DEBUG_SEND_RECV; + if (r == OSPF_DEBUG_SEND_RECV) + { + vty_out (vty, "debug ospf packet all%s", VTY_NEWLINE); + for (i = 0; i < 5; i++) + if (conf_debug_ospf_packet[i] & OSPF_DEBUG_DETAIL) + vty_out (vty, "debug ospf packet %s detail%s", + type_str[i], + VTY_NEWLINE); + return 1; + } + + /* debug ospf packet (hello|dd|ls-request|ls-update|ls-ack) + (send|recv) (detail). */ + for (i = 0; i < 5; i++) + { + if (conf_debug_ospf_packet[i] == 0) + continue; + + vty_out (vty, "debug ospf packet %s%s%s", + type_str[i], detail_str[conf_debug_ospf_packet[i]], + VTY_NEWLINE); + write = 1; + } + + return write; +} + +/* Initialize debug commands. */ +void +debug_init () +{ + install_node (&debug_node, config_write_debug); + + install_element (ENABLE_NODE, &show_debugging_ospf_cmd); + install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_detail_cmd); + install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_cmd); + install_element (ENABLE_NODE, &debug_ospf_packet_all_cmd); + install_element (ENABLE_NODE, &debug_ospf_ism_sub_cmd); + install_element (ENABLE_NODE, &debug_ospf_ism_cmd); + install_element (ENABLE_NODE, &debug_ospf_nsm_sub_cmd); + install_element (ENABLE_NODE, &debug_ospf_nsm_cmd); + install_element (ENABLE_NODE, &debug_ospf_lsa_sub_cmd); + install_element (ENABLE_NODE, &debug_ospf_lsa_cmd); + install_element (ENABLE_NODE, &debug_ospf_zebra_sub_cmd); + install_element (ENABLE_NODE, &debug_ospf_zebra_cmd); + install_element (ENABLE_NODE, &debug_ospf_event_cmd); +#ifdef HAVE_NSSA + install_element (ENABLE_NODE, &debug_ospf_nssa_cmd); +#endif /* HAVE_NSSA */ + install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_detail_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_packet_all_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_ism_sub_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_ism_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_nsm_sub_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_nsm_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_lsa_sub_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_lsa_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_zebra_sub_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_zebra_cmd); + install_element (ENABLE_NODE, &no_debug_ospf_event_cmd); +#ifdef HAVE_NSSA + install_element (ENABLE_NODE, &no_debug_ospf_nssa_cmd); +#endif /* HAVE_NSSA */ + + install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_detail_cmd); + install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_cmd); + install_element (CONFIG_NODE, &debug_ospf_packet_all_cmd); + install_element (CONFIG_NODE, &debug_ospf_ism_sub_cmd); + install_element (CONFIG_NODE, &debug_ospf_ism_cmd); + install_element (CONFIG_NODE, &debug_ospf_nsm_sub_cmd); + install_element (CONFIG_NODE, &debug_ospf_nsm_cmd); + install_element (CONFIG_NODE, &debug_ospf_lsa_sub_cmd); + install_element (CONFIG_NODE, &debug_ospf_lsa_cmd); + install_element (CONFIG_NODE, &debug_ospf_zebra_sub_cmd); + install_element (CONFIG_NODE, &debug_ospf_zebra_cmd); + install_element (CONFIG_NODE, &debug_ospf_event_cmd); +#ifdef HAVE_NSSA + install_element (CONFIG_NODE, &debug_ospf_nssa_cmd); +#endif /* HAVE_NSSA */ + install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_detail_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_packet_all_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_ism_sub_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_ism_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_nsm_sub_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_nsm_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_lsa_sub_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_lsa_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_zebra_sub_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_zebra_cmd); + install_element (CONFIG_NODE, &no_debug_ospf_event_cmd); +#ifdef HAVE_NSSA + install_element (CONFIG_NODE, &no_debug_ospf_nssa_cmd); +#endif /* HAVE_NSSA */ +} diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h new file mode 100644 index 0000000..70479fb --- /dev/null +++ b/ospfd/ospf_dump.h @@ -0,0 +1,136 @@ +/* + * OSPFd dump routine. + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_DUMP_H +#define _ZEBRA_OSPF_DUMP_H + +/* Debug Flags. */ +#define OSPF_DEBUG_HELLO 0x01 +#define OSPF_DEBUG_DB_DESC 0x02 +#define OSPF_DEBUG_LS_REQ 0x04 +#define OSPF_DEBUG_LS_UPD 0x08 +#define OSPF_DEBUG_LS_ACK 0x10 +#define OSPF_DEBUG_ALL 0x1f + +#define OSPF_DEBUG_SEND 0x01 +#define OSPF_DEBUG_RECV 0x02 +#define OSPF_DEBUG_SEND_RECV 0x03 +#define OSPF_DEBUG_DETAIL 0x04 + +#define OSPF_DEBUG_ISM_STATUS 0x01 +#define OSPF_DEBUG_ISM_EVENTS 0x02 +#define OSPF_DEBUG_ISM_TIMERS 0x04 +#define OSPF_DEBUG_ISM 0x07 +#define OSPF_DEBUG_NSM_STATUS 0x01 +#define OSPF_DEBUG_NSM_EVENTS 0x02 +#define OSPF_DEBUG_NSM_TIMERS 0x04 +#define OSPF_DEBUG_NSM 0x07 + +#define OSPF_DEBUG_LSA_GENERATE 0x01 +#define OSPF_DEBUG_LSA_FLOODING 0x02 +#define OSPF_DEBUG_LSA_INSTALL 0x04 +#define OSPF_DEBUG_LSA_REFRESH 0x08 +#define OSPF_DEBUG_LSA 0x0F + +#define OSPF_DEBUG_ZEBRA_INTERFACE 0x01 +#define OSPF_DEBUG_ZEBRA_REDISTRIBUTE 0x02 +#define OSPF_DEBUG_ZEBRA 0x03 + +#define OSPF_DEBUG_EVENT 0x01 +#define OSPF_DEBUG_NSSA 0x02 + +/* Macro for setting debug option. */ +#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b) +#define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b) +#define TERM_DEBUG_PACKET_ON(a, b) term_debug_ospf_packet[a] |= (b) +#define TERM_DEBUG_PACKET_OFF(a, b) term_debug_ospf_packet[a] &= ~(b) +#define DEBUG_PACKET_ON(a, b) \ + do { \ + CONF_DEBUG_PACKET_ON(a, b); \ + TERM_DEBUG_PACKET_ON(a, b); \ + } while (0) +#define DEBUG_PACKET_OFF(a, b) \ + do { \ + CONF_DEBUG_PACKET_OFF(a, b); \ + TERM_DEBUG_PACKET_OFF(a, b); \ + } while (0) + +#define CONF_DEBUG_ON(a, b) conf_debug_ospf_ ## a |= (OSPF_DEBUG_ ## b) +#define CONF_DEBUG_OFF(a, b) conf_debug_ospf_ ## a &= ~(OSPF_DEBUG_ ## b) +#define TERM_DEBUG_ON(a, b) term_debug_ospf_ ## a |= (OSPF_DEBUG_ ## b) +#define TERM_DEBUG_OFF(a, b) term_debug_ospf_ ## a &= ~(OSPF_DEBUG_ ## b) +#define DEBUG_ON(a, b) \ + do { \ + CONF_DEBUG_ON(a, b); \ + TERM_DEBUG_ON(a, b); \ + } while (0) +#define DEBUG_OFF(a, b) \ + do { \ + CONF_DEBUG_OFF(a, b); \ + TERM_DEBUG_OFF(a, b); \ + } while (0) + +/* Macro for checking debug option. */ +#define IS_DEBUG_OSPF_PACKET(a, b) \ + (term_debug_ospf_packet[a] & OSPF_DEBUG_ ## b) +#define IS_DEBUG_OSPF(a, b) \ + (term_debug_ospf_ ## a & OSPF_DEBUG_ ## b) +#define IS_DEBUG_OSPF_EVENT IS_DEBUG_OSPF(event,EVENT) + +#define IS_DEBUG_OSPF_NSSA IS_DEBUG_OSPF(event,NSSA) + +#define IS_CONF_DEBUG_OSPF_PACKET(a, b) \ + (conf_debug_ospf_packet[a] & OSPF_DEBUG_ ## b) +#define IS_CONF_DEBUG_OSPF(a, b) \ + (conf_debug_ospf_ ## a & OSPF_DEBUG_ ## b) + +struct stream; + +#define AREA_NAME(A) ospf_area_name_string ((A)) +#define IF_NAME(I) ospf_if_name_string ((I)) + +/* Extern debug flag. */ +extern unsigned long term_debug_ospf_packet[]; +extern unsigned long term_debug_ospf_event; +extern unsigned long term_debug_ospf_ism; +extern unsigned long term_debug_ospf_nsm; +extern unsigned long term_debug_ospf_lsa; +extern unsigned long term_debug_ospf_zebra; +extern unsigned long term_debug_ospf_nssa; + +/* Message Strings. */ +extern char *ospf_packet_type_str[]; +extern char *ospf_lsa_type_str[]; + +/* Prototypes. */ +char *ospf_area_name_string (struct ospf_area *); +char *ospf_area_desc_string (struct ospf_area *); +char *ospf_if_name_string (struct ospf_interface *); +void ospf_nbr_state_message (struct ospf_neighbor *, char *, size_t); +char *ospf_options_dump (u_char); +char *ospf_timer_dump (struct thread *, char *, size_t); +void ospf_ip_header_dump (struct stream *); +void ospf_packet_dump (struct stream *); +void ospf_lsa_header_dump (struct lsa_header *); +void debug_init (); + +#endif /* _ZEBRA_OSPF_DUMP_H */ diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c new file mode 100644 index 0000000..251f2eb --- /dev/null +++ b/ospfd/ospf_flood.c @@ -0,0 +1,976 @@ +/* + * OSPF Flooding -- RFC2328 Section 13. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "command.h" +#include "table.h" +#include "thread.h" +#include "memory.h" +#include "log.h" +#include "zclient.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + +extern struct zclient *zclient; + +/* Do the LSA acking specified in table 19, Section 13.5, row 2 + * This get called from ospf_flood_out_interface. Declared inline + * for speed. */ +static void +ospf_flood_delayed_lsa_ack (struct ospf_neighbor *inbr, struct ospf_lsa *lsa) +{ + /* LSA is more recent than database copy, but was not + flooded back out receiving interface. Delayed + acknowledgment sent. If interface is in Backup state + delayed acknowledgment sent only if advertisement + received from Designated Router, otherwise do nothing See + RFC 2328 Section 13.5 */ + + /* Whether LSA is more recent or not, and whether this is in + response to the LSA being sent out recieving interface has been + worked out previously */ + + /* Deal with router as BDR */ + if (inbr->oi->state == ISM_Backup && ! NBR_IS_DR (inbr)) + return; + + /* Schedule a delayed LSA Ack to be sent */ + listnode_add (inbr->oi->ls_ack, ospf_lsa_lock (lsa)); +} + +/* Check LSA is related to external info. */ +struct external_info * +ospf_external_info_check (struct ospf_lsa *lsa) +{ + struct as_external_lsa *al; + struct prefix_ipv4 p; + struct route_node *rn; + int type; + + al = (struct as_external_lsa *) lsa->data; + + p.family = AF_INET; + p.prefix = lsa->data->id; + p.prefixlen = ip_masklen (al->mask); + + for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) + { + int redist_type = is_prefix_default (&p) ? DEFAULT_ROUTE : type; + if (ospf_is_type_redistributed (redist_type)) + if (EXTERNAL_INFO (type)) + { + rn = route_node_lookup (EXTERNAL_INFO (type), + (struct prefix *) &p); + if (rn) + { + route_unlock_node (rn); + if (rn->info != NULL) + return (struct external_info *) rn->info; + } + } + } + + return NULL; +} + +void +ospf_process_self_originated_lsa (struct ospf *ospf, + struct ospf_lsa *new, struct ospf_area *area) +{ + struct ospf_interface *oi; + struct external_info *ei; + listnode node; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type%d:%s]: Process self-originated LSA", + new->data->type, inet_ntoa (new->data->id)); + + /* If we're here, we installed a self-originated LSA that we received + from a neighbor, i.e. it's more recent. We must see whether we want + to originate it. + If yes, we should use this LSA's sequence number and reoriginate + a new instance. + if not --- we must flush this LSA from the domain. */ + switch (new->data->type) + { + case OSPF_ROUTER_LSA: + /* Originate a new instance and schedule flooding */ + /* It shouldn't be necessary, but anyway */ + ospf_lsa_unlock (area->router_lsa_self); + area->router_lsa_self = ospf_lsa_lock (new); + + ospf_router_lsa_timer_add (area); + return; + case OSPF_NETWORK_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: +#endif /* HAVE_OPAQUE_LSA */ + /* We must find the interface the LSA could belong to. + If the interface is no more a broadcast type or we are no more + the DR, we flush the LSA otherwise -- create the new instance and + schedule flooding. */ + + /* Look through all interfaces, not just area, since interface + could be moved from one area to another. */ + for (node = listhead (ospf->oiflist); node; nextnode (node)) + /* These are sanity check. */ + if ((oi = getdata (node)) != NULL) + if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &new->data->id)) + { + if (oi->area != area || + oi->type != OSPF_IFTYPE_BROADCAST || + !IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))) + { + ospf_schedule_lsa_flush_area (area, new); + return; + } + +#ifdef HAVE_OPAQUE_LSA + if (new->data->type == OSPF_OPAQUE_LINK_LSA) + { + ospf_opaque_lsa_refresh (new); + return; + } +#endif /* HAVE_OPAQUE_LSA */ + + ospf_lsa_unlock (oi->network_lsa_self); + oi->network_lsa_self = ospf_lsa_lock (new); + + /* Schedule network-LSA origination. */ + ospf_network_lsa_timer_add (oi); + return; + } + break; + case OSPF_SUMMARY_LSA: + case OSPF_ASBR_SUMMARY_LSA: + ospf_schedule_abr_task (ospf); + break; + case OSPF_AS_EXTERNAL_LSA : +#ifdef HAVE_NSSA + case OSPF_AS_NSSA_LSA: +#endif /* HAVE_NSSA */ + ei = ospf_external_info_check (new); + if (ei) + ospf_external_lsa_refresh (ospf, new, ei, LSA_REFRESH_FORCE); + else + ospf_lsa_flush_as (ospf, new); + break; +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AREA_LSA: + ospf_opaque_lsa_refresh (new); + break; + case OSPF_OPAQUE_AS_LSA: + ospf_opaque_lsa_refresh (new); /* Reconsideration may needed. *//* XXX */ + break; +#endif /* HAVE_OPAQUE_LSA */ + default: + break; + } +} + +/* OSPF LSA flooding -- RFC2328 Section 13.(5). */ + +/* Now Updated for NSSA operation, as follows: + + + Type-5's have no change. Blocked to STUB or NSSA. + + Type-7's can be received, and if a DR + they will also flood the local NSSA Area as Type-7's + + If a Self-Originated LSA (now an ASBR), + The LSDB will be updated as Type-5's, (for continual re-fresh) + + If an NSSA-IR it is installed/flooded as Type-7, P-bit on. + if an NSSA-ABR it is installed/flooded as Type-7, P-bit off. + + Later, during the ABR TASK, if the ABR is the Elected NSSA + translator, then All Type-7s (with P-bit ON) are Translated to + Type-5's and flooded to all non-NSSA/STUB areas. + + During ASE Calculations, + non-ABRs calculate external routes from Type-7's + ABRs calculate external routes from Type-5's and non-self Type-7s +*/ +int +ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr, + struct ospf_lsa *current, struct ospf_lsa *new) +{ + struct ospf_interface *oi; + struct timeval now; + int lsa_ack_flag; + + /* Type-7 LSA's will be flooded throughout their native NSSA area, + but will also be flooded as Type-5's into ABR capable links. */ + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Flooding]: start, NBR %s (%s), cur(%p), New-LSA[%s]", + inet_ntoa (nbr->router_id), + LOOKUP (ospf_nsm_state_msg, nbr->state), + current, + dump_lsa_key (new)); + + lsa_ack_flag = 0; + oi = nbr->oi; + + /* Get current time. */ + gettimeofday (&now, NULL); + + /* If there is already a database copy, and if the + database copy was received via flooding and installed less + than MinLSArrival seconds ago, discard the new LSA + (without acknowledging it). */ + if (current != NULL) /* -- endo. */ + { + if (IS_LSA_SELF (current) + && (ntohs (current->data->ls_age) == 0 + && ntohl (current->data->ls_seqnum) == OSPF_INITIAL_SEQUENCE_NUMBER)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Flooding]: Got a self-originated LSA, " + "while local one is initial instance."); + ; /* Accept this LSA for quick LSDB resynchronization. */ + } + else if (tv_cmp (tv_sub (now, current->tv_recv), + int2tv (OSPF_MIN_LS_ARRIVAL)) < 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Flooding]: LSA is received recently."); + return -1; + } + } + + /* Flood the new LSA out some subset of the router's interfaces. + In some cases (e.g., the state of the receiving interface is + DR and the LSA was received from a router other than the + Backup DR) the LSA will be flooded back out the receiving + interface. */ + lsa_ack_flag = ospf_flood_through (ospf, nbr, new); + +#ifdef HAVE_OPAQUE_LSA + /* Remove the current database copy from all neighbors' Link state + retransmission lists. AS_EXTERNAL and AS_EXTERNAL_OPAQUE does + ^^^^^^^^^^^^^^^^^^^^^^^ + not have area ID. + All other (even NSSA's) do have area ID. */ +#else /* HAVE_OPAQUE_LSA */ + /* Remove the current database copy from all neighbors' Link state + retransmission lists. Only AS_EXTERNAL does not have area ID. + All other (even NSSA's) do have area ID. */ +#endif /* HAVE_OPAQUE_LSA */ + if (current) + { + switch (current->data->type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + ospf_ls_retransmit_delete_nbr_as (ospf, current); + break; + default: + ospf_ls_retransmit_delete_nbr_area (nbr->oi->area, current); + break; + } + } + + /* Do some internal house keeping that is needed here */ + SET_FLAG (new->flags, OSPF_LSA_RECEIVED); + ospf_lsa_is_self_originated (ospf, new); /* Let it set the flag */ + + /* Install the new LSA in the link state database + (replacing the current database copy). This may cause the + routing table calculation to be scheduled. In addition, + timestamp the new LSA with the current time. The flooding + procedure cannot overwrite the newly installed LSA until + MinLSArrival seconds have elapsed. */ + + new = ospf_lsa_install (ospf, nbr->oi, new); + + /* Acknowledge the receipt of the LSA by sending a Link State + Acknowledgment packet back out the receiving interface. */ + if (lsa_ack_flag) + ospf_flood_delayed_lsa_ack (nbr, new); + + /* If this new LSA indicates that it was originated by the + receiving router itself, the router must take special action, + either updating the LSA or in some cases flushing it from + the routing domain. */ + if (ospf_lsa_is_self_originated (ospf, new)) + ospf_process_self_originated_lsa (ospf, new, oi->area); + else + /* Update statistics value for OSPF-MIB. */ + ospf->rx_lsa_count++; + + return 0; +} + +/* OSPF LSA flooding -- RFC2328 Section 13.3. */ +int +ospf_flood_through_interface (struct ospf_interface *oi, + struct ospf_neighbor *inbr, + struct ospf_lsa *lsa) +{ + struct ospf_neighbor *onbr; + struct route_node *rn; + int retx_flag; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_flood_through_interface(): " + "considering int %s, INBR(%s), LSA[%s]", + IF_NAME (oi), inbr ? inet_ntoa (inbr->router_id) : "NULL", + dump_lsa_key (lsa)); + + if (!ospf_if_is_enable (oi)) + return 0; + + /* Remember if new LSA is aded to a retransmit list. */ + retx_flag = 0; + + /* Each of the neighbors attached to this interface are examined, + to determine whether they must receive the new LSA. The following + steps are executed for each neighbor: */ + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + { + struct ospf_lsa *ls_req; + + if (rn->info == NULL) + continue; + + onbr = rn->info; + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_flood_through_interface(): considering nbr %s (%s)", + inet_ntoa (onbr->router_id), + LOOKUP (ospf_nsm_state_msg, onbr->state)); + + /* If the neighbor is in a lesser state than Exchange, it + does not participate in flooding, and the next neighbor + should be examined. */ + if (onbr->state < NSM_Exchange) + continue; + + /* If the adjacency is not yet full (neighbor state is + Exchange or Loading), examine the Link state request + list associated with this adjacency. If there is an + instance of the new LSA on the list, it indicates that + the neighboring router has an instance of the LSA + already. Compare the new LSA to the neighbor's copy: */ + if (onbr->state < NSM_Full) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_flood_through_interface(): nbr adj is not Full"); + ls_req = ospf_ls_request_lookup (onbr, lsa); + if (ls_req != NULL) + { + int ret; + + ret = ospf_lsa_more_recent (ls_req, lsa); + /* The new LSA is less recent. */ + if (ret > 0) + continue; + /* The two copies are the same instance, then delete + the LSA from the Link state request list. */ + else if (ret == 0) + { + ospf_ls_request_delete (onbr, ls_req); + ospf_check_nbr_loading (onbr); + continue; + } + /* The new LSA is more recent. Delete the LSA + from the Link state request list. */ + else + { + ospf_ls_request_delete (onbr, ls_req); + ospf_check_nbr_loading (onbr); + } + } + } + +#ifdef HAVE_OPAQUE_LSA + if (IS_OPAQUE_LSA (lsa->data->type)) + { + if (! CHECK_FLAG (onbr->options, OSPF_OPTION_O)) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("Skip this neighbor: Not Opaque-capable."); + continue; + } + + if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (oi->ospf->opaque) + && IS_LSA_SELF (lsa) + && onbr->state == NSM_Full) + { + /* Small attempt to reduce unnecessary retransmission. */ + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("Skip this neighbor: Initial flushing done."); + continue; + } + } +#endif /* HAVE_OPAQUE_LSA */ + + /* If the new LSA was received from this neighbor, + examine the next neighbor. */ + if (inbr) + { + /* + * Triggered by LSUpd message parser "ospf_ls_upd ()". + * E.g., all LSAs handling here is received via network. + */ + if (IPV4_ADDR_SAME (&inbr->router_id, &onbr->router_id)) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("Skip this neighbor: inbr == onbr"); + continue; + } + } + else + { + /* + * Triggered by MaxAge remover, so far. + * NULL "inbr" means flooding starts from this node. + */ + if (IPV4_ADDR_SAME (&lsa->data->adv_router, &onbr->router_id)) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("Skip this neighbor: lsah->adv_router == onbr"); + continue; + } + } + + /* Add the new LSA to the Link state retransmission list + for the adjacency. The LSA will be retransmitted + at intervals until an acknowledgment is seen from + the neighbor. */ + ospf_ls_retransmit_add (onbr, lsa); + retx_flag = 1; + } + + /* If in the previous step, the LSA was NOT added to any of + the Link state retransmission lists, there is no need to + flood the LSA out the interface. */ + if (retx_flag == 0) + { + return (inbr && inbr->oi == oi); + } + + /* if we've received the lsa on this interface we need to perform + additional checking */ + if (inbr && (inbr->oi == oi)) + { + /* If the new LSA was received on this interface, and it was + received from either the Designated Router or the Backup + Designated Router, chances are that all the neighbors have + received the LSA already. */ + if (NBR_IS_DR (inbr) || NBR_IS_BDR (inbr)) + { +#ifdef HAVE_NSSA + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_flood_through_interface(): " + "DR/BDR NOT SEND to int %s", IF_NAME (oi)); +#endif /* HAVE_NSSA */ + return 1; + } + + /* If the new LSA was received on this interface, and the + interface state is Backup, examine the next interface. The + Designated Router will do the flooding on this interface. + However, if the Designated Router fails the router will + end up retransmitting the updates. */ + + if (oi->state == ISM_Backup) + { +#ifdef HAVE_NSSA + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_flood_through_interface(): " + "ISM_Backup NOT SEND to int %s", IF_NAME (oi)); +#endif /* HAVE_NSSA */ + return 1; + } + } + + /* The LSA must be flooded out the interface. Send a Link State + Update packet (including the new LSA as contents) out the + interface. The LSA's LS age must be incremented by InfTransDelay + (which must be > 0) when it is copied into the outgoing Link + State Update packet (until the LS age field reaches the maximum + value of MaxAge). */ + +#ifdef HAVE_NSSA + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_flood_through_interface(): " + "DR/BDR sending upd to int %s", IF_NAME (oi)); +#else /* ! HAVE_NSSA */ + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_flood_through_interface(): " + "sending upd to int %s", IF_NAME (oi)); +#endif /* HAVE_NSSA */ + + /* RFC2328 Section 13.3 + On non-broadcast networks, separate Link State Update + packets must be sent, as unicasts, to each adjacent neighbor + (i.e., those in state Exchange or greater). The destination + IP addresses for these packets are the neighbors' IP + addresses. */ + if (oi->type == OSPF_IFTYPE_NBMA) + { + struct route_node *rn; + struct ospf_neighbor *nbr; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) + ospf_ls_upd_send_lsa (nbr, lsa, OSPF_SEND_PACKET_DIRECT); + } + else + ospf_ls_upd_send_lsa (oi->nbr_self, lsa, OSPF_SEND_PACKET_INDIRECT); + + return 0; +} + +int +ospf_flood_through_area (struct ospf_area *area, + struct ospf_neighbor *inbr, struct ospf_lsa *lsa) +{ + listnode node; + int lsa_ack_flag = 0; + + /* All other types are specific to a single area (Area A). The + eligible interfaces are all those interfaces attaching to the + Area A. If Area A is the backbone, this includes all the virtual + links. */ + for (node = listhead (area->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + + if (area->area_id.s_addr != OSPF_AREA_BACKBONE && + oi->type == OSPF_IFTYPE_VIRTUALLINK) + continue; + +#ifdef HAVE_OPAQUE_LSA + if ((lsa->data->type == OSPF_OPAQUE_LINK_LSA) && (lsa->oi != oi)) + { + /* + * Link local scoped Opaque-LSA should only be flooded + * for the link on which the LSA has received. + */ + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("Type-9 Opaque-LSA: lsa->oi(%p) != oi(%p)", lsa->oi, oi); + continue; + } +#endif /* HAVE_OPAQUE_LSA */ + + if (ospf_flood_through_interface (oi, inbr, lsa)) + lsa_ack_flag = 1; + } + + return (lsa_ack_flag); +} + +int +ospf_flood_through_as (struct ospf *ospf, struct ospf_neighbor *inbr, + struct ospf_lsa *lsa) +{ + listnode node; + int lsa_ack_flag; + + lsa_ack_flag = 0; + + /* The incoming LSA is type 5 or type 7 (AS-EXTERNAL or AS-NSSA ) + + Divert the Type-5 LSA's to all non-NSSA/STUB areas + + Divert the Type-7 LSA's to all NSSA areas + + AS-external-LSAs are flooded throughout the entire AS, with the + exception of stub areas (see Section 3.6). The eligible + interfaces are all the router's interfaces, excluding virtual + links and those interfaces attaching to stub areas. */ + +#ifdef HAVE_NSSA + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) /* Translated from 7 */ + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("Flood/AS: NSSA TRANSLATED LSA"); +#endif /* HAVE_NSSA */ + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + int continue_flag = 0; + struct ospf_area *area = getdata (node); + listnode if_node; + + switch (area->external_routing) + { + /* Don't send AS externals into stub areas. Various types + of support for partial stub areas can be implemented + here. NSSA's will receive Type-7's that have areas + matching the originl LSA. */ + case OSPF_AREA_NSSA: /* Sending Type 5 or 7 into NSSA area */ +#ifdef HAVE_NSSA + /* Type-7, flood NSSA area */ + if (lsa->data->type == OSPF_AS_NSSA_LSA + && area == lsa->area) + continue_flag = 0; + else + continue_flag = 1; /* Skip this NSSA area for Type-5's et al */ + break; +#endif /* HAVE_NSSA */ + + case OSPF_AREA_TYPE_MAX: + case OSPF_AREA_STUB: + continue_flag = 1; /* Skip this area. */ + break; + + case OSPF_AREA_DEFAULT: + default: +#ifdef HAVE_NSSA + /* No Type-7 into normal area */ + if (lsa->data->type == OSPF_AS_NSSA_LSA) + continue_flag = 1; /* skip Type-7 */ + else +#endif /* HAVE_NSSA */ + continue_flag = 0; /* Do this area. */ + break; + } + + /* Do continue for above switch. Saves a big if then mess */ + if (continue_flag) + continue; /* main for-loop */ + + /* send to every interface in this area */ + + for (if_node = listhead (area->oiflist); if_node; nextnode (if_node)) + { + struct ospf_interface *oi = getdata (if_node); + + /* Skip virtual links */ + if (oi->type != OSPF_IFTYPE_VIRTUALLINK) + if (ospf_flood_through_interface (oi, inbr, lsa)) /* lsa */ + lsa_ack_flag = 1; + } + } /* main area for-loop */ + + return (lsa_ack_flag); +} + +int +ospf_flood_through (struct ospf *ospf, + struct ospf_neighbor *inbr, struct ospf_lsa *lsa) +{ + int lsa_ack_flag = 0; + + /* Type-7 LSA's for NSSA are flooded throughout the AS here, and + upon return are updated in the LSDB for Type-7's. Later, + re-fresh will re-send them (and also, if ABR, packet code will + translate to Type-5's) + + As usual, Type-5 LSA's (if not DISCARDED because we are STUB or + NSSA) are flooded throughout the AS, and are updated in the + global table. */ + /* + * At the common sub-sub-function "ospf_flood_through_interface()", + * a parameter "inbr" will be used to distinguish the called context + * whether the given LSA was received from the neighbor, or the + * flooding for the LSA starts from this node (e.g. the LSA was self- + * originated, or the LSA is going to be flushed from routing domain). + * + * So, for consistency reasons, this function "ospf_flood_through()" + * should also allow the usage that the given "inbr" parameter to be + * NULL. If we do so, corresponding AREA parameter should be referred + * by "lsa->area", instead of "inbr->oi->area". + */ + switch (lsa->data->type) + { + case OSPF_AS_EXTERNAL_LSA: /* Type-5 */ +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + lsa_ack_flag = ospf_flood_through_as (ospf, inbr, lsa); + break; +#ifdef HAVE_NSSA + /* Type-7 Only received within NSSA, then flooded */ + case OSPF_AS_NSSA_LSA: + /* Any P-bit was installed with the Type-7. */ + + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("ospf_flood_through: LOCAL NSSA FLOOD of Type-7."); + /* Fallthrough */ +#endif /* HAVE_NSSA */ + default: + lsa_ack_flag = ospf_flood_through_area (lsa->area, inbr, lsa); + break; + } + + return (lsa_ack_flag); +} + + + +/* Management functions for neighbor's Link State Request list. */ +void +ospf_ls_request_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + /* + * We cannot make use of the newly introduced callback function + * "lsdb->new_lsa_hook" to replace debug output below, just because + * it seems no simple and smart way to pass neighbor information to + * the common function "ospf_lsdb_add()" -- endo. + */ + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("RqstL(%lu)++, NBR(%s), LSA[%s]", + ospf_ls_request_count (nbr), + inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); + + ospf_lsdb_add (&nbr->ls_req, lsa); +} + +unsigned long +ospf_ls_request_count (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_count_all (&nbr->ls_req); +} + +int +ospf_ls_request_isempty (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_isempty (&nbr->ls_req); +} + +/* Remove LSA from neighbor's ls-request list. */ +void +ospf_ls_request_delete (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + if (nbr->ls_req_last == lsa) + { + ospf_lsa_unlock (nbr->ls_req_last); + nbr->ls_req_last = NULL; + } + + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) /* -- endo. */ + zlog_info ("RqstL(%lu)--, NBR(%s), LSA[%s]", + ospf_ls_request_count (nbr), + inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); + + ospf_lsdb_delete (&nbr->ls_req, lsa); +} + +/* Remove all LSA from neighbor's ls-requenst list. */ +void +ospf_ls_request_delete_all (struct ospf_neighbor *nbr) +{ + ospf_lsa_unlock (nbr->ls_req_last); + nbr->ls_req_last = NULL; + ospf_lsdb_delete_all (&nbr->ls_req); +} + +/* Lookup LSA from neighbor's ls-request list. */ +struct ospf_lsa * +ospf_ls_request_lookup (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + return ospf_lsdb_lookup (&nbr->ls_req, lsa); +} + +struct ospf_lsa * +ospf_ls_request_new (struct lsa_header *lsah) +{ + struct ospf_lsa *new; + + new = ospf_lsa_new (); + new->data = ospf_lsa_data_new (OSPF_LSA_HEADER_SIZE); + memcpy (new->data, lsah, OSPF_LSA_HEADER_SIZE); + + return new; +} + + +/* Management functions for neighbor's ls-retransmit list. */ +unsigned long +ospf_ls_retransmit_count (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_count_all (&nbr->ls_rxmt); +} + +unsigned long +ospf_ls_retransmit_count_self (struct ospf_neighbor *nbr, int lsa_type) +{ + return ospf_lsdb_count_self (&nbr->ls_rxmt, lsa_type); +} + +int +ospf_ls_retransmit_isempty (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_isempty (&nbr->ls_rxmt); +} + +/* Add LSA to be retransmitted to neighbor's ls-retransmit list. */ +void +ospf_ls_retransmit_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + struct ospf_lsa *old; + + old = ospf_ls_retransmit_lookup (nbr, lsa); + + if (ospf_lsa_more_recent (old, lsa) < 0) + { + if (old) + { + old->retransmit_counter--; + ospf_lsdb_delete (&nbr->ls_rxmt, old); + } + lsa->retransmit_counter++; + /* + * We cannot make use of the newly introduced callback function + * "lsdb->new_lsa_hook" to replace debug output below, just because + * it seems no simple and smart way to pass neighbor information to + * the common function "ospf_lsdb_add()" -- endo. + */ + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("RXmtL(%lu)++, NBR(%s), LSA[%s]", + ospf_ls_retransmit_count (nbr), + inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); + ospf_lsdb_add (&nbr->ls_rxmt, lsa); + } +} + +/* Remove LSA from neibghbor's ls-retransmit list. */ +void +ospf_ls_retransmit_delete (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + if (ospf_ls_retransmit_lookup (nbr, lsa)) + { + lsa->retransmit_counter--; + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) /* -- endo. */ + zlog_info ("RXmtL(%lu)--, NBR(%s), LSA[%s]", + ospf_ls_retransmit_count (nbr), + inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); + ospf_lsdb_delete (&nbr->ls_rxmt, lsa); + } +} + +/* Clear neighbor's ls-retransmit list. */ +void +ospf_ls_retransmit_clear (struct ospf_neighbor *nbr) +{ + struct ospf_lsdb *lsdb; + int i; + + lsdb = &nbr->ls_rxmt; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + { + struct route_table *table = lsdb->type[i].db; + struct route_node *rn; + struct ospf_lsa *lsa; + + for (rn = route_top (table); rn; rn = route_next (rn)) + if ((lsa = rn->info) != NULL) + ospf_ls_retransmit_delete (nbr, lsa); + } + + ospf_lsa_unlock (nbr->ls_req_last); + nbr->ls_req_last = NULL; +} + +/* Lookup LSA from neighbor's ls-retransmit list. */ +struct ospf_lsa * +ospf_ls_retransmit_lookup (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + return ospf_lsdb_lookup (&nbr->ls_rxmt, lsa); +} + +void +ospf_ls_retransmit_delete_nbr_if (struct ospf_interface *oi, + struct ospf_lsa *lsa) +{ + struct route_node *rn; + struct ospf_neighbor *nbr; + struct ospf_lsa *lsr; + + if (ospf_if_is_enable (oi)) + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + /* If LSA find in LS-retransmit list, then remove it. */ + if ((nbr = rn->info) != NULL) + { + lsr = ospf_ls_retransmit_lookup (nbr, lsa); + + /* If LSA find in ls-retransmit list, remove it. */ + if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum) + ospf_ls_retransmit_delete (nbr, lsr); + } +} + +void +ospf_ls_retransmit_delete_nbr_area (struct ospf_area *area, + struct ospf_lsa *lsa) +{ + listnode node; + + for (node = listhead (area->oiflist); node; nextnode (node)) + ospf_ls_retransmit_delete_nbr_if (getdata (node), lsa); +} + +void +ospf_ls_retransmit_delete_nbr_as (struct ospf *ospf, struct ospf_lsa *lsa) +{ + listnode node; + + for (node = listhead (ospf->oiflist); node; nextnode (node)) + ospf_ls_retransmit_delete_nbr_if (getdata (node), lsa); +} + + +/* Sets ls_age to MaxAge and floods throu the area. + When we implement ASE routing, there will be anothe function + flushing an LSA from the whole domain. */ +void +ospf_lsa_flush_area (struct ospf_lsa *lsa, struct ospf_area *area) +{ + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + ospf_flood_through_area (area, NULL, lsa); + ospf_lsa_maxage (area->ospf, lsa); +} + +void +ospf_lsa_flush_as (struct ospf *ospf, struct ospf_lsa *lsa) +{ + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + ospf_flood_through_as (ospf, NULL, lsa); + ospf_lsa_maxage (ospf, lsa); +} diff --git a/ospfd/ospf_flood.h b/ospfd/ospf_flood.h new file mode 100644 index 0000000..2e3f083 --- /dev/null +++ b/ospfd/ospf_flood.h @@ -0,0 +1,67 @@ +/* + * OSPF Flooding -- RFC2328 Section 13. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_FLOOD_H +#define _ZEBRA_OSPF_FLOOD_H + +int ospf_flood (struct ospf *, struct ospf_neighbor *, struct ospf_lsa *, + struct ospf_lsa *); +int ospf_flood_through (struct ospf *, struct ospf_neighbor *, + struct ospf_lsa *); +int ospf_flood_through_area (struct ospf_area *, struct ospf_neighbor *, + struct ospf_lsa *); +int ospf_flood_through_as (struct ospf *, struct ospf_neighbor *, + struct ospf_lsa *); + +unsigned long ospf_ls_request_count (struct ospf_neighbor *); +int ospf_ls_request_isempty (struct ospf_neighbor *); +struct ospf_lsa *ospf_ls_request_new (struct lsa_header *); +void ospf_ls_request_free (struct ospf_lsa *); +void ospf_ls_request_add (struct ospf_neighbor *, struct ospf_lsa *); +void ospf_ls_request_delete (struct ospf_neighbor *, struct ospf_lsa *); +void ospf_ls_request_delete_all (struct ospf_neighbor *); +struct ospf_lsa *ospf_ls_request_lookup (struct ospf_neighbor *, + struct ospf_lsa *); + +unsigned long ospf_ls_retransmit_count (struct ospf_neighbor *); +unsigned long ospf_ls_retransmit_count_self (struct ospf_neighbor *, int); +int ospf_ls_retransmit_isempty (struct ospf_neighbor *); +void ospf_ls_retransmit_add (struct ospf_neighbor *, struct ospf_lsa *); +void ospf_ls_retransmit_delete (struct ospf_neighbor *, struct ospf_lsa *); +void ospf_ls_retransmit_clear (struct ospf_neighbor *); +struct ospf_lsa *ospf_ls_retransmit_lookup (struct ospf_neighbor *, + struct ospf_lsa *); +void ospf_ls_retransmit_delete_nbr_area (struct ospf_area *, + struct ospf_lsa *); +void ospf_ls_retransmit_delete_nbr_as (struct ospf *, struct ospf_lsa *); +void ospf_ls_retransmit_add_nbr_all (struct ospf_interface *, + struct ospf_lsa *); + +void ospf_flood_lsa_area (struct ospf_lsa *, struct ospf_area *); +void ospf_flood_lsa_as (struct ospf_lsa *); +void ospf_lsa_flush_area (struct ospf_lsa *, struct ospf_area *); +void ospf_lsa_flush_as (struct ospf *, struct ospf_lsa *); +struct external_info *ospf_external_info_check (struct ospf_lsa *); + +void ospf_lsdb_init (struct ospf_lsdb *); + +#endif /* _ZEBRA_OSPF_FLOOD_H */ diff --git a/ospfd/ospf_ia.c b/ospfd/ospf_ia.c new file mode 100644 index 0000000..59f8666 --- /dev/null +++ b/ospfd/ospf_ia.c @@ -0,0 +1,727 @@ +/* + * OSPF inter-area routing. + * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + + +#include + +#include "thread.h" +#include "memory.h" +#include "hash.h" +#include "linklist.h" +#include "prefix.h" +#include "table.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_ia.h" +#include "ospfd/ospf_dump.h" + +#define DEBUG + +struct ospf_route * +ospf_find_abr_route (struct route_table *rtrs, + struct prefix_ipv4 *abr, + struct ospf_area *area) +{ + struct route_node *rn; + struct ospf_route *or; + listnode node; + + if ((rn = route_node_lookup (rtrs, (struct prefix *) abr)) == NULL) + return NULL; + + route_unlock_node (rn); + + for (node = listhead ((list) rn->info); node; nextnode (node)) + if ((or = getdata (node)) != NULL) + if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id) && (or->u.std.flags & ROUTER_LSA_BORDER)) + return or; + + return NULL; +} + +void +ospf_ia_network_route (struct ospf *ospf, struct route_table *rt, + struct prefix_ipv4 *p, struct ospf_route *new_or, + struct ospf_route *abr_or) +{ + struct route_node *rn1; + struct ospf_route *or; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_network_route(): processing summary route to %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + + /* Find a route to the same dest */ + if ((rn1 = route_node_lookup (rt, (struct prefix *) p))) + { + int res; + + route_unlock_node (rn1); + + if ((or = rn1->info)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_network_route(): " + "Found a route to the same network"); + /* Check the existing route. */ + if ((res = ospf_route_cmp (ospf, new_or, or)) < 0) + { + /* New route is better, so replace old one. */ + ospf_route_subst (rn1, new_or, abr_or); + } + else if (res == 0) + { + /* New and old route are equal, so next hops can be added. */ + route_lock_node (rn1); + ospf_route_copy_nexthops (or, abr_or->path); + route_unlock_node (rn1); + + /* new route can be deleted, because existing route has been updated. */ + ospf_route_free (new_or); + } + else + { + /* New route is worse, so free it. */ + ospf_route_free (new_or); + return; + } + } /* if (or)*/ + } /*if (rn1)*/ + else + { /* no route */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_network_route(): add new route to %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + ospf_route_add (rt, p, new_or, abr_or); + } +} + +void +ospf_ia_router_route (struct ospf *ospf, struct route_table *rtrs, + struct prefix_ipv4 *p, + struct ospf_route *new_or, struct ospf_route *abr_or) +{ + struct ospf_route *or = NULL; + struct route_node *rn; + int ret; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_router_route(): considering %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + /* Find a route to the same dest */ + rn = route_node_get (rtrs, (struct prefix *) p); + + if (rn->info == NULL) + /* This is a new route */ + rn->info = list_new (); + else + { + struct ospf_area *or_area; + or_area = ospf_area_lookup_by_area_id (ospf, new_or->u.std.area_id); + assert (or_area); + /* This is an additional route */ + route_unlock_node (rn); + or = ospf_find_asbr_route_through_area (rtrs, p, or_area); + } + + if (or) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_router_route(): " + "a route to the same ABR through the same area exists"); + /* New route is better */ + if ((ret = ospf_route_cmp (ospf, new_or, or)) < 0) + { + listnode_delete (rn->info, or); + ospf_route_free (or); + /* proceed down */ + } + /* Routes are the same */ + else if (ret == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_router_route(): merging the new route"); + + ospf_route_copy_nexthops (or, abr_or->path); + ospf_route_free (new_or); + return; + } + /* New route is worse */ + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_router_route(): skipping the new route"); + ospf_route_free (new_or); + return; + } + } + + ospf_route_copy_nexthops (new_or, abr_or->path); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_router_route(): adding the new route"); + + listnode_add (rn->info, new_or); +} + + +int +process_summary_lsa (struct ospf_area *area, struct route_table *rt, + struct route_table *rtrs, struct ospf_lsa *lsa) +{ + struct ospf *ospf = area->ospf; + struct ospf_area_range *range; + struct ospf_route *abr_or, *new_or; + struct summary_lsa *sl; + struct prefix_ipv4 p, abr; + u_int32_t metric; + + if (lsa == NULL) + return 0; + + sl = (struct summary_lsa *) lsa->data; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("process_summary_lsa(): LS ID: %s", inet_ntoa (sl->header.id)); + + metric = GET_METRIC (sl->metric); + + if (metric == OSPF_LS_INFINITY) + return 0; + + if (IS_LSA_MAXAGE (lsa)) + return 0; + + if (ospf_lsa_is_self_originated (area->ospf, lsa)) + return 0; + + p.family = AF_INET; + p.prefix = sl->header.id; + + if (sl->header.type == OSPF_SUMMARY_LSA) + p.prefixlen = ip_masklen (sl->mask); + else + p.prefixlen = IPV4_MAX_BITLEN; + + apply_mask_ipv4 (&p); + + if (sl->header.type == OSPF_SUMMARY_LSA && + (range = ospf_area_range_match_any (ospf, &p)) && + ospf_area_range_active (range)) + return 0; + + if (ospf->abr_type != OSPF_ABR_STAND && + area->external_routing != OSPF_AREA_DEFAULT && + p.prefix.s_addr == OSPF_DEFAULT_DESTINATION && + p.prefixlen == 0) + return 0; /* Ignore summary default from a stub area */ + + abr.family = AF_INET; + abr.prefix = sl->header.adv_router; + abr.prefixlen = IPV4_MAX_BITLEN; + apply_mask_ipv4 (&abr); + + abr_or = ospf_find_abr_route (rtrs, &abr, area); + + if (abr_or == NULL) + return 0; + + new_or = ospf_route_new (); + new_or->type = OSPF_DESTINATION_NETWORK; + new_or->id = sl->header.id; + new_or->mask = sl->mask; + new_or->u.std.options = sl->header.options; + new_or->u.std.origin = (struct lsa_header *) sl; + new_or->cost = abr_or->cost + metric; + new_or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + new_or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + new_or->path_type = OSPF_PATH_INTER_AREA; + + if (sl->header.type == OSPF_SUMMARY_LSA) + ospf_ia_network_route (ospf, rt, &p, new_or, abr_or); + else + { + new_or->type = OSPF_DESTINATION_ROUTER; + new_or->u.std.flags = ROUTER_LSA_EXTERNAL; + ospf_ia_router_route (ospf, rtrs, &p, new_or, abr_or); + } + + return 0; +} + +void +ospf_examine_summaries (struct ospf_area *area, + struct route_table *lsdb_rt, + struct route_table *rt, + struct route_table *rtrs) +{ + struct ospf_lsa *lsa; + struct route_node *rn; + + LSDB_LOOP (lsdb_rt, rn, lsa) + process_summary_lsa (area, rt, rtrs, lsa); +} + +int +ospf_area_is_transit (struct ospf_area *area) +{ + return (area->transit == OSPF_TRANSIT_TRUE) || + ospf_full_virtual_nbrs(area); /* Cisco forgets to set the V-bit :( */ +} + +void +ospf_update_network_route (struct ospf *ospf, + struct route_table *rt, + struct route_table *rtrs, + struct summary_lsa *lsa, + struct prefix_ipv4 *p, + struct ospf_area *area) +{ + struct route_node *rn; + struct ospf_route *or, *abr_or, *new_or; + struct prefix_ipv4 abr; + u_int32_t cost; + + abr.family = AF_INET; + abr.prefix =lsa->header.adv_router; + abr.prefixlen = IPV4_MAX_BITLEN; + apply_mask_ipv4 (&abr); + + abr_or = ospf_find_abr_route (rtrs, &abr, area); + + if (abr_or == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): can't find a route to the ABR"); + return; + } + + cost = abr_or->cost + GET_METRIC (lsa->metric); + + rn = route_node_lookup (rt, (struct prefix *) p); + + if (! rn) + { + if (ospf->abr_type != OSPF_ABR_SHORTCUT) + return; /* Standard ABR can update only already installed + backbone paths */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): " + "Allowing Shortcut ABR to add new route"); + new_or = ospf_route_new (); + new_or->type = OSPF_DESTINATION_NETWORK; + new_or->id = lsa->header.id; + new_or->mask = lsa->mask; + new_or->u.std.options = lsa->header.options; + new_or->u.std.origin = (struct lsa_header *) lsa; + new_or->cost = cost; + new_or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + new_or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + new_or->path_type = OSPF_PATH_INTER_AREA; + ospf_route_add (rt, p, new_or, abr_or); + + return; + } + else + { + route_unlock_node (rn); + if (rn->info == NULL) + return; + } + + or = rn->info; + + if (or->path_type != OSPF_PATH_INTRA_AREA && + or->path_type != OSPF_PATH_INTER_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): ERR: path type is wrong"); + return; + } + + if (ospf->abr_type == OSPF_ABR_SHORTCUT) + { + if (or->path_type == OSPF_PATH_INTRA_AREA && + !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): Shortcut: " + "this intra-area path is not backbone"); + return; + } + } + else /* Not Shortcut ABR */ + { + if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): " + "route is not BB-associated"); + return; /* We can update only BB routes */ + } + } + + if (or->cost < cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): new route is worse"); + return; + } + + if (or->cost == cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): " + "new route is same distance, adding nexthops"); + ospf_route_copy_nexthops (or, abr_or->path); + } + + if (or->cost > cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_network_route(): " + "new route is better, overriding nexthops"); + ospf_route_subst_nexthops (or, abr_or->path); + or->cost = cost; + + if ((ospf->abr_type == OSPF_ABR_SHORTCUT) && + !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) + { + or->path_type = OSPF_PATH_INTER_AREA; + or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + /* Note that we can do this only in Shortcut ABR mode, + because standard ABR must leave the route type and area + unchanged + */ + } + } +} + +void +ospf_update_router_route (struct ospf *ospf, + struct route_table *rtrs, + struct summary_lsa *lsa, + struct prefix_ipv4 *p, + struct ospf_area *area) +{ + struct ospf_route *or, *abr_or, *new_or; + struct prefix_ipv4 abr; + u_int32_t cost; + + abr.family = AF_INET; + abr.prefix = lsa->header.adv_router; + abr.prefixlen = IPV4_MAX_BITLEN; + apply_mask_ipv4 (&abr); + + abr_or = ospf_find_abr_route (rtrs, &abr, area); + + if (abr_or == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_update_router_route(): can't find a route to the ABR"); + return; + } + + cost = abr_or->cost + GET_METRIC (lsa->metric); + + /* First try to find a backbone path, + because standard ABR can update only BB-associated paths */ + + if ((ospf->backbone == NULL) && + (ospf->abr_type != OSPF_ABR_SHORTCUT)) + + /* no BB area, not Shortcut ABR, exiting */ + return; + + or = ospf_find_asbr_route_through_area (rtrs, p, ospf->backbone); + + if (or == NULL) + { + if (ospf->abr_type != OSPF_ABR_SHORTCUT) + + /* route to ASBR through the BB not found + the router is not Shortcut ABR, exiting */ + + return; + else + /* We're a Shortcut ABR*/ + { + /* Let it either add a new router or update the route + through the same (non-BB) area. */ + + new_or = ospf_route_new (); + new_or->type = OSPF_DESTINATION_ROUTER; + new_or->id = lsa->header.id; + new_or->mask = lsa->mask; + new_or->u.std.options = lsa->header.options; + new_or->u.std.origin = (struct lsa_header *)lsa; + new_or->cost = cost; + new_or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + new_or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + new_or->path_type = OSPF_PATH_INTER_AREA; + new_or->u.std.flags = ROUTER_LSA_EXTERNAL; + ospf_ia_router_route (ospf, rtrs, p, new_or, abr_or); + + return; + } + } + + /* At this point the "or" is always bb-associated */ + + if (!(or->u.std.flags & ROUTER_LSA_EXTERNAL)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_upd_router_route(): the remote router is not an ASBR"); + return; + } + + if (or->path_type != OSPF_PATH_INTRA_AREA && + or->path_type != OSPF_PATH_INTER_AREA) + return; + + if (or->cost < cost) + return; + + else if (or->cost == cost) + ospf_route_copy_nexthops (or, abr_or->path); + + else if (or->cost > cost) + { + ospf_route_subst_nexthops (or, abr_or->path); + or->cost = cost; + + /* Even if the ABR runs in Shortcut mode, we can't change + the path type and area, because the "or" is always bb-associated + at this point and even Shortcut ABR can't change these attributes */ + } +} + +int +process_transit_summary_lsa (struct ospf_area *area, struct route_table *rt, + struct route_table *rtrs, struct ospf_lsa *lsa) +{ + struct ospf *ospf = area->ospf; + struct summary_lsa *sl; + struct prefix_ipv4 p; + u_int32_t metric; + + if (lsa == NULL) + return 0; + + sl = (struct summary_lsa *) lsa->data; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("process_transit_summaries(): LS ID: %s", + inet_ntoa (lsa->data->id)); + metric = GET_METRIC (sl->metric); + + if (metric == OSPF_LS_INFINITY) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("process_transit_summaries(): metric is infinity, skip"); + return 0; + } + + if (IS_LSA_MAXAGE (lsa)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("process_transit_summaries(): This LSA is too old"); + return 0; + } + + if (ospf_lsa_is_self_originated (area->ospf, lsa)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("process_transit_summaries(): This LSA is mine, skip"); + return 0; + } + + p.family = AF_INET; + p.prefix = sl->header.id; + + if (sl->header.type == OSPF_SUMMARY_LSA) + p.prefixlen = ip_masklen (sl->mask); + else + p.prefixlen = IPV4_MAX_BITLEN; + + apply_mask_ipv4 (&p); + + if (sl->header.type == OSPF_SUMMARY_LSA) + ospf_update_network_route (ospf, rt, rtrs, sl, &p, area); + else + ospf_update_router_route (ospf, rtrs, sl, &p, area); + + return 0; +} + +void +ospf_examine_transit_summaries (struct ospf_area *area, + struct route_table *lsdb_rt, + struct route_table *rt, + struct route_table *rtrs) +{ + struct ospf_lsa *lsa; + struct route_node *rn; + + LSDB_LOOP (lsdb_rt, rn, lsa) + process_transit_summary_lsa (area, rt, rtrs, lsa); +} + +void +ospf_ia_routing (struct ospf *ospf, + struct route_table *rt, + struct route_table *rtrs) +{ + struct ospf_area * area; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing():start"); + + if (IS_OSPF_ABR (ospf)) + { + listnode node; + struct ospf_area *area; + + switch (ospf->abr_type) + { + case OSPF_ABR_STAND: + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing():Standard ABR"); + + if ((area = ospf->backbone)) + { + listnode node; + + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_ia_routing():backbone area found"); + zlog_info ("ospf_ia_routing():examining summaries"); + } + + OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); + + for (node = listhead (ospf->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + if (area != ospf->backbone) + if (ospf_area_is_transit (area)) + OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs); + } + else + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing():backbone area NOT found"); + break; + case OSPF_ABR_IBM: + case OSPF_ABR_CISCO: + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing():Alternative Cisco/IBM ABR"); + area = ospf->backbone; /* Find the BB */ + + /* If we have an active BB connection */ + if (area && ospf_act_bb_connection (ospf)) + { + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_ia_routing(): backbone area found"); + zlog_info ("ospf_ia_routing(): examining BB summaries"); + } + + OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); + + for (node = listhead (ospf->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + if (area != ospf->backbone) + if (ospf_area_is_transit (area)) + OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs); + } + else + { /* No active BB connection--consider all areas */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing(): " + "Active BB connection not found"); + for (node = listhead (ospf->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); + } + break; + case OSPF_ABR_SHORTCUT: + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing():Alternative Shortcut"); + area = ospf->backbone; /* Find the BB */ + + /* If we have an active BB connection */ + if (area && ospf_act_bb_connection (ospf)) + { + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_ia_routing(): backbone area found"); + zlog_info ("ospf_ia_routing(): examining BB summaries"); + } + OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); + } + + for (node = listhead (ospf->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + if (area != ospf->backbone) + if (ospf_area_is_transit (area) || + ((area->shortcut_configured != OSPF_SHORTCUT_DISABLE) && + ((ospf->backbone == NULL) || + ((area->shortcut_configured == OSPF_SHORTCUT_ENABLE) && + area->shortcut_capability)))) + OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs); + break; + default: + break; + } + } + else + { + listnode node; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ia_routing():not ABR, considering all areas"); + + for (node = listhead (ospf->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); + } +} diff --git a/ospfd/ospf_ia.h b/ospfd/ospf_ia.h new file mode 100644 index 0000000..4eb3c9d --- /dev/null +++ b/ospfd/ospf_ia.h @@ -0,0 +1,43 @@ +/* + * OSPF inter-area routing. + * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_IA_H +#define _ZEBRA_OSPF_IA_H + +/* Macros. */ +#define OSPF_EXAMINE_SUMMARIES_ALL(A,N,R) \ + { \ + ospf_examine_summaries ((A), SUMMARY_LSDB ((A)), (N), (R)); \ + ospf_examine_summaries ((A), ASBR_SUMMARY_LSDB ((A)), (N), (R)); \ + } + +#define OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL(A,N,R) \ + { \ + ospf_examine_transit_summaries ((A), SUMMARY_LSDB ((A)), (N), (R)); \ + ospf_examine_transit_summaries ((A), ASBR_SUMMARY_LSDB ((A)), (N), (R)); \ + } + +void ospf_ia_routing (struct ospf *, struct route_table *, + struct route_table *); +int ospf_area_is_transit (struct ospf_area *); + +#endif /* _ZEBRA_OSPF_IA_H */ diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c new file mode 100644 index 0000000..4e202ff --- /dev/null +++ b/ospfd/ospf_interface.c @@ -0,0 +1,1073 @@ +/* + * OSPF Interface functions. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "memory.h" +#include "command.h" +#include "stream.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_network.h" +#include "ospfd/ospf_dump.h" +#ifdef HAVE_SNMP +#include "ospfd/ospf_snmp.h" +#endif /* HAVE_SNMP */ + + +int +ospf_if_get_output_cost (struct ospf_interface *oi) +{ + /* If all else fails, use default OSPF cost */ + u_int32_t cost; + u_int32_t bw, refbw; + + bw = oi->ifp->bandwidth ? oi->ifp->bandwidth : OSPF_DEFAULT_BANDWIDTH; + refbw = oi->ospf->ref_bandwidth; + + /* A specifed ip ospf cost overrides a calculated one. */ + if (OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (oi->ifp), output_cost_cmd) || + OSPF_IF_PARAM_CONFIGURED (oi->params, output_cost_cmd)) + cost = OSPF_IF_PARAM (oi, output_cost_cmd); + /* See if a cost can be calculated from the zebra processes + interface bandwidth field. */ + else + { + cost = (u_int32_t) ((double)refbw / (double)bw + (double)0.5); + if (cost < 1) + cost = 1; + else if (cost > 65535) + cost = 65535; + } + + return cost; +} + +void +ospf_if_recalculate_output_cost (struct interface *ifp) +{ + u_int32_t newcost; + struct route_node *rn; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct ospf_interface *oi; + + if ( (oi = rn->info) == NULL) + continue; + + newcost = ospf_if_get_output_cost (oi); + + /* Is actual output cost changed? */ + if (oi->output_cost != newcost) + { + oi->output_cost = newcost; + ospf_router_lsa_timer_add (oi->area); + } + } +} + +void +ospf_if_reset_variables (struct ospf_interface *oi) +{ + /* Set default values. */ + /* don't clear this flag. oi->flag = OSPF_IF_DISABLE; */ + + if (oi->vl_data) + oi->type = OSPF_IFTYPE_VIRTUALLINK; + else + /* preserve network-type */ + if (oi->type != OSPF_IFTYPE_NBMA) + oi->type = OSPF_IFTYPE_BROADCAST; + + oi->state = ISM_Down; + + oi->crypt_seqnum = 0; + + /* This must be short, (less than RxmtInterval) + - RFC 2328 Section 13.5 para 3. Set to 1 second to avoid Acks being + held back for too long - MAG */ + oi->v_ls_ack = 1; +} + +void +ospf_add_to_if (struct interface *ifp, struct ospf_interface *oi) +{ + struct route_node *rn; + struct prefix p; + + p = *oi->address; + p.prefixlen = IPV4_MAX_PREFIXLEN; + + rn = route_node_get (IF_OIFS (ifp), &p); + assert (! rn->info); + rn->info = oi; +} + +void +ospf_delete_from_if (struct interface *ifp, struct ospf_interface *oi) +{ + struct route_node *rn; + struct prefix p; + + p = *oi->address; + p.prefixlen = IPV4_MAX_PREFIXLEN; + + rn = route_node_lookup (IF_OIFS (oi->ifp), &p); + assert (rn); + assert (rn->info); + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); +} + +struct ospf_interface * +ospf_if_new (struct ospf *ospf, struct interface *ifp, struct prefix *p) +{ + struct ospf_interface *oi; + + oi = XCALLOC (MTYPE_OSPF_IF, sizeof (struct ospf_interface)); + memset (oi, 0, sizeof (struct ospf_interface)); + + /* Set zebra interface pointer. */ + oi->ifp = ifp; + oi->address = p; + + ospf_add_to_if (ifp, oi); + listnode_add (ospf->oiflist, oi); + + /* Clear self-originated network-LSA. */ + oi->network_lsa_self = NULL; + + /* Initialize neighbor list. */ + oi->nbrs = route_table_init (); + + /* Initialize static neighbor list. */ + oi->nbr_nbma = list_new (); + + /* Initialize Link State Acknowledgment list. */ + oi->ls_ack = list_new (); + oi->ls_ack_direct.ls_ack = list_new (); + + /* Set default values. */ + ospf_if_reset_variables (oi); + + /* Add pseudo neighbor. */ + oi->nbr_self = ospf_nbr_new (oi); + oi->nbr_self->state = NSM_TwoWay; + oi->nbr_self->priority = OSPF_IF_PARAM (oi, priority); + oi->nbr_self->options = OSPF_OPTION_E; + + oi->ls_upd_queue = route_table_init (); + oi->t_ls_upd_event = NULL; + oi->t_ls_ack_direct = NULL; + + oi->crypt_seqnum = time (NULL); + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_type9_lsa_init (oi); +#endif /* HAVE_OPAQUE_LSA */ + + oi->ospf = ospf; + + return oi; +} + +/* Restore an interface to its pre UP state + Used from ism_interface_down only */ +void +ospf_if_cleanup (struct ospf_interface *oi) +{ + struct route_node *rn; + listnode node; + struct ospf_neighbor *nbr; + + /* oi->nbrs and oi->nbr_nbma should be deletete on InterafceDown event */ + /* delete all static neighbors attached to this interface */ + for (node = listhead (oi->nbr_nbma); node; ) + { + struct ospf_nbr_nbma *nbr_nbma = getdata (node); + nextnode (node); + + OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll); + + if (nbr_nbma->nbr) + { + nbr_nbma->nbr->nbr_nbma = NULL; + nbr_nbma->nbr = NULL; + } + + nbr_nbma->oi = NULL; + + listnode_delete (oi->nbr_nbma, nbr_nbma); + } + + /* send Neighbor event KillNbr to all associated neighbors. */ + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + if (nbr != oi->nbr_self) + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_KillNbr); + + /* Cleanup Link State Acknowlegdment list. */ + for (node = listhead (oi->ls_ack); node; nextnode (node)) + ospf_lsa_unlock (node->data); + list_delete_all_node (oi->ls_ack); + + oi->crypt_seqnum = 0; + + /* Empty link state update queue */ + ospf_ls_upd_queue_empty (oi); + + /* Handle pseudo neighbor. */ + ospf_nbr_delete (oi->nbr_self); + oi->nbr_self = ospf_nbr_new (oi); + oi->nbr_self->state = NSM_TwoWay; + oi->nbr_self->priority = OSPF_IF_PARAM (oi, priority); + oi->nbr_self->router_id = oi->ospf->router_id; + oi->nbr_self->src = oi->address->u.prefix4; + oi->nbr_self->address = *oi->address; + + switch (oi->area->external_routing) + { + case OSPF_AREA_DEFAULT: + SET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + break; + case OSPF_AREA_STUB: + UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + break; +#ifdef HAVE_NSSA + case OSPF_AREA_NSSA: + UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + SET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP); + break; +#endif /* HAVE_NSSA */ + } + + ospf_nbr_add_self (oi); + ospf_lsa_unlock (oi->network_lsa_self); + oi->network_lsa_self = NULL; + OSPF_TIMER_OFF (oi->t_network_lsa_self); +} + +void +ospf_if_free (struct ospf_interface *oi) +{ + ospf_if_down (oi); + + assert (oi->state == ISM_Down); + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_type9_lsa_term (oi); +#endif /* HAVE_OPAQUE_LSA */ + + /* Free Pseudo Neighbour */ + ospf_nbr_delete (oi->nbr_self); + + route_table_finish (oi->nbrs); + route_table_finish (oi->ls_upd_queue); + + /* Free any lists that should be freed */ + list_free (oi->nbr_nbma); + + list_free (oi->ls_ack); + list_free (oi->ls_ack_direct.ls_ack); + + ospf_delete_from_if (oi->ifp, oi); + + listnode_delete (oi->ospf->oiflist, oi); + listnode_delete (oi->area->oiflist, oi); + + memset (oi, 0, sizeof (*oi)); + XFREE (MTYPE_OSPF_IF, oi); +} + + +/* +* check if interface with given address is configured and +* return it if yes. +*/ +struct ospf_interface * +ospf_if_is_configured (struct ospf *ospf, struct in_addr *address) +{ + listnode node; + struct ospf_interface *oi; + struct prefix *addr; + + for (node = listhead (ospf->oiflist); node; nextnode (node)) + if ((oi = getdata (node)) != NULL && oi->type != OSPF_IFTYPE_VIRTUALLINK) + { + if (oi->type == OSPF_IFTYPE_POINTOPOINT) + addr = oi->connected->destination; + else + addr = oi->address; + + if (IPV4_ADDR_SAME (address, &addr->u.prefix4)) + return oi; + } + + return NULL; +} + +int +ospf_if_is_up (struct ospf_interface *oi) +{ + return if_is_up (oi->ifp); +} + +struct ospf_interface * +ospf_if_lookup_by_local_addr (struct ospf *ospf, + struct interface *ifp, struct in_addr address) +{ + listnode node; + struct ospf_interface *oi; + + for (node = listhead (ospf->oiflist); node; nextnode (node)) + if ((oi = getdata (node)) != NULL && oi->type != OSPF_IFTYPE_VIRTUALLINK) + { + if (ifp && oi->ifp != ifp) + continue; + + if (IPV4_ADDR_SAME (&address, &oi->address->u.prefix4)) + return oi; + } + + return NULL; +} + +struct ospf_interface * +ospf_if_lookup_by_prefix (struct ospf *ospf, struct prefix_ipv4 *p) +{ + listnode node; + struct ospf_interface *oi; + struct prefix ptmp; + + /* Check each Interface. */ + for (node = listhead (ospf->oiflist); node; nextnode (node)) + { + if ((oi = getdata (node)) != NULL && oi->type != OSPF_IFTYPE_VIRTUALLINK) + { + if (oi->type == OSPF_IFTYPE_POINTOPOINT) + { + prefix_copy (&ptmp, oi->connected->destination); + ptmp.prefixlen = IPV4_MAX_BITLEN; + } + else + prefix_copy (&ptmp, oi->address); + + apply_mask (&ptmp); + if (prefix_same (&ptmp, (struct prefix *) p)) + return oi; + } + } + return NULL; +} + +/* determine receiving interface by source of packet */ +struct ospf_interface * +ospf_if_lookup_recv_if (struct ospf *ospf, struct in_addr src) +{ + listnode node; + struct prefix_ipv4 addr; + struct ospf_interface *oi, *match; + + addr.family = AF_INET; + addr.prefix = src; + addr.prefixlen = IPV4_MAX_BITLEN; + + match = NULL; + + for (node = listhead (ospf->oiflist); node; nextnode (node)) + { + oi = getdata (node); + + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + continue; + + if (oi->type == OSPF_IFTYPE_POINTOPOINT) + { + if (IPV4_ADDR_SAME (&oi->connected->destination->u.prefix4, &src)) + return oi; + } + else + { + if (prefix_match (oi->address, (struct prefix *) &addr)) + match = oi; + } + } + + return match; +} + +void +ospf_if_stream_set (struct ospf_interface *oi) +{ + /* set output fifo queue. */ + if (oi->obuf == NULL) + oi->obuf = ospf_fifo_new (); +} + +void +ospf_if_stream_unset (struct ospf_interface *oi) +{ + struct ospf *ospf = oi->ospf; + + if (oi->obuf) + { + ospf_fifo_free (oi->obuf); + oi->obuf = NULL; + + if (oi->on_write_q) + { + listnode_delete (ospf->oi_write_q, oi); + if (list_isempty(ospf->oi_write_q)) + OSPF_TIMER_OFF (ospf->t_write); + oi->on_write_q = 0; + } + } +} + + +struct ospf_if_params * +ospf_new_if_params () +{ + struct ospf_if_params *oip; + + oip = XMALLOC (MTYPE_OSPF_IF_PARAMS, sizeof (struct ospf_if_params)); + memset (oip, 0, sizeof (struct ospf_if_params)); + + if (!oip) + return NULL; + + memset (oip, 0, sizeof (struct ospf_if_params)); + + UNSET_IF_PARAM (oip, output_cost_cmd); + UNSET_IF_PARAM (oip, transmit_delay); + UNSET_IF_PARAM (oip, retransmit_interval); + UNSET_IF_PARAM (oip, passive_interface); + UNSET_IF_PARAM (oip, v_hello); + UNSET_IF_PARAM (oip, v_wait); + UNSET_IF_PARAM (oip, priority); + UNSET_IF_PARAM (oip, type); + UNSET_IF_PARAM (oip, auth_simple); + UNSET_IF_PARAM (oip, auth_crypt); + UNSET_IF_PARAM (oip, auth_type); + + oip->auth_crypt = list_new (); + + return oip; +} + +void +ospf_del_if_params (struct ospf_if_params *oip) +{ + list_delete (oip->auth_crypt); + XFREE (MTYPE_OSPF_IF_PARAMS, oip); +} + +void +ospf_free_if_params (struct interface *ifp, struct in_addr addr) +{ + struct ospf_if_params *oip; + struct prefix_ipv4 p; + struct route_node *rn; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = addr; + rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*)&p); + if (!rn || !rn->info) + return; + + oip = rn->info; + route_unlock_node (rn); + + if (!OSPF_IF_PARAM_CONFIGURED (oip, output_cost_cmd) && + !OSPF_IF_PARAM_CONFIGURED (oip, transmit_delay) && + !OSPF_IF_PARAM_CONFIGURED (oip, retransmit_interval) && + !OSPF_IF_PARAM_CONFIGURED (oip, passive_interface) && + !OSPF_IF_PARAM_CONFIGURED (oip, v_hello) && + !OSPF_IF_PARAM_CONFIGURED (oip, v_wait) && + !OSPF_IF_PARAM_CONFIGURED (oip, priority) && + !OSPF_IF_PARAM_CONFIGURED (oip, type) && + !OSPF_IF_PARAM_CONFIGURED (oip, auth_simple) && + !OSPF_IF_PARAM_CONFIGURED (oip, auth_type) && + listcount (oip->auth_crypt) == 0) + { + ospf_del_if_params (oip); + rn->info = NULL; + route_unlock_node (rn); + } +} + +struct ospf_if_params * +ospf_lookup_if_params (struct interface *ifp, struct in_addr addr) +{ + struct prefix_ipv4 p; + struct route_node *rn; + + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = addr; + + rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*)&p); + + if (rn) + { + route_unlock_node (rn); + return rn->info; + } + + return NULL; +} + +struct ospf_if_params * +ospf_get_if_params (struct interface *ifp, struct in_addr addr) +{ + struct prefix_ipv4 p; + struct route_node *rn; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = addr; + + rn = route_node_get (IF_OIFS_PARAMS (ifp), (struct prefix*)&p); + + if (rn->info == NULL) + rn->info = ospf_new_if_params (); + else + route_unlock_node (rn); + + return rn->info; +} + +void +ospf_if_update_params (struct interface *ifp, struct in_addr addr) +{ + struct route_node *rn; + struct ospf_interface *oi; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + if ((oi = rn->info) == NULL) + continue; + + if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &addr)) + oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4); + } +} + +int +ospf_if_new_hook (struct interface *ifp) +{ + int rc = 0; + + ifp->info = XMALLOC (MTYPE_OSPF_IF_INFO, sizeof (struct ospf_if_info)); + memset (ifp->info, 0, sizeof (struct ospf_if_info)); + + IF_OIFS (ifp) = route_table_init (); + IF_OIFS_PARAMS (ifp) = route_table_init (); + + IF_DEF_PARAMS (ifp) = ospf_new_if_params (); + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), transmit_delay); + IF_DEF_PARAMS (ifp)->transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), retransmit_interval); + IF_DEF_PARAMS (ifp)->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), priority); + IF_DEF_PARAMS (ifp)->priority = OSPF_ROUTER_PRIORITY_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), passive_interface); + IF_DEF_PARAMS (ifp)->passive_interface = OSPF_IF_ACTIVE; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello); + IF_DEF_PARAMS (ifp)->v_hello = OSPF_HELLO_INTERVAL_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait); + IF_DEF_PARAMS (ifp)->v_wait = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_simple); + memset (IF_DEF_PARAMS (ifp)->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE); + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_crypt); + IF_DEF_PARAMS (ifp)->auth_crypt = list_new (); + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type); + IF_DEF_PARAMS (ifp)->auth_type = OSPF_AUTH_NOTSET; + +#ifdef HAVE_OPAQUE_LSA + rc = ospf_opaque_new_if (ifp); +#endif /* HAVE_OPAQUE_LSA */ + return rc; +} + +int +ospf_if_delete_hook (struct interface *ifp) +{ + int rc = 0; +#ifdef HAVE_OPAQUE_LSA + rc = ospf_opaque_del_if (ifp); +#endif /* HAVE_OPAQUE_LSA */ + route_table_finish (IF_OIFS (ifp)); + route_table_finish (IF_OIFS_PARAMS (ifp)); + XFREE (MTYPE_OSPF_IF_INFO, ifp->info); + ifp->info = NULL; + + return rc; +} + +int +ospf_if_is_enable (struct ospf_interface *oi) +{ + if (!if_is_loopback (oi->ifp)) + if (if_is_up (oi->ifp)) + return 1; + + return 0; +} + +int +ospf_if_up (struct ospf_interface *oi) +{ + if (oi == NULL) + return 0; + + if (oi->type == OSPF_IFTYPE_LOOPBACK) + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_LoopInd); + else + { + if (oi->type != OSPF_IFTYPE_VIRTUALLINK) + ospf_if_add_allspfrouters (oi->ospf, oi->address, oi->ifp->ifindex); + ospf_if_stream_set (oi); + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceUp); + } + + return 1; +} + +int +ospf_if_down (struct ospf_interface *oi) +{ + if (oi == NULL) + return 0; + + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); + /* Shutdown packet reception and sending */ + ospf_if_stream_unset (oi); + if (oi->type != OSPF_IFTYPE_VIRTUALLINK) + ospf_if_drop_allspfrouters (oi->ospf, oi->address, oi->ifp->ifindex); + + + return 1; +} + + +/* Virtual Link related functions. */ + +struct ospf_vl_data * +ospf_vl_data_new (struct ospf_area *area, struct in_addr vl_peer) +{ + struct ospf_vl_data *vl_data; + + vl_data = XMALLOC (MTYPE_OSPF_VL_DATA, sizeof (struct ospf_vl_data)); + memset (vl_data, 0, sizeof (struct ospf_vl_data)); + + vl_data->vl_peer.s_addr = vl_peer.s_addr; + vl_data->vl_area_id = area->area_id; + vl_data->format = area->format; + + return vl_data; +} + +void +ospf_vl_data_free (struct ospf_vl_data *vl_data) +{ + XFREE (MTYPE_OSPF_VL_DATA, vl_data); +} + +u_int vlink_count = 0; + +struct ospf_interface * +ospf_vl_new (struct ospf *ospf, struct ospf_vl_data *vl_data) +{ + struct ospf_interface * voi; + struct interface * vi; + char ifname[INTERFACE_NAMSIZ + 1]; + struct ospf_area *area; + struct in_addr area_id; + struct connected *co; + struct prefix_ipv4 *p; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): Start"); + if (vlink_count == OSPF_VL_MAX_COUNT) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): Alarm: " + "cannot create more than OSPF_MAX_VL_COUNT virtual links"); + return NULL; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): creating pseudo zebra interface"); + + vi = if_create (); + co = connected_new (); + co->ifp = vi; + listnode_add (vi->connected, co); + + p = prefix_ipv4_new (); + p->family = AF_INET; + p->prefix.s_addr = 0; + p->prefixlen = 0; + + co->address = (struct prefix *)p; + + voi = ospf_if_new (ospf, vi, co->address); + if (voi == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): Alarm: OSPF int structure is not created"); + return NULL; + } + voi->connected = co; + voi->vl_data = vl_data; + voi->ifp->mtu = OSPF_VL_MTU; + voi->type = OSPF_IFTYPE_VIRTUALLINK; + + sprintf (ifname, "VLINK%d", vlink_count++); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): Created name: %s", ifname); + strncpy (vi->name, ifname, IFNAMSIZ); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): set if->name to %s", vi->name); + + area_id.s_addr = 0; + area = ospf_area_get (ospf, area_id, OSPF_AREA_ID_FORMAT_ADDRESS); + voi->area = area; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): set associated area to the backbone"); + + ospf_area_add_if (voi->area, voi); + + ospf_if_stream_set (voi); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_new(): Stop"); + return voi; +} + +void +ospf_vl_if_delete (struct ospf_vl_data *vl_data) +{ + struct interface *ifp = vl_data->vl_oi->ifp; + vl_data->vl_oi->address->u.prefix4.s_addr = 0; + vl_data->vl_oi->address->prefixlen = 0; + ospf_if_free (vl_data->vl_oi); + if_delete (ifp); + vlink_count--; +} + +struct ospf_vl_data * +ospf_vl_lookup (struct ospf_area *area, struct in_addr vl_peer) +{ + struct ospf_vl_data *vl_data; + listnode node; + + for (node = listhead (area->ospf->vlinks); node; nextnode (node)) + if ((vl_data = getdata (node)) != NULL) + if (vl_data->vl_peer.s_addr == vl_peer.s_addr && + IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) + return vl_data; + + return NULL; +} + +void +ospf_vl_shutdown (struct ospf_vl_data *vl_data) +{ + struct ospf_interface *oi; + + if ((oi = vl_data->vl_oi) == NULL) + return; + + oi->address->u.prefix4.s_addr = 0; + oi->address->prefixlen = 0; + + UNSET_FLAG (oi->ifp->flags, IFF_UP); + /* OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceDown); */ + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); +} + +void +ospf_vl_add (struct ospf *ospf, struct ospf_vl_data *vl_data) +{ + listnode_add (ospf->vlinks, vl_data); +#ifdef HAVE_SNMP + ospf_snmp_vl_add (vl_data); +#endif /* HAVE_SNMP */ +} + +void +ospf_vl_delete (struct ospf *ospf, struct ospf_vl_data *vl_data) +{ + ospf_vl_shutdown (vl_data); + ospf_vl_if_delete (vl_data); + +#ifdef HAVE_SNMP + ospf_snmp_vl_delete (vl_data); +#endif /* HAVE_SNMP */ + listnode_delete (ospf->vlinks, vl_data); + + ospf_vl_data_free (vl_data); +} + +void +ospf_vl_set_params (struct ospf_vl_data *vl_data, struct vertex *v) +{ + int changed = 0; + struct ospf_interface *voi; + listnode node; + struct vertex_nexthop *nh; + int i; + struct router_lsa *rl; + + voi = vl_data->vl_oi; + + if (voi->output_cost != v->distance) + { + voi->output_cost = v->distance; + changed = 1; + } + + for (node = listhead (v->nexthop); node; nextnode (node)) + if ((nh = getdata (node)) != NULL) + { + vl_data->out_oi = (struct ospf_interface *) nh->oi; + + voi->address->u.prefix4 = vl_data->out_oi->address->u.prefix4; + voi->address->prefixlen = vl_data->out_oi->address->prefixlen; + + break; /* We take the first interface. */ + } + + rl = (struct router_lsa *)v->lsa; + + for (i = 0; i < ntohs (rl->links); i++) + { + switch (rl->link[i].type) + { + case LSA_LINK_TYPE_VIRTUALLINK: + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("found back link through VL"); + case LSA_LINK_TYPE_TRANSIT: + case LSA_LINK_TYPE_POINTOPOINT: + vl_data->peer_addr = rl->link[i].link_data; + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("%s peer address is %s\n", + vl_data->vl_oi->ifp->name, inet_ntoa(vl_data->peer_addr)); + return; + } + } +} + + +void +ospf_vl_up_check (struct ospf_area *area, struct in_addr rid, + struct vertex *v) +{ + struct ospf *ospf = area->ospf; + listnode node; + struct ospf_vl_data *vl_data; + struct ospf_interface *oi; + + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_vl_up_check(): Start"); + zlog_info ("ospf_vl_up_check(): Router ID is %s", inet_ntoa (rid)); + zlog_info ("ospf_vl_up_check(): Area is %s", inet_ntoa (area->area_id)); + } + + for (node = listhead (ospf->vlinks); node; nextnode (node)) + { + if ((vl_data = getdata (node)) == NULL) + continue; + + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_vl_up_check(): considering VL, name: %s", + vl_data->vl_oi->ifp->name); + zlog_info ("ospf_vl_up_check(): VL area: %s, peer ID: %s", + inet_ntoa (vl_data->vl_area_id), + inet_ntoa (vl_data->vl_peer)); + } + + if (IPV4_ADDR_SAME (&vl_data->vl_peer, &rid) && + IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) + { + oi = vl_data->vl_oi; + SET_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_up_check(): this VL matched"); + + if (oi->state == ISM_Down) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_vl_up_check(): VL is down, waking it up"); + SET_FLAG (oi->ifp->flags, IFF_UP); + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceUp); + } + + ospf_vl_set_params (vl_data, v); + } + } +} + +void +ospf_vl_unapprove (struct ospf *ospf) +{ + listnode node; + struct ospf_vl_data *vl_data; + + for (node = listhead (ospf->vlinks); node; nextnode (node)) + if ((vl_data = getdata (node)) != NULL) + UNSET_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED); +} + +void +ospf_vl_shut_unapproved (struct ospf *ospf) +{ + listnode node; + struct ospf_vl_data *vl_data; + + for (node = listhead (ospf->vlinks); node; nextnode (node)) + if ((vl_data = getdata (node)) != NULL) + if (!CHECK_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED)) + ospf_vl_shutdown (vl_data); +} + +int +ospf_full_virtual_nbrs (struct ospf_area *area) +{ + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("counting fully adjacent virtual neighbors in area %s", + inet_ntoa (area->area_id)); + zlog_info ("there are %d of them", area->full_vls); + } + + return area->full_vls; +} + +int +ospf_vls_in_area (struct ospf_area *area) +{ + listnode node; + struct ospf_vl_data *vl_data; + int c = 0; + + for (node = listhead (area->ospf->vlinks); node; nextnode (node)) + if ((vl_data = getdata (node)) != NULL) + if (IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) + c++; + + return c; +} + + +struct crypt_key * +ospf_crypt_key_new () +{ + struct crypt_key *ck; + + ck = XMALLOC (MTYPE_OSPF_CRYPT_KEY, sizeof (struct crypt_key)); + memset (ck, 0, sizeof (struct crypt_key)); + + return ck; +} + +void +ospf_crypt_key_add (list crypt, struct crypt_key *ck) +{ + listnode_add (crypt, ck); +} + +struct crypt_key * +ospf_crypt_key_lookup (list auth_crypt, u_char key_id) +{ + listnode node; + struct crypt_key *ck; + + for (node = listhead (auth_crypt); node; nextnode (node)) + { + ck = getdata (node); + if (ck->key_id == key_id) + return ck; + } + + return NULL; +} + +int +ospf_crypt_key_delete (list auth_crypt, u_char key_id) +{ + listnode node; + struct crypt_key *ck; + + for (node = listhead (auth_crypt); node; nextnode (node)) + { + ck = getdata (node); + if (ck->key_id == key_id) + { + listnode_delete (auth_crypt, ck); + return 1; + } + } + + return 0; +} + +void +ospf_if_init () +{ + /* Initialize Zebra interface data structure. */ + if_init (); + om->iflist = iflist; + if_add_hook (IF_NEW_HOOK, ospf_if_new_hook); + if_add_hook (IF_DELETE_HOOK, ospf_if_delete_hook); +} diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h new file mode 100644 index 0000000..1dc0ce7 --- /dev/null +++ b/ospfd/ospf_interface.h @@ -0,0 +1,249 @@ +/* + * OSPF Interface functions. + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_INTERFACE_H +#define _ZEBRA_OSPF_INTERFACE_H + +#define OSPF_AUTH_SIMPLE_SIZE 8 +#define OSPF_AUTH_MD5_SIZE 16 + +#define IF_OSPF_IF_INFO(I) ((struct ospf_if_info *)((I)->info)) +#define IF_DEF_PARAMS(I) (IF_OSPF_IF_INFO (I)->def_params) +#define IF_OIFS(I) (IF_OSPF_IF_INFO (I)->oifs) +#define IF_OIFS_PARAMS(I) (IF_OSPF_IF_INFO (I)->params) + +#define OSPF_IF_PARAM_CONFIGURED(S, P) ((S) && (S)->P##__config) +#define OSPF_IF_PARAM(O, P) \ + (OSPF_IF_PARAM_CONFIGURED ((O)->params, P)?\ + (O)->params->P:IF_DEF_PARAMS((O)->ifp)->P) + +#define DECLARE_IF_PARAM(T, P) T P; u_char P##__config:1 +#define UNSET_IF_PARAM(S, P) ((S)->P##__config) = 0 +#define SET_IF_PARAM(S, P) ((S)->P##__config) = 1 + +struct ospf_if_params +{ + DECLARE_IF_PARAM (u_int32_t, transmit_delay); /* Interface Transmisson Delay */ + DECLARE_IF_PARAM (u_int32_t, output_cost_cmd);/* Command Interface Output Cost */ + DECLARE_IF_PARAM (u_int32_t, retransmit_interval); /* Retransmission Interval */ + DECLARE_IF_PARAM (u_char, passive_interface); /* OSPF Interface is passive */ + DECLARE_IF_PARAM (u_char, priority); /* OSPF Interface priority */ + DECLARE_IF_PARAM (u_char, type); /* type of interface */ +#define OSPF_IF_ACTIVE 0 +#define OSPF_IF_PASSIVE 1 + + DECLARE_IF_PARAM (u_int32_t, v_hello); /* Hello Interval */ + DECLARE_IF_PARAM (u_int32_t, v_wait); /* Router Dead Interval */ + + /* Authentication data. */ + u_char auth_simple[OSPF_AUTH_SIMPLE_SIZE + 1]; /* Simple password. */ + u_char auth_simple__config:1; + + DECLARE_IF_PARAM (list, auth_crypt); /* List of Auth cryptographic data. */ + DECLARE_IF_PARAM (int, auth_type); /* OSPF authentication type */ +}; + +struct ospf_if_info +{ + struct ospf_if_params *def_params; + struct route_table *params; + struct route_table *oifs; +}; + +struct ospf_interface; + +struct ospf_vl_data +{ + struct in_addr vl_peer; /* Router-ID of the peer for VLs. */ + struct in_addr vl_area_id; /* Transit area for this VL. */ + int format; /* area ID format */ + struct ospf_interface *vl_oi; /* Interface data structure for the VL. */ + struct ospf_interface *out_oi; /* The interface to go out. */ + struct in_addr peer_addr; /* Address used to reach the peer. */ + u_char flags; +}; + + +#define OSPF_VL_MAX_COUNT 256 +#define OSPF_VL_MTU 1500 + +#define OSPF_VL_FLAG_APPROVED 0x01 + +struct crypt_key +{ + u_char key_id; + u_char auth_key[OSPF_AUTH_MD5_SIZE + 1]; +}; + +/* OSPF interface structure. */ +struct ospf_interface +{ + /* This interface's parent ospf instance. */ + struct ospf *ospf; + + /* OSPF Area. */ + struct ospf_area *area; + + /* Interface data from zebra. */ + struct interface *ifp; + struct ospf_vl_data *vl_data; /* Data for Virtual Link */ + + /* Packet send buffer. */ + struct ospf_fifo *obuf; /* Output queue */ + + /* OSPF Network Type. */ + u_char type; +#define OSPF_IFTYPE_NONE 0 +#define OSPF_IFTYPE_POINTOPOINT 1 +#define OSPF_IFTYPE_BROADCAST 2 +#define OSPF_IFTYPE_NBMA 3 +#define OSPF_IFTYPE_POINTOMULTIPOINT 4 +#define OSPF_IFTYPE_VIRTUALLINK 5 +#define OSPF_IFTYPE_LOOPBACK 6 +#define OSPF_IFTYPE_MAX 7 + + /* State of Interface State Machine. */ + u_char state; + + struct prefix *address; /* Interface prefix */ + struct connected *connected; /* Pointer to connected */ + + /* Configured varables. */ + struct ospf_if_params *params; + u_int32_t crypt_seqnum; /* Cryptographic Sequence Number */ + u_int32_t output_cost; /* Acutual Interface Output Cost */ + + /* Neighbor information. */ + struct route_table *nbrs; /* OSPF Neighbor List */ + struct ospf_neighbor *nbr_self; /* Neighbor Self */ +#define DR(I) ((I)->nbr_self->d_router) +#define BDR(I) ((I)->nbr_self->bd_router) +#define OPTIONS(I) ((I)->nbr_self->options) +#define PRIORITY(I) ((I)->nbr_self->priority) + + /* List of configured NBMA neighbor. */ + list nbr_nbma; + + /* self-originated LSAs. */ + struct ospf_lsa *network_lsa_self; /* network-LSA. */ +#ifdef HAVE_OPAQUE_LSA + list opaque_lsa_self; /* Type-9 Opaque-LSAs */ +#endif /* HAVE_OPAQUE_LSA */ + + struct route_table *ls_upd_queue; + + list ls_ack; /* Link State Acknowledgment list. */ + + struct + { + list ls_ack; + struct in_addr dst; + } ls_ack_direct; + + /* Timer values. */ + u_int32_t v_ls_ack; /* Delayed Link State Acknowledgment */ + + /* Threads. */ + struct thread *t_hello; /* timer */ + struct thread *t_wait; /* timer */ + struct thread *t_ls_ack; /* timer */ + struct thread *t_ls_ack_direct; /* event */ + struct thread *t_ls_upd_event; /* event */ + struct thread *t_network_lsa_self; /* self-originated network-LSA + reflesh thread. timer */ +#ifdef HAVE_OPAQUE_LSA + struct thread *t_opaque_lsa_self; /* Type-9 Opaque-LSAs */ +#endif /* HAVE_OPAQUE_LSA */ + + int on_write_q; + + /* Statistics fields. */ + u_int32_t hello_in; /* Hello message input count. */ + u_int32_t hello_out; /* Hello message output count. */ + u_int32_t db_desc_in; /* database desc. message input count. */ + u_int32_t db_desc_out; /* database desc. message output count. */ + u_int32_t ls_req_in; /* LS request message input count. */ + u_int32_t ls_req_out; /* LS request message output count. */ + u_int32_t ls_upd_in; /* LS update message input count. */ + u_int32_t ls_upd_out; /* LS update message output count. */ + u_int32_t ls_ack_in; /* LS Ack message input count. */ + u_int32_t ls_ack_out; /* LS Ack message output count. */ + u_int32_t discarded; /* discarded input count by error. */ + u_int32_t state_change; /* Number of status change. */ + + u_int32_t full_nbrs; +}; + +/* Prototypes. */ +char *ospf_if_name (struct ospf_interface *); +struct ospf_interface *ospf_if_new (struct ospf *, struct interface *, + struct prefix *); +void ospf_if_cleanup (struct ospf_interface *); +void ospf_if_free (struct ospf_interface *); +int ospf_if_up (struct ospf_interface *); +int ospf_if_down (struct ospf_interface *); + +int ospf_if_is_up (struct ospf_interface *); +struct ospf_interface *ospf_if_lookup_by_name (char *); +struct ospf_interface *ospf_if_lookup_by_local_addr (struct ospf *, + struct interface *, + struct in_addr); +struct ospf_interface *ospf_if_lookup_by_prefix (struct ospf *, + struct prefix_ipv4 *); +struct ospf_interface *ospf_if_addr_local (struct in_addr); +struct ospf_interface *ospf_if_lookup_recv_if (struct ospf *, struct in_addr); +struct ospf_interface *ospf_if_is_configured (struct ospf *, struct in_addr *); + +struct ospf_if_params *ospf_lookup_if_params (struct interface *, + struct in_addr); +struct ospf_if_params *ospf_get_if_params (struct interface *, struct in_addr); +void ospf_del_if_params (struct ospf_if_params *); +void ospf_free_if_params (struct interface *, struct in_addr); +void ospf_if_update_params (struct interface *, struct in_addr); + +int ospf_if_new_hook (struct interface *); +void ospf_if_init (); +void ospf_if_stream_set (struct ospf_interface *); +void ospf_if_stream_unset (struct ospf_interface *); +void ospf_if_reset_variables (struct ospf_interface *); +int ospf_if_is_enable (struct ospf_interface *); +int ospf_if_get_output_cost (struct ospf_interface *); +void ospf_if_recalculate_output_cost (struct interface *); + +struct ospf_interface *ospf_vl_new (struct ospf *, struct ospf_vl_data *); +struct ospf_vl_data *ospf_vl_data_new (struct ospf_area *, struct in_addr); +struct ospf_vl_data *ospf_vl_lookup (struct ospf_area *, struct in_addr); +void ospf_vl_data_free (struct ospf_vl_data *); +void ospf_vl_add (struct ospf *, struct ospf_vl_data *); +void ospf_vl_delete (struct ospf *, struct ospf_vl_data *); +void ospf_vl_up_check (struct ospf_area *, struct in_addr, struct vertex *); +void ospf_vl_unapprove (struct ospf *); +void ospf_vl_shut_unapproved (struct ospf *); +int ospf_full_virtual_nbrs (struct ospf_area *); +int ospf_vls_in_area (struct ospf_area *); + +struct crypt_key *ospf_crypt_key_lookup (list, u_char); +struct crypt_key *ospf_crypt_key_new (); +void ospf_crypt_key_add (list, struct crypt_key *); +int ospf_crypt_key_delete (list, u_char); + +#endif /* _ZEBRA_OSPF_INTERFACE_H */ diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c new file mode 100644 index 0000000..c539231 --- /dev/null +++ b/ospfd/ospf_ism.c @@ -0,0 +1,652 @@ +/* + * OSPF version 2 Interface State Machine + * From RFC2328 [OSPF Version 2] + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_network.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_abr.h" + +/* elect DR and BDR. Refer to RFC2319 section 9.4 */ +struct ospf_neighbor * +ospf_dr_election_sub (list routers) +{ + listnode node; + struct ospf_neighbor *nbr, *max = NULL; + + /* Choose highest router priority. + In case of tie, choose highest Router ID. */ + for (node = listhead (routers); node; nextnode (node)) + { + nbr = getdata (node); + + if (max == NULL) + max = nbr; + else + { + if (max->priority < nbr->priority) + max = nbr; + else if (max->priority == nbr->priority) + if (IPV4_ADDR_CMP (&max->router_id, &nbr->router_id) < 0) + max = nbr; + } + } + + return max; +} + +struct ospf_neighbor * +ospf_elect_dr (struct ospf_interface *oi, list el_list) +{ + list dr_list; + listnode node; + struct ospf_neighbor *nbr, *dr = NULL, *bdr = NULL; + + dr_list = list_new (); + + /* Add neighbors to the list. */ + for (node = listhead (el_list); node; nextnode (node)) + { + nbr = getdata (node); + + /* neighbor declared to be DR. */ + if (NBR_IS_DR (nbr)) + listnode_add (dr_list, nbr); + + /* Preserve neighbor BDR. */ + if (IPV4_ADDR_SAME (&BDR (oi), &nbr->address.u.prefix4)) + bdr = nbr; + } + + /* Elect Designated Router. */ + if (listcount (dr_list) > 0) + dr = ospf_dr_election_sub (dr_list); + else + dr = bdr; + + /* Set DR to interface. */ + if (dr) + DR (oi) = dr->address.u.prefix4; + else + DR (oi).s_addr = 0; + + list_delete (dr_list); + + return dr; +} + +struct ospf_neighbor * +ospf_elect_bdr (struct ospf_interface *oi, list el_list) +{ + list bdr_list, no_dr_list; + listnode node; + struct ospf_neighbor *nbr, *bdr = NULL; + + bdr_list = list_new (); + no_dr_list = list_new (); + + /* Add neighbors to the list. */ + for (node = listhead (el_list); node; nextnode (node)) + { + nbr = getdata (node); + + /* neighbor declared to be DR. */ + if (NBR_IS_DR (nbr)) + continue; + + /* neighbor declared to be BDR. */ + if (NBR_IS_BDR (nbr)) + listnode_add (bdr_list, nbr); + + listnode_add (no_dr_list, nbr); + } + + /* Elect Backup Designated Router. */ + if (listcount (bdr_list) > 0) + bdr = ospf_dr_election_sub (bdr_list); + else + bdr = ospf_dr_election_sub (no_dr_list); + + /* Set BDR to interface. */ + if (bdr) + BDR (oi) = bdr->address.u.prefix4; + else + BDR (oi).s_addr = 0; + + list_delete (bdr_list); + list_delete (no_dr_list); + + return bdr; +} + +int +ospf_ism_state (struct ospf_interface *oi) +{ + if (IPV4_ADDR_SAME (&DR (oi), &oi->address->u.prefix4)) + return ISM_DR; + else if (IPV4_ADDR_SAME (&BDR (oi), &oi->address->u.prefix4)) + return ISM_Backup; + else + return ISM_DROther; +} + +void +ospf_dr_eligible_routers (struct route_table *nbrs, list el_list) +{ + struct route_node *rn; + struct ospf_neighbor *nbr; + + for (rn = route_top (nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + /* Ignore 0.0.0.0 node*/ + if (nbr->router_id.s_addr != 0) + /* Is neighbor eligible? */ + if (nbr->priority != 0) + /* Is neighbor upper 2-Way? */ + if (nbr->state >= NSM_TwoWay) + listnode_add (el_list, nbr); +} + +/* Generate AdjOK? NSM event. */ +void +ospf_dr_change (struct ospf *ospf, struct route_table *nbrs) +{ + struct route_node *rn; + struct ospf_neighbor *nbr; + + for (rn = route_top (nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + /* Ignore 0.0.0.0 node*/ + if (nbr->router_id.s_addr != 0) + /* Is neighbor upper 2-Way? */ + if (nbr->state >= NSM_TwoWay) + /* Ignore myself. */ + if (!IPV4_ADDR_SAME (&nbr->router_id, &ospf->router_id)) + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_AdjOK); +} + +int +ospf_dr_election (struct ospf_interface *oi) +{ + struct in_addr old_dr, old_bdr; + int old_state, new_state; + list el_list; + struct ospf_neighbor *dr, *bdr; + + /* backup current values. */ + old_dr = DR (oi); + old_bdr = BDR (oi); + old_state = oi->state; + + el_list = list_new (); + + /* List eligible routers. */ + ospf_dr_eligible_routers (oi->nbrs, el_list); + + /* First election of DR and BDR. */ + bdr = ospf_elect_bdr (oi, el_list); + dr = ospf_elect_dr (oi, el_list); + + new_state = ospf_ism_state (oi); + + zlog_info ("DR-Election[1st]: Backup %s", inet_ntoa (BDR (oi))); + zlog_info ("DR-Election[1st]: DR %s", inet_ntoa (DR (oi))); + + if (new_state != old_state && + !(new_state == ISM_DROther && old_state < ISM_DROther)) + { + ospf_elect_bdr (oi, el_list); + ospf_elect_dr (oi, el_list); + + new_state = ospf_ism_state (oi); + + zlog_info ("DR-Election[2nd]: Backup %s", inet_ntoa (BDR (oi))); + zlog_info ("DR-Election[2nd]: DR %s", inet_ntoa (DR (oi))); + } + + list_delete (el_list); + + /* if DR or BDR changes, cause AdjOK? neighbor event. */ + if (!IPV4_ADDR_SAME (&old_dr, &DR (oi)) || + !IPV4_ADDR_SAME (&old_bdr, &BDR (oi))) + ospf_dr_change (oi->ospf, oi->nbrs); + + if (oi->type == OSPF_IFTYPE_BROADCAST || oi->type == OSPF_IFTYPE_POINTOPOINT) + { + /* Multicast group change. */ + if ((old_state != ISM_DR && old_state != ISM_Backup) && + (new_state == ISM_DR || new_state == ISM_Backup)) + ospf_if_add_alldrouters (oi->ospf, oi->address, oi->ifp->ifindex); + else if ((old_state == ISM_DR || old_state == ISM_Backup) && + (new_state != ISM_DR && new_state != ISM_Backup)) + ospf_if_drop_alldrouters (oi->ospf, oi->address, oi->ifp->ifindex); + } + + return new_state; +} + + +int +ospf_hello_timer (struct thread *thread) +{ + struct ospf_interface *oi; + + oi = THREAD_ARG (thread); + oi->t_hello = NULL; + + if (IS_DEBUG_OSPF (ism, ISM_TIMERS)) + zlog (NULL, LOG_DEBUG, "ISM[%s]: Timer (Hello timer expire)", + IF_NAME (oi)); + + /* Sending hello packet. */ + ospf_hello_send (oi); + + /* Hello timer set. */ + OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, + OSPF_IF_PARAM (oi, v_hello)); + + return 0; +} + +int +ospf_wait_timer (struct thread *thread) +{ + struct ospf_interface *oi; + + oi = THREAD_ARG (thread); + oi->t_wait = NULL; + + if (IS_DEBUG_OSPF (ism, ISM_TIMERS)) + zlog (NULL, LOG_DEBUG, "ISM[%s]: Timer (Wait timer expire)", + IF_NAME (oi)); + + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_WaitTimer); + + return 0; +} + +/* Hook function called after ospf ISM event is occured. And vty's + network command invoke this function after making interface + structure. */ +void +ism_timer_set (struct ospf_interface *oi) +{ + switch (oi->state) + { + case ISM_Down: + /* First entry point of ospf interface state machine. In this state + interface parameters must be set to initial values, and timers are + reset also. */ + OSPF_ISM_TIMER_OFF (oi->t_hello); + OSPF_ISM_TIMER_OFF (oi->t_wait); + OSPF_ISM_TIMER_OFF (oi->t_ls_ack); + break; + case ISM_Loopback: + /* In this state, the interface may be looped back and will be + unavailable for regular data traffic. */ + OSPF_ISM_TIMER_OFF (oi->t_hello); + OSPF_ISM_TIMER_OFF (oi->t_wait); + OSPF_ISM_TIMER_OFF (oi->t_ls_ack); + break; + case ISM_Waiting: + /* The router is trying to determine the identity of DRouter and + BDRouter. The router begin to receive and send Hello Packets. */ + /* send first hello immediately */ + OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, 1); + OSPF_ISM_TIMER_ON (oi->t_wait, ospf_wait_timer, + OSPF_IF_PARAM (oi, v_wait)); + OSPF_ISM_TIMER_OFF (oi->t_ls_ack); + break; + case ISM_PointToPoint: + /* The interface connects to a physical Point-to-point network or + virtual link. The router attempts to form an adjacency with + neighboring router. Hello packets are also sent. */ + /* send first hello immediately */ + OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, 1); + + OSPF_ISM_TIMER_OFF (oi->t_wait); + OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); + break; + case ISM_DROther: + /* The network type of the interface is broadcast or NBMA network, + and the router itself is neither Designated Router nor + Backup Designated Router. */ + OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, + OSPF_IF_PARAM (oi, v_hello)); + OSPF_ISM_TIMER_OFF (oi->t_wait); + OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); + break; + case ISM_Backup: + /* The network type of the interface is broadcast os NBMA network, + and the router is Backup Designated Router. */ + OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, + OSPF_IF_PARAM (oi, v_hello)); + OSPF_ISM_TIMER_OFF (oi->t_wait); + OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); + break; + case ISM_DR: + /* The network type of the interface is broadcast or NBMA network, + and the router is Designated Router. */ + OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, + OSPF_IF_PARAM (oi, v_hello)); + OSPF_ISM_TIMER_OFF (oi->t_wait); + OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); + break; + } +} + +int +ism_stop (struct ospf_interface *oi) +{ + return 0; +} + +int +ism_interface_up (struct ospf_interface *oi) +{ + int next_state = 0; + + /* if network type is point-to-point, Point-to-MultiPoint or virtual link, + the state transitions to Point-to-Point. */ + if (oi->type == OSPF_IFTYPE_POINTOPOINT || + oi->type == OSPF_IFTYPE_POINTOMULTIPOINT || + oi->type == OSPF_IFTYPE_VIRTUALLINK) + next_state = ISM_PointToPoint; + /* Else if the router is not eligible to DR, the state transitions to + DROther. */ + else if (PRIORITY (oi) == 0) /* router is eligible? */ + next_state = ISM_DROther; + else + /* Otherwise, the state transitions to Waiting. */ + next_state = ISM_Waiting; + + if (oi->type == OSPF_IFTYPE_NBMA) + ospf_nbr_nbma_if_update (oi->ospf, oi); + + /* ospf_ism_event (t); */ + return next_state; +} + +int +ism_loop_ind (struct ospf_interface *oi) +{ + int ret = 0; + + /* call ism_interface_down. */ + /* ret = ism_interface_down (oi); */ + + return ret; +} + +/* Interface down event handler. */ +int +ism_interface_down (struct ospf_interface *oi) +{ + ospf_if_cleanup (oi); + return 0; +} + + +int +ism_backup_seen (struct ospf_interface *oi) +{ + return ospf_dr_election (oi); +} + +int +ism_wait_timer (struct ospf_interface *oi) +{ + return ospf_dr_election (oi); +} + +int +ism_neighbor_change (struct ospf_interface *oi) +{ + return ospf_dr_election (oi); +} + +int +ism_ignore (struct ospf_interface *oi) +{ + if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) + zlog (NULL, LOG_INFO, "ISM[%s]: ism_ignore called", IF_NAME (oi)); + + return 0; +} + +/* Interface State Machine */ +struct { + int (*func) (); + int next_state; +} ISM [OSPF_ISM_STATE_MAX][OSPF_ISM_EVENT_MAX] = +{ + { + /* DependUpon: dummy state. */ + { ism_ignore, ISM_DependUpon }, /* NoEvent */ + { ism_ignore, ISM_DependUpon }, /* InterfaceUp */ + { ism_ignore, ISM_DependUpon }, /* WaitTimer */ + { ism_ignore, ISM_DependUpon }, /* BackupSeen */ + { ism_ignore, ISM_DependUpon }, /* NeighborChange */ + { ism_ignore, ISM_DependUpon }, /* LoopInd */ + { ism_ignore, ISM_DependUpon }, /* UnloopInd */ + { ism_ignore, ISM_DependUpon }, /* InterfaceDown */ + }, + { + /* Down:*/ + { ism_ignore, ISM_DependUpon }, /* NoEvent */ + { ism_interface_up, ISM_DependUpon }, /* InterfaceUp */ + { ism_ignore, ISM_Down }, /* WaitTimer */ + { ism_ignore, ISM_Down }, /* BackupSeen */ + { ism_ignore, ISM_Down }, /* NeighborChange */ + { ism_loop_ind, ISM_Loopback }, /* LoopInd */ + { ism_ignore, ISM_Down }, /* UnloopInd */ + { ism_interface_down, ISM_Down }, /* InterfaceDown */ + }, + { + /* Loopback: */ + { ism_ignore, ISM_DependUpon }, /* NoEvent */ + { ism_ignore, ISM_Loopback }, /* InterfaceUp */ + { ism_ignore, ISM_Loopback }, /* WaitTimer */ + { ism_ignore, ISM_Loopback }, /* BackupSeen */ + { ism_ignore, ISM_Loopback }, /* NeighborChange */ + { ism_ignore, ISM_Loopback }, /* LoopInd */ + { ism_ignore, ISM_Down }, /* UnloopInd */ + { ism_interface_down, ISM_Down }, /* InterfaceDown */ + }, + { + /* Waiting: */ + { ism_ignore, ISM_DependUpon }, /* NoEvent */ + { ism_ignore, ISM_Waiting }, /* InterfaceUp */ + { ism_wait_timer, ISM_DependUpon }, /* WaitTimer */ + { ism_backup_seen, ISM_DependUpon }, /* BackupSeen */ + { ism_ignore, ISM_Waiting }, /* NeighborChange */ + { ism_loop_ind, ISM_Loopback }, /* LoopInd */ + { ism_ignore, ISM_Waiting }, /* UnloopInd */ + { ism_interface_down, ISM_Down }, /* InterfaceDown */ + }, + { + /* Point-to-Point: */ + { ism_ignore, ISM_DependUpon }, /* NoEvent */ + { ism_ignore, ISM_PointToPoint }, /* InterfaceUp */ + { ism_ignore, ISM_PointToPoint }, /* WaitTimer */ + { ism_ignore, ISM_PointToPoint }, /* BackupSeen */ + { ism_ignore, ISM_PointToPoint }, /* NeighborChange */ + { ism_loop_ind, ISM_Loopback }, /* LoopInd */ + { ism_ignore, ISM_PointToPoint }, /* UnloopInd */ + { ism_interface_down, ISM_Down }, /* InterfaceDown */ + }, + { + /* DROther: */ + { ism_ignore, ISM_DependUpon }, /* NoEvent */ + { ism_ignore, ISM_DROther }, /* InterfaceUp */ + { ism_ignore, ISM_DROther }, /* WaitTimer */ + { ism_ignore, ISM_DROther }, /* BackupSeen */ + { ism_neighbor_change, ISM_DependUpon }, /* NeighborChange */ + { ism_loop_ind, ISM_Loopback }, /* LoopInd */ + { ism_ignore, ISM_DROther }, /* UnloopInd */ + { ism_interface_down, ISM_Down }, /* InterfaceDown */ + }, + { + /* Backup: */ + { ism_ignore, ISM_DependUpon }, /* NoEvent */ + { ism_ignore, ISM_Backup }, /* InterfaceUp */ + { ism_ignore, ISM_Backup }, /* WaitTimer */ + { ism_ignore, ISM_Backup }, /* BackupSeen */ + { ism_neighbor_change, ISM_DependUpon }, /* NeighborChange */ + { ism_loop_ind, ISM_Loopback }, /* LoopInd */ + { ism_ignore, ISM_Backup }, /* UnloopInd */ + { ism_interface_down, ISM_Down }, /* InterfaceDown */ + }, + { + /* DR: */ + { ism_ignore, ISM_DependUpon }, /* NoEvent */ + { ism_ignore, ISM_DR }, /* InterfaceUp */ + { ism_ignore, ISM_DR }, /* WaitTimer */ + { ism_ignore, ISM_DR }, /* BackupSeen */ + { ism_neighbor_change, ISM_DependUpon }, /* NeighborChange */ + { ism_loop_ind, ISM_Loopback }, /* LoopInd */ + { ism_ignore, ISM_DR }, /* UnloopInd */ + { ism_interface_down, ISM_Down }, /* InterfaceDown */ + }, +}; + +static char *ospf_ism_event_str[] = +{ + "NoEvent", + "InterfaceUp", + "WaitTimer", + "BackupSeen", + "NeighborChange", + "LoopInd", + "UnLoopInd", + "InterfaceDown", +}; + +void +ism_change_state (struct ospf_interface *oi, int state) +{ + int old_state; + struct ospf_lsa *lsa; + + /* Logging change of state. */ + if (IS_DEBUG_OSPF (ism, ISM_STATUS)) + zlog (NULL, LOG_INFO, "ISM[%s]: State change %s -> %s", IF_NAME (oi), + LOOKUP (ospf_ism_state_msg, oi->state), + LOOKUP (ospf_ism_state_msg, state)); + + old_state = oi->state; + oi->state = state; + oi->state_change++; + + if (old_state == ISM_Down || state == ISM_Down) + ospf_check_abr_status (oi->ospf); + + /* Originate router-LSA. */ + if (oi->area) + { + if (state == ISM_Down) + { + if (oi->area->act_ints > 0) + oi->area->act_ints--; + } + else if (old_state == ISM_Down) + oi->area->act_ints++; + + /* schedule router-LSA originate. */ + ospf_router_lsa_timer_add (oi->area); + } + + /* Originate network-LSA. */ + if (old_state != ISM_DR && state == ISM_DR) + ospf_network_lsa_timer_add (oi); + else if (old_state == ISM_DR && state != ISM_DR) + { + /* Free self originated network LSA. */ + lsa = oi->network_lsa_self; + if (lsa) + { + ospf_lsa_flush_area (lsa, oi->area); + OSPF_TIMER_OFF (oi->t_network_lsa_self); + } + + ospf_lsa_unlock (oi->network_lsa_self); + oi->network_lsa_self = NULL; + } + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_ism_change (oi, old_state); +#endif /* HAVE_OPAQUE_LSA */ + + /* Check area border status. */ + ospf_check_abr_status (oi->ospf); +} + +/* Execute ISM event process. */ +int +ospf_ism_event (struct thread *thread) +{ + int event; + int next_state; + struct ospf_interface *oi; + + oi = THREAD_ARG (thread); + event = THREAD_VAL (thread); + + /* Call function. */ + next_state = (*(ISM [oi->state][event].func))(oi); + + if (! next_state) + next_state = ISM [oi->state][event].next_state; + + if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) + zlog (NULL, LOG_INFO, "ISM[%s]: %s (%s)", IF_NAME (oi), + LOOKUP (ospf_ism_state_msg, oi->state), + ospf_ism_event_str[event]); + + /* If state is changed. */ + if (next_state != oi->state) + ism_change_state (oi, next_state); + + /* Make sure timer is set. */ + ism_timer_set (oi); + + return 0; +} + diff --git a/ospfd/ospf_ism.h b/ospfd/ospf_ism.h new file mode 100644 index 0000000..6de8b8e --- /dev/null +++ b/ospfd/ospf_ism.h @@ -0,0 +1,88 @@ +/* + * OSPF version 2 Interface State Machine. + * From RFC2328 [OSPF Version 2] + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ISM_H +#define _ZEBRA_OSPF_ISM_H + +/* OSPF Interface State Machine Status. */ +#define ISM_DependUpon 0 +#define ISM_Down 1 +#define ISM_Loopback 2 +#define ISM_Waiting 3 +#define ISM_PointToPoint 4 +#define ISM_DROther 5 +#define ISM_Backup 6 +#define ISM_DR 7 +#define OSPF_ISM_STATE_MAX 8 + +/* OSPF Interface State Machine Event. */ +#define ISM_NoEvent 0 +#define ISM_InterfaceUp 1 +#define ISM_WaitTimer 2 +#define ISM_BackupSeen 3 +#define ISM_NeighborChange 4 +#define ISM_LoopInd 5 +#define ISM_UnloopInd 6 +#define ISM_InterfaceDown 7 +#define OSPF_ISM_EVENT_MAX 8 + +#define OSPF_ISM_WRITE_ON(O) \ + do \ + { \ + if (oi->on_write_q == 0) \ + { \ + listnode_add ((O)->oi_write_q, oi); \ + oi->on_write_q = 1; \ + } \ + if ((O)->t_write == NULL) \ + (O)->t_write = \ + thread_add_write (master, ospf_write, (O), (O)->fd); \ + } while (0) + +/* Macro for OSPF ISM timer turn on. */ +#define OSPF_ISM_TIMER_ON(T,F,V) \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), oi, (V)) + +/* Macro for OSPF ISM timer turn off. */ +#define OSPF_ISM_TIMER_OFF(X) \ + if (X) \ + { \ + thread_cancel (X); \ + (X) = NULL; \ + } + +/* Macro for OSPF schedule event. */ +#define OSPF_ISM_EVENT_SCHEDULE(I,E) \ + thread_add_event (master, ospf_ism_event, (I), (E)) + +/* Macro for OSPF execute event. */ +#define OSPF_ISM_EVENT_EXECUTE(I,E) \ + thread_execute (master, ospf_ism_event, (I), (E)) + +/* Prototypes. */ +int ospf_ism_event (struct thread *); +void ism_change_status (struct ospf_interface *, int); +int ospf_hello_timer (struct thread *thread); + +#endif /* _ZEBRA_OSPF_ISM_H */ diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c new file mode 100644 index 0000000..75490d6 --- /dev/null +++ b/ospfd/ospf_lsa.c @@ -0,0 +1,3312 @@ +/* + * OSPF Link State Advertisement + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "memory.h" +#include "stream.h" +#include "log.h" +#include "thread.h" +#include "hash.h" +#include "sockunion.h" /* for inet_aton() */ + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" + + +u_int32_t +get_metric (u_char *metric) +{ + u_int32_t m; + m = metric[0]; + m = (m << 8) + metric[1]; + m = (m << 8) + metric[2]; + return m; +} + + +struct timeval +tv_adjust (struct timeval a) +{ + while (a.tv_usec >= 1000000) + { + a.tv_usec -= 1000000; + a.tv_sec++; + } + + while (a.tv_usec < 0) + { + a.tv_usec += 1000000; + a.tv_sec--; + } + + return a; +} + +int +tv_ceil (struct timeval a) +{ + a = tv_adjust (a); + + return (a.tv_usec ? a.tv_sec + 1 : a.tv_sec); +} + +int +tv_floor (struct timeval a) +{ + a = tv_adjust (a); + + return a.tv_sec; +} + +struct timeval +int2tv (int a) +{ + struct timeval ret; + + ret.tv_sec = a; + ret.tv_usec = 0; + + return ret; +} + +struct timeval +tv_add (struct timeval a, struct timeval b) +{ + struct timeval ret; + + ret.tv_sec = a.tv_sec + b.tv_sec; + ret.tv_usec = a.tv_usec + b.tv_usec; + + return tv_adjust (ret); +} + +struct timeval +tv_sub (struct timeval a, struct timeval b) +{ + struct timeval ret; + + ret.tv_sec = a.tv_sec - b.tv_sec; + ret.tv_usec = a.tv_usec - b.tv_usec; + + return tv_adjust (ret); +} + +int +tv_cmp (struct timeval a, struct timeval b) +{ + return (a.tv_sec == b.tv_sec ? + a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec); +} + +int +ospf_lsa_refresh_delay (struct ospf_lsa *lsa) +{ + struct timeval delta, now; + int delay = 0; + + gettimeofday (&now, NULL); + delta = tv_sub (now, lsa->tv_orig); + + if (tv_cmp (delta, int2tv (OSPF_MIN_LS_INTERVAL)) < 0) + { + delay = tv_ceil (tv_sub (int2tv (OSPF_MIN_LS_INTERVAL), delta)); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type%d:%s]: Refresh timer delay %d seconds", + lsa->data->type, inet_ntoa (lsa->data->id), delay); + + assert (delay > 0); + } + + return delay; +} + + +int +get_age (struct ospf_lsa *lsa) +{ + int age; + struct timeval now; + + gettimeofday (&now, NULL); + age = ntohs (lsa->data->ls_age) + tv_floor (tv_sub (now, lsa->tv_recv)); + + return age; +} + + +/* Fletcher Checksum -- Refer to RFC1008. */ +#define MODX 4102 +#define LSA_CHECKSUM_OFFSET 15 + +u_int16_t +ospf_lsa_checksum (struct lsa_header *lsa) +{ + u_char *sp, *ep, *p, *q; + int c0 = 0, c1 = 0; + int x, y; + u_int16_t length; + + lsa->checksum = 0; + length = ntohs (lsa->length) - 2; + sp = (char *) &lsa->options; + + for (ep = sp + length; sp < ep; sp = q) + { + q = sp + MODX; + if (q > ep) + q = ep; + for (p = sp; p < q; p++) + { + c0 += *p; + c1 += c0; + } + c0 %= 255; + c1 %= 255; + } + + x = ((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255; + if (x <= 0) + x += 255; + y = 510 - c0 - x; + if (y > 255) + y -= 255; + + /* take care endian issue. */ + lsa->checksum = htons ((x << 8) + y); + + return (lsa->checksum); +} + + + +/* Create OSPF LSA. */ +struct ospf_lsa * +ospf_lsa_new () +{ + struct ospf_lsa *new; + + new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa)); + memset (new, 0, sizeof (struct ospf_lsa)); + + new->flags = 0; + new->lock = 1; + new->retransmit_counter = 0; + gettimeofday (&new->tv_recv, NULL); + new->tv_orig = new->tv_recv; + new->refresh_list = -1; + + return new; +} + +/* Duplicate OSPF LSA. */ +struct ospf_lsa * +ospf_lsa_dup (struct ospf_lsa *lsa) +{ + struct ospf_lsa *new; + + if (lsa == NULL) + return NULL; + + new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa)); + + memcpy (new, lsa, sizeof (struct ospf_lsa)); + UNSET_FLAG (new->flags, OSPF_LSA_DISCARD); + new->lock = 1; + new->retransmit_counter = 0; + new->data = ospf_lsa_data_dup (lsa->data); + + /* kevinm: Clear the refresh_list, otherwise there are going + to be problems when we try to remove the LSA from the + queue (which it's not a member of.) + XXX: Should we add the LSA to the refresh_list queue? */ + new->refresh_list = -1; + + if (IS_DEBUG_OSPF (lsa, LSA)) + zlog_info ("LSA: duplicated %p (new: %p)", lsa, new); + + return new; +} + +/* Free OSPF LSA. */ +void +ospf_lsa_free (struct ospf_lsa *lsa) +{ + assert (lsa->lock == 0); + + if (IS_DEBUG_OSPF (lsa, LSA)) + zlog_info ("LSA: freed %p", lsa); + + /* Delete LSA data. */ + if (lsa->data != NULL) + ospf_lsa_data_free (lsa->data); + + assert (lsa->refresh_list < 0); + + memset (lsa, 0, sizeof (struct ospf_lsa)); + XFREE (MTYPE_OSPF_LSA, lsa); +} + +/* Lock LSA. */ +struct ospf_lsa * +ospf_lsa_lock (struct ospf_lsa *lsa) +{ + lsa->lock++; + return lsa; +} + +/* Unlock LSA. */ +void +ospf_lsa_unlock (struct ospf_lsa *lsa) +{ + /* This is sanity check. */ + if (!lsa) + return; + + lsa->lock--; + + assert (lsa->lock >= 0); + + if (lsa->lock == 0) + { + assert (CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)); + ospf_lsa_free (lsa); + } +} + +/* Check discard flag. */ +void +ospf_lsa_discard (struct ospf_lsa *lsa) +{ + if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)) + { + SET_FLAG (lsa->flags, OSPF_LSA_DISCARD); + ospf_lsa_unlock (lsa); + } +} + +/* Create LSA data. */ +struct lsa_header * +ospf_lsa_data_new (size_t size) +{ + struct lsa_header *new; + + new = (struct lsa_header *) XMALLOC (MTYPE_OSPF_LSA_DATA, size); + memset (new, 0, size); + + return new; +} + +/* Duplicate LSA data. */ +struct lsa_header * +ospf_lsa_data_dup (struct lsa_header *lsah) +{ + struct lsa_header *new; + + new = ospf_lsa_data_new (ntohs (lsah->length)); + memcpy (new, lsah, ntohs (lsah->length)); + + return new; +} + +/* Free LSA data. */ +void +ospf_lsa_data_free (struct lsa_header *lsah) +{ + if (IS_DEBUG_OSPF (lsa, LSA)) + zlog_info ("LSA[Type%d:%s]: data freed %p", + lsah->type, inet_ntoa (lsah->id), lsah); + + XFREE (MTYPE_OSPF_LSA_DATA, lsah); +} + + +/* LSA general functions. */ + +const char * +dump_lsa_key (struct ospf_lsa *lsa) +{ + static char buf[] = { + "Type255,id(255.255.255.255),ar(255.255.255.255)", + }; + struct lsa_header *lsah; + + if (lsa != NULL && (lsah = lsa->data) != NULL) + { + char id[INET_ADDRSTRLEN], ar[INET_ADDRSTRLEN]; + strcpy (id, inet_ntoa (lsah->id)); + strcpy (ar, inet_ntoa (lsah->adv_router)); + + sprintf (buf, "Type%d,id(%s),ar(%s)", lsah->type, id, ar); + } + else + strcpy (buf, "NULL"); + + return buf; +} + +u_int32_t +lsa_seqnum_increment (struct ospf_lsa *lsa) +{ + u_int32_t seqnum; + + seqnum = ntohl (lsa->data->ls_seqnum) + 1; + + return htonl (seqnum); +} + +void +lsa_header_set (struct stream *s, u_char options, + u_char type, struct in_addr id, struct in_addr router_id) +{ + struct lsa_header *lsah; + + lsah = (struct lsa_header *) STREAM_DATA (s); + + lsah->ls_age = htons (0); + lsah->options = options; + lsah->type = type; + lsah->id = id; + lsah->adv_router = router_id; + lsah->ls_seqnum = htonl (OSPF_INITIAL_SEQUENCE_NUMBER); + + ospf_output_forward (s, OSPF_LSA_HEADER_SIZE); +} + + +/* router-LSA related functions. */ +/* Get router-LSA flags. */ +u_char +router_lsa_flags (struct ospf_area *area) +{ + u_char flags; + + flags = area->ospf->flags; + + /* Set virtual link flag. */ + if (ospf_full_virtual_nbrs (area)) + SET_FLAG (flags, ROUTER_LSA_VIRTUAL); + else + /* Just sanity check */ + UNSET_FLAG (flags, ROUTER_LSA_VIRTUAL); + + /* Set Shortcut ABR behabiour flag. */ + UNSET_FLAG (flags, ROUTER_LSA_SHORTCUT); + if (area->ospf->abr_type == OSPF_ABR_SHORTCUT) + if (!OSPF_IS_AREA_BACKBONE (area)) + if ((area->shortcut_configured == OSPF_SHORTCUT_DEFAULT && + area->ospf->backbone == NULL) || + area->shortcut_configured == OSPF_SHORTCUT_ENABLE) + SET_FLAG (flags, ROUTER_LSA_SHORTCUT); + + /* ASBR can't exit in stub area. */ + if (area->external_routing == OSPF_AREA_STUB) + UNSET_FLAG (flags, OSPF_FLAG_ASBR); + + return flags; +} + +/* Lookup neighbor other than myself. + And check neighbor count, + Point-to-Point link must have only 1 neighbor. */ +struct ospf_neighbor * +ospf_nbr_lookup_ptop (struct ospf_interface *oi) +{ + struct ospf_neighbor *nbr = NULL; + struct route_node *rn; + + /* Search neighbor, there must be one of two nbrs. */ + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id)) + if (nbr->state == NSM_Full) + { + route_unlock_node (rn); + break; + } + + /* PtoP link must have only 1 neighbor. */ + if (ospf_nbr_count (oi, 0) > 1) + zlog_warn ("Point-to-Point link has more than 1 neighobrs."); + + return nbr; +} + +/* Set a link information. */ +void +link_info_set (struct stream *s, struct in_addr id, + struct in_addr data, u_char type, u_char tos, u_int16_t cost) +{ + /* TOS based routing is not supported. */ + stream_put_ipv4 (s, id.s_addr); /* Link ID. */ + stream_put_ipv4 (s, data.s_addr); /* Link Data. */ + stream_putc (s, type); /* Link Type. */ + stream_putc (s, tos); /* TOS = 0. */ + stream_putw (s, cost); /* Link Cost. */ +} + +/* Describe Point-to-Point link. */ +int +lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi) +{ + int links = 0; + struct ospf_neighbor *nbr; + struct in_addr id, mask; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type1]: Set link Point-to-Point"); + + if ((nbr = ospf_nbr_lookup_ptop (oi))) + if (nbr->state == NSM_Full) + { + /* For unnumbered point-to-point networks, the Link Data field + should specify the interface's MIB-II ifIndex value. */ + link_info_set (s, nbr->router_id, oi->address->u.prefix4, + LSA_LINK_TYPE_POINTOPOINT, 0, oi->output_cost); + links++; + } + + if (oi->connected->destination != NULL) + { + /* Option 1: + link_type = LSA_LINK_TYPE_STUB; + link_id = nbr->address.u.prefix4; + link_data.s_addr = 0xffffffff; + link_cost = o->output_cost; */ + + id.s_addr = oi->connected->destination->u.prefix4.s_addr; + mask.s_addr = 0xffffffff; + link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); + } + else + { + /* Option 2: We need to include link to a stub + network regardless of the state of the neighbor */ + masklen2ip (oi->address->prefixlen, &mask); + id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; + link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); + } + links++; + + return links; +} + +/* Describe Broadcast Link. */ +int +lsa_link_broadcast_set (struct stream *s, struct ospf_interface *oi) +{ + struct ospf_neighbor *dr; + struct in_addr id, mask; + + /* Describe Type 3 Link. */ + if (oi->state == ISM_Waiting) + { + masklen2ip (oi->address->prefixlen, &mask); + id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; + link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); + return 1; + } + + dr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi)); + /* Describe Type 2 link. */ + if (dr && (dr->state == NSM_Full || + IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))) && + ospf_nbr_count (oi, NSM_Full) > 0) + { + link_info_set (s, DR (oi), oi->address->u.prefix4, + LSA_LINK_TYPE_TRANSIT, 0, oi->output_cost); + } + /* Describe type 3 link. */ + else + { + masklen2ip (oi->address->prefixlen, &mask); + id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; + link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); + } + return 1; +} + +int +lsa_link_loopback_set (struct stream *s, struct ospf_interface *oi) +{ + struct in_addr id, mask; + + /* Describe Type 3 Link. */ + if (oi->state != ISM_Loopback) + return 0; + + mask.s_addr = 0xffffffff; + id.s_addr = oi->address->u.prefix4.s_addr; + link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); + return 1; +} + +/* Describe Virtual Link. */ +int +lsa_link_virtuallink_set (struct stream *s, struct ospf_interface *oi) +{ + struct ospf_neighbor *nbr; + + if (oi->state == ISM_PointToPoint) + if ((nbr = ospf_nbr_lookup_ptop (oi))) + if (nbr->state == NSM_Full) + { + link_info_set (s, nbr->router_id, oi->address->u.prefix4, + LSA_LINK_TYPE_VIRTUALLINK, 0, oi->output_cost); + return 1; + } + + return 0; +} + +#define lsa_link_nbma_set(S,O) lsa_link_broadcast_set (S, O) + +/* This function add for support point-to-multipoint ,see RFC2328 + 12.4.1.4.*/ +int +lsa_link_ptomp_set (struct stream *s, struct ospf_interface *oi) +{ + int links = 0; + struct route_node *rn; + struct ospf_neighbor *nbr = NULL; + struct in_addr id, mask; + + mask.s_addr = 0xffffffff; + id.s_addr = oi->address->u.prefix4.s_addr; + link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, 0); + links++; + + zlog_info ("PointToMultipoint: running ptomultip_set"); + + /* Search neighbor, */ + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + /* Ignore myself. */ + if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id)) + if (nbr->state == NSM_Full) + + { + link_info_set (s, nbr->router_id, oi->address->u.prefix4, + LSA_LINK_TYPE_POINTOPOINT, 0, oi->output_cost); + links++; + zlog_info ("PointToMultipoint: set link to %s", + inet_ntoa(oi->address->u.prefix4)); + } + + return links; +} + +/* Set router-LSA link information. */ +int +router_lsa_link_set (struct stream *s, struct ospf_area *area) +{ + listnode node; + int links = 0; + + for (node = listhead (area->oiflist); node; node = nextnode (node)) + { + struct ospf_interface *oi = node->data; + struct interface *ifp = oi->ifp; + + /* Check interface is up, OSPF is enable. */ + if (if_is_up (ifp)) + { + if (oi->state != ISM_Down) + { + /* Describe each link. */ + switch (oi->type) + { + case OSPF_IFTYPE_POINTOPOINT: + links += lsa_link_ptop_set (s, oi); + break; + case OSPF_IFTYPE_BROADCAST: + links += lsa_link_broadcast_set (s, oi); + break; + case OSPF_IFTYPE_NBMA: + links += lsa_link_nbma_set (s, oi); + break; + case OSPF_IFTYPE_POINTOMULTIPOINT: + links += lsa_link_ptomp_set (s, oi); + break; + case OSPF_IFTYPE_VIRTUALLINK: + links += lsa_link_virtuallink_set (s, oi); + break; + case OSPF_IFTYPE_LOOPBACK: + links += lsa_link_loopback_set (s, oi); + } + } + } + } + + return links; +} + +/* Set router-LSA body. */ +void +ospf_router_lsa_body_set (struct stream *s, struct ospf_area *area) +{ + unsigned long putp; + u_int16_t cnt; + + /* Set flags. */ + stream_putc (s, router_lsa_flags (area)); + + /* Set Zero fields. */ + stream_putc (s, 0); + + /* Keep pointer to # links. */ + putp = s->putp; + + /* Forward word */ + stream_putw(s, 0); + + /* Set all link information. */ + cnt = router_lsa_link_set (s, area); + + /* Set # of links here. */ + stream_putw_at (s, putp, cnt); +} + +/* Create new router-LSA. */ +struct ospf_lsa * +ospf_router_lsa_new (struct ospf_area *area) +{ + struct ospf *ospf = area->ospf; + struct stream *s; + struct lsa_header *lsah; + struct ospf_lsa *new; + int length; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type1]: Create router-LSA instance"); + + /* Create a stream for LSA. */ + s = stream_new (OSPF_MAX_LSA_SIZE); + lsah = (struct lsa_header *) STREAM_DATA (s); + +#ifdef HAVE_NSSA + /* Set LSA common header fields. */ + lsa_header_set (s, LSA_OPTIONS_GET (area) | LSA_NSSA_GET (area), + OSPF_ROUTER_LSA, ospf->router_id, ospf->router_id); +#else /* ! HAVE_NSSA */ + /* Set LSA common header fields. */ + lsa_header_set (s, LSA_OPTIONS_GET (area), + OSPF_ROUTER_LSA, ospf->router_id, ospf->router_id); +#endif /* HAVE_NSSA */ + + /* Set router-LSA body fields. */ + ospf_router_lsa_body_set (s, area); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Now, create OSPF LSA instance. */ + new = ospf_lsa_new (); + new->area = area; + SET_FLAG (new->flags, OSPF_LSA_SELF); + + /* Copy LSA data to store, discard stream. */ + new->data = ospf_lsa_data_new (length); + memcpy (new->data, lsah, length); + stream_free (s); + + return new; +} + +/* Originate Router-LSA. */ +struct ospf_lsa * +ospf_router_lsa_originate (struct ospf_area *area) +{ + struct ospf_lsa *new; + + /* Create new router-LSA instance. */ + new = ospf_router_lsa_new (area); + + /* Sanity check. */ + if (new->data->adv_router.s_addr == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type1]: AdvRouter is 0, discard"); + ospf_lsa_discard (new); + return NULL; + } + + /* Install LSA to LSDB. */ + new = ospf_lsa_install (area->ospf, NULL, new); + + /* Update LSA origination count. */ + area->ospf->lsa_originate_count++; + + /* Flooding new LSA through area. */ + ospf_flood_through_area (area, NULL, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: Originate router-LSA %p", + new->data->type, inet_ntoa (new->data->id), new); + ospf_lsa_header_dump (new->data); + } + + return new; +} + +/* Refresh router-LSA. */ +struct ospf_lsa * +ospf_router_lsa_refresh (struct ospf_lsa *lsa) +{ + struct ospf_area *area = lsa->area; + struct ospf_lsa *new; + + /* Sanity check. */ + assert (lsa->data); + + /* Delete LSA from neighbor retransmit-list. */ + ospf_ls_retransmit_delete_nbr_area (area, lsa); + + /* Create new router-LSA instance. */ + new = ospf_router_lsa_new (area); + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + ospf_lsa_install (area->ospf, NULL, new); + + /* Flood LSA through area. */ + ospf_flood_through_area (area, NULL, new); + + /* Debug logging. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: router-LSA refresh", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + return NULL; +} + +int +ospf_router_lsa_timer (struct thread *t) +{ + struct ospf_area *area; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[router-LSA]: (router-LSA Refresh expire)"); + + area = THREAD_ARG (t); + area->t_router_lsa_self = NULL; + + /* Now refresh router-LSA. */ + if (area->router_lsa_self) + ospf_router_lsa_refresh (area->router_lsa_self); + /* Newly originate router-LSA. */ + else + ospf_router_lsa_originate (area); + + return 0; +} + +void +ospf_router_lsa_timer_add (struct ospf_area *area) +{ + /* Keep area's self-originated router-LSA. */ + struct ospf_lsa *lsa = area->router_lsa_self; + + /* Cancel previously scheduled router-LSA timer. */ + if (area->t_router_lsa_self) + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type1]: Cancel previous router-LSA timer"); + + OSPF_TIMER_OFF (area->t_router_lsa_self); + + /* If router-LSA is originated previously, check the interval time. */ + if (lsa) + { + int delay; + if ((delay = ospf_lsa_refresh_delay (lsa)) > 0) + { + OSPF_AREA_TIMER_ON (area->t_router_lsa_self, + ospf_router_lsa_timer, delay); + return; + } + } + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type1]: Scheduling router-LSA origination right away"); + + /* Immediately refresh router-LSA. */ + OSPF_AREA_TIMER_ON (area->t_router_lsa_self, ospf_router_lsa_timer, 0); +} + +int +ospf_router_lsa_update_timer (struct thread *thread) +{ + struct ospf *ospf = THREAD_ARG (thread); + listnode node; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("Timer[router-LSA Update]: (timer expire)"); + + ospf->t_router_lsa_update = NULL; + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + struct ospf_area *area = getdata (node); + struct ospf_lsa *lsa = area->router_lsa_self; + struct router_lsa *rl; + char *area_str; + + /* Keep Area ID string. */ + area_str = AREA_NAME (area); + + /* If LSA not exist in this Area, originate new. */ + if (lsa == NULL) + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info("LSA[Type1]: Create router-LSA for Area %s", area_str); + + ospf_router_lsa_originate (area); + } + /* If router-ID is changed, Link ID must change. + First flush old LSA, then originate new. */ + else if (!IPV4_ADDR_SAME (&lsa->data->id, &ospf->router_id)) + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info("LSA[Type%d:%s]: Refresh router-LSA for Area %s", + lsa->data->type, inet_ntoa (lsa->data->id), area_str); + ospf_lsa_flush_area (lsa, area); + ospf_lsa_unlock (area->router_lsa_self); + area->router_lsa_self = NULL; + + /* Refresh router-LSA, (not install) and flood through area. */ + ospf_router_lsa_timer_add (area); + } + else + { + rl = (struct router_lsa *) lsa->data; + /* Refresh router-LSA, (not install) and flood through area. */ + if (rl->flags != ospf->flags) + ospf_router_lsa_timer_add (area); + } + } + + return 0; +} + + +/* network-LSA related functions. */ +/* Originate Network-LSA. */ +void +ospf_network_lsa_body_set (struct stream *s, struct ospf_interface *oi) +{ + struct in_addr mask; + struct route_node *rn; + struct ospf_neighbor *nbr; + + masklen2ip (oi->address->prefixlen, &mask); + stream_put_ipv4 (s, mask.s_addr); + + /* The network-LSA lists those routers that are fully adjacent to + the Designated Router; each fully adjacent router is identified by + its OSPF Router ID. The Designated Router includes itself in this + list. RFC2328, Section 12.4.2 */ + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + if (nbr->state == NSM_Full || nbr == oi->nbr_self) + stream_put_ipv4 (s, nbr->router_id.s_addr); +} + +struct ospf_lsa * +ospf_network_lsa_new (struct ospf_interface *oi) +{ + struct stream *s; + struct ospf_lsa *new; + struct lsa_header *lsah; + int length; + + /* If there are no neighbours on this network (the net is stub), + the router does not originate network-LSA (see RFC 12.4.2) */ + if (oi->full_nbrs == 0) + return NULL; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type2]: Create network-LSA instance"); + + /* Create new stream for LSA. */ + s = stream_new (OSPF_MAX_LSA_SIZE); + lsah = (struct lsa_header *) STREAM_DATA (s); + + lsa_header_set (s, (OPTIONS (oi) | LSA_OPTIONS_GET (oi->area)), + OSPF_NETWORK_LSA, DR (oi), oi->ospf->router_id); + + /* Set network-LSA body fields. */ + ospf_network_lsa_body_set (s, oi); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Create OSPF LSA instance. */ + new = ospf_lsa_new (); + new->area = oi->area; + SET_FLAG (new->flags, OSPF_LSA_SELF); + + /* Copy LSA to store. */ + new->data = ospf_lsa_data_new (length); + memcpy (new->data, lsah, length); + stream_free (s); + + return new; +} + +/* Originate network-LSA. */ +struct ospf_lsa * +ospf_network_lsa_originate (struct ospf_interface *oi) +{ + struct ospf_lsa *new; + + /* Create new network-LSA instance. */ + new = ospf_network_lsa_new (oi); + if (new == NULL) + return NULL; + + /* Install LSA to LSDB. */ + new = ospf_lsa_install (oi->ospf, oi, new); + + /* Update LSA origination count. */ + oi->ospf->lsa_originate_count++; + + /* Flooding new LSA through area. */ + ospf_flood_through_area (oi->area, NULL, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: Originate network-LSA %p", + new->data->type, inet_ntoa (new->data->id), new); + ospf_lsa_header_dump (new->data); + } + + return new; +} + +int +ospf_network_lsa_refresh (struct ospf_lsa *lsa, struct ospf_interface *oi) +{ + struct ospf_area *area = lsa->area; + struct ospf_lsa *new; + + assert (lsa->data); + + /* Delete LSA from neighbor retransmit-list. */ + ospf_ls_retransmit_delete_nbr_area (area, lsa); + + /* Create new network-LSA instance. */ + new = ospf_network_lsa_new (oi); + if (new == NULL) + return -1; + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + ospf_lsa_install (area->ospf, oi, new); + + /* Flood LSA through aera. */ + ospf_flood_through_area (area, NULL, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: network-LSA refresh", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + return 0; +} + +int +ospf_network_lsa_refresh_timer (struct thread *t) +{ + struct ospf_interface *oi; + + oi = THREAD_ARG (t); + oi->t_network_lsa_self = NULL; + + if (oi->network_lsa_self) + /* Now refresh network-LSA. */ + ospf_network_lsa_refresh (oi->network_lsa_self, oi); + else + /* Newly create network-LSA. */ + ospf_network_lsa_originate (oi); + + return 0; +} + +void +ospf_network_lsa_timer_add (struct ospf_interface *oi) +{ + /* Keep interface's self-originated network-LSA. */ + struct ospf_lsa *lsa = oi->network_lsa_self; + + /* Cancel previously schedules network-LSA timer. */ + if (oi->t_network_lsa_self) + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type2]: Cancel previous network-LSA timer"); + OSPF_TIMER_OFF (oi->t_network_lsa_self); + + /* If network-LSA is originated previously, check the interval time. */ + if (lsa) + { + int delay; + if ((delay = ospf_lsa_refresh_delay (lsa)) > 0) + { + oi->t_network_lsa_self = + thread_add_timer (master, ospf_network_lsa_refresh_timer, + oi, delay); + return; + } + } + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("Scheduling network-LSA origination right away"); + + /* Immediately refresh network-LSA. */ + oi->t_network_lsa_self = + thread_add_event (master, ospf_network_lsa_refresh_timer, oi, 0); +} + + +void +stream_put_ospf_metric (struct stream *s, u_int32_t metric_value) +{ + u_int32_t metric; + char *mp; + + /* Put 0 metric. TOS metric is not supported. */ + metric = htonl (metric_value); + mp = (char *) &metric; + mp++; + stream_put (s, mp, 3); +} + +/* summary-LSA related functions. */ +void +ospf_summary_lsa_body_set (struct stream *s, struct prefix *p, + u_int32_t metric) +{ + struct in_addr mask; + + masklen2ip (p->prefixlen, &mask); + + /* Put Network Mask. */ + stream_put_ipv4 (s, mask.s_addr); + + /* Set # TOS. */ + stream_putc (s, (u_char) 0); + + /* Set metric. */ + stream_put_ospf_metric (s, metric); +} + +struct ospf_lsa * +ospf_summary_lsa_new (struct ospf_area *area, struct prefix *p, + u_int32_t metric, struct in_addr id) +{ + struct stream *s; + struct ospf_lsa *new; + struct lsa_header *lsah; + int length; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type3]: Create summary-LSA instance"); + + /* Create new stream for LSA. */ + s = stream_new (OSPF_MAX_LSA_SIZE); + lsah = (struct lsa_header *) STREAM_DATA (s); + + lsa_header_set (s, LSA_OPTIONS_GET (area), OSPF_SUMMARY_LSA, + id, area->ospf->router_id); + + /* Set summary-LSA body fields. */ + ospf_summary_lsa_body_set (s, p, metric); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Create OSPF LSA instance. */ + new = ospf_lsa_new (); + new->area = area; + SET_FLAG (new->flags, OSPF_LSA_SELF); + + /* Copy LSA to store. */ + new->data = ospf_lsa_data_new (length); + memcpy (new->data, lsah, length); + stream_free (s); + + return new; +} + +/* Originate Summary-LSA. */ +struct ospf_lsa * +ospf_summary_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, + struct ospf_area *area) +{ + struct ospf_lsa *new; + struct in_addr id; + + id = ospf_lsa_unique_id (area->ospf, area->lsdb, OSPF_SUMMARY_LSA, p); + + /* Create new summary-LSA instance. */ + new = ospf_summary_lsa_new (area, (struct prefix *) p, metric, id); + + /* Instlal LSA to LSDB. */ + new = ospf_lsa_install (area->ospf, NULL, new); + + /* Update LSA origination count. */ + area->ospf->lsa_originate_count++; + + /* Flooding new LSA through area. */ + ospf_flood_through_area (area, NULL, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: Originate summary-LSA %p", + new->data->type, inet_ntoa (new->data->id), new); + ospf_lsa_header_dump (new->data); + } + + return new; +} + +struct ospf_lsa* +ospf_summary_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) +{ + struct ospf_lsa *new; + struct summary_lsa *sl; + struct prefix p; + + /* Sanity check. */ + assert (lsa->data); + + sl = (struct summary_lsa *)lsa->data; + p.prefixlen = ip_masklen (sl->mask); + new = ospf_summary_lsa_new (lsa->area, &p, GET_METRIC (sl->metric), + sl->header.id); + + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + /* Re-calculate checksum. */ + ospf_lsa_checksum (new->data); + + ospf_lsa_install (ospf, NULL, new); + + /* Flood LSA through AS. */ + ospf_flood_through_area (new->area, NULL, new); + + /* Debug logging. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: summary-LSA refresh", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + return new; +} + + +/* summary-ASBR-LSA related functions. */ +void +ospf_summary_asbr_lsa_body_set (struct stream *s, struct prefix *p, + u_int32_t metric) +{ + struct in_addr mask; + + masklen2ip (p->prefixlen, &mask); + + /* Put Network Mask. */ + stream_put_ipv4 (s, mask.s_addr); + + /* Set # TOS. */ + stream_putc (s, (u_char) 0); + + /* Set metric. */ + stream_put_ospf_metric (s, metric); +} + +struct ospf_lsa * +ospf_summary_asbr_lsa_new (struct ospf_area *area, struct prefix *p, + u_int32_t metric, struct in_addr id) +{ + struct stream *s; + struct ospf_lsa *new; + struct lsa_header *lsah; + int length; + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type3]: Create summary-LSA instance"); + + /* Create new stream for LSA. */ + s = stream_new (OSPF_MAX_LSA_SIZE); + lsah = (struct lsa_header *) STREAM_DATA (s); + + lsa_header_set (s, LSA_OPTIONS_GET (area), OSPF_ASBR_SUMMARY_LSA, + id, area->ospf->router_id); + + /* Set summary-LSA body fields. */ + ospf_summary_asbr_lsa_body_set (s, p, metric); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Create OSPF LSA instance. */ + new = ospf_lsa_new (); + new->area = area; + SET_FLAG (new->flags, OSPF_LSA_SELF); + + /* Copy LSA to store. */ + new->data = ospf_lsa_data_new (length); + memcpy (new->data, lsah, length); + stream_free (s); + + return new; +} + +/* Originate summary-ASBR-LSA. */ +struct ospf_lsa * +ospf_summary_asbr_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, + struct ospf_area *area) +{ + struct ospf_lsa *new; + struct in_addr id; + + id = ospf_lsa_unique_id (area->ospf, area->lsdb, OSPF_ASBR_SUMMARY_LSA, p); + + /* Create new summary-LSA instance. */ + new = ospf_summary_asbr_lsa_new (area, (struct prefix *) p, metric, id); + + /* Install LSA to LSDB. */ + new = ospf_lsa_install (area->ospf, NULL, new); + + /* Update LSA origination count. */ + area->ospf->lsa_originate_count++; + + /* Flooding new LSA through area. */ + ospf_flood_through_area (area, NULL, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: Originate summary-ASBR-LSA %p", + new->data->type, inet_ntoa (new->data->id), new); + ospf_lsa_header_dump (new->data); + } + + return new; +} + +struct ospf_lsa* +ospf_summary_asbr_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) +{ + struct ospf_lsa *new; + struct summary_lsa *sl; + struct prefix p; + + /* Sanity check. */ + assert (lsa->data); + + sl = (struct summary_lsa *)lsa->data; + p.prefixlen = ip_masklen (sl->mask); + new = ospf_summary_asbr_lsa_new (lsa->area, &p, GET_METRIC (sl->metric), + sl->header.id); + + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + /* Re-calculate checksum. */ + ospf_lsa_checksum (new->data); + + ospf_lsa_install (ospf, NULL, new); + + /* Flood LSA through area. */ + ospf_flood_through_area (new->area, NULL, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: summary-ASBR-LSA refresh", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + return new; +} + +/* AS-external-LSA related functions. */ + +/* Get nexthop for AS-external-LSAs. Return nexthop if its interface + is connected, else 0*/ +struct in_addr +ospf_external_lsa_nexthop_get (struct ospf *ospf, struct in_addr nexthop) +{ + struct in_addr fwd; + struct prefix nh; + listnode n1; + + fwd.s_addr = 0; + + if (!nexthop.s_addr) + return fwd; + + /* Check whether nexthop is covered by OSPF network. */ + nh.family = AF_INET; + nh.u.prefix4 = nexthop; + nh.prefixlen = IPV4_MAX_BITLEN; + + for (n1 = listhead (ospf->oiflist); n1; nextnode (n1)) + { + struct ospf_interface *oi = getdata (n1); + + if (if_is_up (oi->ifp)) + if (oi->address->family == AF_INET) + if (prefix_match (oi->address, &nh)) + return nexthop; + } + + return fwd; +} + +#ifdef HAVE_NSSA +/* NSSA-external-LSA related functions. */ + +/* Get 1st IP connection for Forward Addr */ + +struct in_addr +ospf_get_ip_from_ifp (struct ospf_interface *oi) +{ + struct in_addr fwd; + + fwd.s_addr = 0; + + if (if_is_up (oi->ifp)) + return oi->address->u.prefix4; + + return fwd; +} + +/* Get 1st IP connection for Forward Addr */ +struct in_addr +ospf_get_nssa_ip (struct ospf_area *area) +{ + struct in_addr fwd; + struct in_addr best_default; + listnode n1; + + fwd.s_addr = 0; + best_default.s_addr = 0; + + for (n1 = listhead (area->ospf->oiflist); n1; nextnode (n1)) + { + struct ospf_interface *oi = getdata (n1); + + if (if_is_up (oi->ifp)) + if (oi->area->external_routing == OSPF_AREA_NSSA) + if (oi->address && oi->address->family == AF_INET) + { + if (best_default.s_addr == 0) + best_default = oi->address->u.prefix4; + if (oi->area == area) + return oi->address->u.prefix4; + } + } + + if (best_default.s_addr != 0) + return best_default; + + return fwd; +} +#endif /* HAVE_NSSA */ + +#define DEFAULT_DEFAULT_METRIC 20 +#define DEFAULT_DEFAULT_ORIGINATE_METRIC 10 +#define DEFAULT_DEFAULT_ALWAYS_METRIC 1 + +#define DEFAULT_METRIC_TYPE EXTERNAL_METRIC_TYPE_2 + +int +metric_type (struct ospf *ospf, u_char src) +{ + return (ospf->dmetric[src].type < 0 ? + DEFAULT_METRIC_TYPE : ospf->dmetric[src].type); +} + +int +metric_value (struct ospf *ospf, u_char src) +{ + if (ospf->dmetric[src].value < 0) + { + if (src == DEFAULT_ROUTE) + { + if (ospf->default_originate == DEFAULT_ORIGINATE_ZEBRA) + return DEFAULT_DEFAULT_ORIGINATE_METRIC; + else + return DEFAULT_DEFAULT_ALWAYS_METRIC; + } + else if (ospf->default_metric < 0) + return DEFAULT_DEFAULT_METRIC; + else + return ospf->default_metric; + } + + return ospf->dmetric[src].value; +} + +/* Set AS-external-LSA body. */ +void +ospf_external_lsa_body_set (struct stream *s, struct external_info *ei, + struct ospf *ospf) +{ + struct prefix_ipv4 *p = &ei->p; + struct in_addr mask, fwd_addr; + u_int32_t mvalue; + int mtype; + int type; + + /* Put Network Mask. */ + masklen2ip (p->prefixlen, &mask); + stream_put_ipv4 (s, mask.s_addr); + + /* If prefix is default, specify DEFAULT_ROUTE. */ + type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type; + + mtype = (ROUTEMAP_METRIC_TYPE (ei) != -1) ? + ROUTEMAP_METRIC_TYPE (ei) : metric_type (ospf, type); + + mvalue = (ROUTEMAP_METRIC (ei) != -1) ? + ROUTEMAP_METRIC (ei) : metric_value (ospf, type); + + /* Put type of external metric. */ + stream_putc (s, (mtype == EXTERNAL_METRIC_TYPE_2 ? 0x80 : 0)); + + /* Put 0 metric. TOS metric is not supported. */ + stream_put_ospf_metric (s, mvalue); + + /* Get forwarding address to nexthop if on the Connection List, else 0. */ + fwd_addr = ospf_external_lsa_nexthop_get (ospf, ei->nexthop); + + /* Put forwarding address. */ + stream_put_ipv4 (s, fwd_addr.s_addr); + + /* Put route tag -- This value should be introduced from configuration. */ + stream_putl (s, 0); +} + +/* Create new external-LSA. */ +struct ospf_lsa * +ospf_external_lsa_new (struct ospf *ospf, + struct external_info *ei, struct in_addr *old_id) +{ + struct stream *s; + struct lsa_header *lsah; + struct ospf_lsa *new; + struct in_addr id; + int length; + + if (ei == NULL) + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_warn ("LSA[Type5]: External info is NULL, could not originated"); + return NULL; + } + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type5]: Originate AS-external-LSA instance"); + + /* If old Link State ID is specified, refresh LSA with same ID. */ + if (old_id) + id = *old_id; + /* Get Link State with unique ID. */ + else + { + id = ospf_lsa_unique_id (ospf, ospf->lsdb, OSPF_AS_EXTERNAL_LSA, &ei->p); + if (id.s_addr == 0xffffffff) + { + /* Maybe Link State ID not available. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type5]: Link ID not available, can't originate"); + return NULL; + } + } + + /* Create new stream for LSA. */ + s = stream_new (OSPF_MAX_LSA_SIZE); + lsah = (struct lsa_header *) STREAM_DATA (s); + + /* Set LSA common header fields. */ + lsa_header_set (s, OSPF_OPTION_E, OSPF_AS_EXTERNAL_LSA, + id, ospf->router_id); + + /* Set AS-external-LSA body fields. */ + ospf_external_lsa_body_set (s, ei, ospf); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Now, create OSPF LSA instance. */ + new = ospf_lsa_new (); + new->area = NULL; + SET_FLAG (new->flags, OSPF_LSA_SELF|OSPF_LSA_APPROVED); + + /* Copy LSA data to store, discard stream. */ + new->data = ospf_lsa_data_new (length); + memcpy (new->data, lsah, length); + stream_free (s); + + return new; +} + +#ifdef HAVE_NSSA +/* As Type-7 */ +void +ospf_install_flood_nssa (struct ospf *ospf, + struct ospf_lsa *lsa, struct external_info *ei) +{ + struct ospf_lsa *new2; + struct as_external_lsa *extlsa; + listnode node; + + /* NSSA Originate or Refresh (If anyNSSA) + + LSA is self-originated. And just installed as Type-5. + Additionally, install as Type-7 LSDB for every attached NSSA. + + P-Bit controls which ABR performs translation to outside world; If + we are an ABR....do not set the P-bit, because we send the Type-5, + not as the ABR Translator, but as the ASBR owner within the AS! + + If we are NOT ABR, Flood through NSSA as Type-7 w/P-bit set. The + elected ABR Translator will see the P-bit, Translate, and re-flood. + + Later, ABR_TASK and P-bit will scan Type-7 LSDB and translate to + Type-5's to non-NSSA Areas. (it will also attempt a re-install) */ + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + struct ospf_area *area = getdata (node); + + /* make lsa duplicate, lock=1 */ + new2 = ospf_lsa_dup (lsa); + + new2->area = area; + new2->data->type = OSPF_AS_NSSA_LSA; + + /* set P-bit if not ABR */ + if (! IS_OSPF_ABR (ospf)) + { + SET_FLAG(new2->data->options, OSPF_OPTION_NP); + + /* set non-zero FWD ADDR + + draft-ietf-ospf-nssa-update-09.txt + + if the network between the NSSA AS boundary router and the + adjacent AS is advertised into OSPF as an internal OSPF route, + the forwarding address should be the next op address as is cu + currently done with type-5 LSAs. If the intervening network is + not adversited into OSPF as an internal OSPF route and the + type-7 LSA's P-bit is set a forwarding address should be + selected from one of the router's active OSPF inteface addresses + which belong to the NSSA. If no such addresses exist, then + no type-7 LSA's with the P-bit set should originate from this + router. */ + + /* kevinm: not updating lsa anymore, just new2 */ + extlsa = (struct as_external_lsa *)(new2->data); + + if (extlsa->e[0].fwd_addr.s_addr == 0) + extlsa->e[0].fwd_addr = ospf_get_nssa_ip(area); /* this NSSA area in ifp */ + + if (extlsa->e[0].fwd_addr.s_addr == 0) + { + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("LSA[Type-7]: Could not build FWD-ADDR"); + ospf_lsa_discard(new2); + return; + } + } + /* Re-calculate checksum. */ + ospf_lsa_checksum (new2->data); + + /* install also as Type-7 */ + ospf_lsa_install (ospf, NULL, new2); /* Remove Old, Lock New = 2 */ + + /* will send each copy, lock=2+n */ + ospf_flood_through_as (ospf, NULL, new2); /* all attached NSSA's, no AS/STUBs */ + } +} +#endif /* HAVE_NSSA */ + +int +is_prefix_default (struct prefix_ipv4 *p) +{ + struct prefix_ipv4 q; + + q.family = AF_INET; + q.prefix.s_addr = 0; + q.prefixlen = 0; + + return prefix_same ((struct prefix *) p, (struct prefix *) &q); +} + +/* Originate an AS-external-LSA, install and flood. */ +struct ospf_lsa * +ospf_external_lsa_originate (struct ospf *ospf, struct external_info *ei) +{ + struct ospf_lsa *new; + + /* Added for NSSA project.... + + External LSAs are originated in ASBRs as usual, but for NSSA systems. + there is the global Type-5 LSDB and a Type-7 LSDB installed for + every area. The Type-7's are flooded to every IR and every ABR; We + install the Type-5 LSDB so that the normal "refresh" code operates + as usual, and flag them as not used during ASE calculations. The + Type-7 LSDB is used for calculations. Each Type-7 has a Forwarding + Address of non-zero. + + If an ABR is the elected NSSA translator, following SPF and during + the ABR task it will translate all the scanned Type-7's, with P-bit + ON and not-self generated, and translate to Type-5's throughout the + non-NSSA/STUB AS. + + A difference in operation depends whether this ASBR is an ABR + or not. If not an ABR, the P-bit is ON, to indicate that any + elected NSSA-ABR can perform its translation. + + If an ABR, the P-bit is OFF; No ABR will perform translation and + this ASBR will flood the Type-5 LSA as usual. + + For the case where this ASBR is not an ABR, the ASE calculations + are based on the Type-5 LSDB; The Type-7 LSDB exists just to + demonstrate to the user that there are LSA's that belong to any + attached NSSA. + + Finally, it just so happens that when the ABR is translating every + Type-7 into Type-5, it installs it into the Type-5 LSDB as an + approved Type-5 (translated from Type-7); at the end of translation + if any Translated Type-5's remain unapproved, then they must be + flushed from the AS. + + */ + + /* Check the AS-external-LSA should be originated. */ + if (!ospf_redistribute_check (ospf, ei, NULL)) + return NULL; + + /* Create new AS-external-LSA instance. */ + if ((new = ospf_external_lsa_new (ospf, ei, NULL)) == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type5:%s]: Could not originate AS-external-LSA", + inet_ntoa (ei->p.prefix)); + return NULL; + } + + /* Install newly created LSA into Type-5 LSDB, lock = 1. */ + ospf_lsa_install (ospf, NULL, new); + + /* Update LSA origination count. */ + ospf->lsa_originate_count++; + + /* Flooding new LSA. only to AS (non-NSSA/STUB) */ + ospf_flood_through_as (ospf, NULL, new); + +#ifdef HAVE_NSSA + /* If there is any attached NSSA, do special handling */ + if (ospf->anyNSSA) + ospf_install_flood_nssa (ospf, new, ei); /* Install/Flood Type-7 to all NSSAs */ +#endif /* HAVE_NSSA */ + + /* Debug logging. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: Originate AS-external-LSA %p", + new->data->type, inet_ntoa (new->data->id), new); + ospf_lsa_header_dump (new->data); + } + + return new; +} + +/* Originate AS-external-LSA from external info with initial flag. */ +int +ospf_external_lsa_originate_timer (struct thread *thread) +{ + struct ospf *ospf = THREAD_ARG (thread); + struct route_node *rn; + struct external_info *ei; + struct route_table *rt; + int type = THREAD_VAL (thread); + + ospf->t_external_lsa = NULL; + + /* Originate As-external-LSA from all type of distribute source. */ + if ((rt = EXTERNAL_INFO (type))) + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((ei = rn->info) != NULL) + if (!is_prefix_default ((struct prefix_ipv4 *)&ei->p)) + if (!ospf_external_lsa_originate (ospf, ei)) + zlog_warn ("LSA: AS-external-LSA was not originated."); + + return 0; +} + +struct external_info * +ospf_default_external_info (struct ospf *ospf) +{ + int type; + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefix.s_addr = 0; + p.prefixlen = 0; + + /* First, lookup redistributed default route. */ + for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) + if (EXTERNAL_INFO (type) && type != ZEBRA_ROUTE_OSPF) + { + rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) &p); + if (rn != NULL) + { + route_unlock_node (rn); + assert (rn->info); + if (ospf_redistribute_check (ospf, rn->info, NULL)) + return rn->info; + } + } + + return NULL; +} + +int +ospf_default_originate_timer (struct thread *thread) +{ + int *origin; + struct prefix_ipv4 p; + struct in_addr nexthop; + struct external_info *ei; + struct ospf *ospf; + + ospf = ospf_lookup (); + + /* Get originate flags. */ + origin = THREAD_ARG (thread); + + p.family = AF_INET; + p.prefix.s_addr = 0; + p.prefixlen = 0; + + if (*origin == DEFAULT_ORIGINATE_ALWAYS) + { + /* If there is no default route via redistribute, + then originate AS-external-LSA with nexthop 0 (self). */ + nexthop.s_addr = 0; + ospf_external_info_add (DEFAULT_ROUTE, p, 0, nexthop); + } + + if ((ei = ospf_default_external_info (ospf))) + ospf_external_lsa_originate (ospf, ei); + + return 0; +} + +#ifdef HAVE_NSSA +/* Flush any NSSA LSAs for given prefix */ +void +ospf_nssa_lsa_flush (struct ospf *ospf, struct prefix_ipv4 *p) +{ + struct listnode *node; + struct ospf_lsa *lsa; + struct ospf_area *area; + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + if (((area = getdata (node)) != NULL) + && (area->external_routing == OSPF_AREA_NSSA)) + { + if (!(lsa = ospf_lsa_lookup (area, OSPF_AS_NSSA_LSA, p->prefix, + ospf->router_id))) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_warn ("LSA: There is no such AS-NSSA-LSA %s/%d in LSDB", + inet_ntoa (p->prefix), p->prefixlen); + continue; + } + ospf_ls_retransmit_delete_nbr_area (area, lsa); + if (!IS_LSA_MAXAGE (lsa)) + { + ospf_refresher_unregister_lsa (ospf, lsa); + ospf_lsa_flush_area (lsa, area); + } + } + } +} +#endif /* HAVE_NSSA */ + +/* Flush an AS-external-LSA from LSDB and routing domain. */ +void +ospf_external_lsa_flush (struct ospf *ospf, + u_char type, struct prefix_ipv4 *p, + unsigned int ifindex, struct in_addr nexthop) +{ + struct ospf_lsa *lsa; + + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA: Flushing AS-external-LSA %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + + /* First lookup LSA from LSDB. */ + if (!(lsa = ospf_external_info_find_lsa (ospf, p))) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_warn ("LSA: There is no such AS-external-LSA %s/%d in LSDB", + inet_ntoa (p->prefix), p->prefixlen); + return; + } +#ifdef HAVE_NSSA + /* If LSA is selforiginated and there is NSSA area, flush + * Type-7 LSA's at first. */ + + if (IS_LSA_SELF(lsa) && (ospf->anyNSSA)) + ospf_nssa_lsa_flush (ospf, p); +#endif /* HAVE_NSSA */ + + /* Sweep LSA from Link State Retransmit List. */ + ospf_ls_retransmit_delete_nbr_as (ospf, lsa); + + if (!IS_LSA_MAXAGE (lsa)) + { + /* Unregister LSA from Refresh queue. */ + ospf_refresher_unregister_lsa (ospf, lsa); + + /* Flush AS-external-LSA through AS. */ + ospf_lsa_flush_as (ospf, lsa); + } + + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("ospf_external_lsa_flush(): stop"); +} + +void +ospf_external_lsa_refresh_default (struct ospf *ospf) +{ + struct prefix_ipv4 p; + struct external_info *ei; + struct ospf_lsa *lsa; + + p.family = AF_INET; + p.prefixlen = 0; + p.prefix.s_addr = 0; + + ei = ospf_default_external_info (ospf); + lsa = ospf_external_info_find_lsa (ospf, &p); + + if (ei) + { + if (lsa) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", lsa); + ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_FORCE); + } + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type5:0.0.0.0]: Originate AS-external-LSA"); + ospf_external_lsa_originate (ospf, ei); + } + } + else + { + if (lsa) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type5:0.0.0.0]: Flush AS-external-LSA"); + ospf_lsa_flush_as (ospf, lsa); + } + } +} + +void +ospf_external_lsa_refresh_type (struct ospf *ospf, u_char type, int force) +{ + struct route_node *rn; + struct external_info *ei; + + if (type != DEFAULT_ROUTE) + if (EXTERNAL_INFO(type)) + /* Refresh each redistributed AS-external-LSAs. */ + for (rn = route_top (EXTERNAL_INFO (type)); rn; rn = route_next (rn)) + if ((ei = rn->info)) + if (!is_prefix_default (&ei->p)) + { + struct ospf_lsa *lsa; + + if ((lsa = ospf_external_info_find_lsa (ospf, &ei->p))) + ospf_external_lsa_refresh (ospf, lsa, ei, force); + else + ospf_external_lsa_originate (ospf, ei); + } +} + +/* Refresh AS-external-LSA. */ +void +ospf_external_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa, + struct external_info *ei, int force) +{ + struct ospf_lsa *new; + int changed; + + /* Check the AS-external-LSA should be originated. */ + if (!ospf_redistribute_check (ospf, ei, &changed)) + { + ospf_external_lsa_flush (ospf, ei->type, &ei->p, + ei->ifindex, ei->nexthop); + return; + } + + if (!changed && !force) + return; + + /* Delete LSA from neighbor retransmit-list. */ + ospf_ls_retransmit_delete_nbr_as (ospf, lsa); + + /* Unregister AS-external-LSA from refresh-list. */ + ospf_refresher_unregister_lsa (ospf, lsa); + + new = ospf_external_lsa_new (ospf, ei, &lsa->data->id); + + if (new == NULL) + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_warn ("LSA[Type%d:%s]: Could not be refreshed", lsa->data->type, + inet_ntoa (lsa->data->id)); + return; + } + + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + /* Record timestamp. */ + gettimeofday (&new->tv_orig, NULL); + + /* Re-calculate checksum. */ + ospf_lsa_checksum (new->data); + + ospf_lsa_install (ospf, NULL, new); /* As type-5. */ + + /* Flood LSA through AS. */ + ospf_flood_through_as (ospf, NULL, new); + +#ifdef HAVE_NSSA + /* If any attached NSSA, install as Type-7, flood to all NSSA Areas */ + if (ospf->anyNSSA) + ospf_install_flood_nssa (ospf, new, ei); /* Install/Flood per new rules */ +#endif /* HAVE_NSSA */ + + /* Register slef-originated LSA to refresh queue. */ + ospf_refresher_register_lsa (ospf, new); + + /* Debug logging. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: AS-external-LSA refresh", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + + return; +} + + +/* LSA installation functions. */ + +/* Install router-LSA to an area. */ +struct ospf_lsa * +ospf_router_lsa_install (struct ospf *ospf, + struct ospf_lsa *new, int rt_recalc) +{ + struct ospf_area *area = new->area; + + /* RFC 2328 Section 13.2 Router-LSAs and network-LSAs + The entire routing table must be recalculated, starting with + the shortest path calculations for each area (not just the + area whose link-state database has changed). + */ + if (rt_recalc) + ospf_spf_calculate_schedule (ospf); + + if (IS_LSA_SELF (new)) + { + /* Set router-LSA refresh timer. */ + OSPF_TIMER_OFF (area->t_router_lsa_self); + OSPF_AREA_TIMER_ON (area->t_router_lsa_self, + ospf_router_lsa_timer, OSPF_LS_REFRESH_TIME); + + /* Set self-originated router-LSA. */ + ospf_lsa_unlock (area->router_lsa_self); + area->router_lsa_self = ospf_lsa_lock (new); + + if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) + zlog_info("LSA[Type%d]: ID %s is self-originated", + new->data->type, inet_ntoa (new->data->id)); + } + + return new; +} + +#define OSPF_INTERFACE_TIMER_ON(T,F,V) \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), oi, (V)) + +/* Install network-LSA to an area. */ +struct ospf_lsa * +ospf_network_lsa_install (struct ospf *ospf, + struct ospf_interface *oi, + struct ospf_lsa *new, + int rt_recalc) +{ + + /* RFC 2328 Section 13.2 Router-LSAs and network-LSAs + The entire routing table must be recalculated, starting with + the shortest path calculations for each area (not just the + area whose link-state database has changed). + */ + if (rt_recalc) + ospf_spf_calculate_schedule (ospf); + + /* We supposed that when LSA is originated by us, we pass the int + for which it was originated. If LSA was received by flooding, + the RECEIVED flag is set, so we do not link the LSA to the int. */ + if (IS_LSA_SELF (new) && !CHECK_FLAG (new->flags, OSPF_LSA_RECEIVED)) + { + /* Set LSRefresh timer. */ + OSPF_TIMER_OFF (oi->t_network_lsa_self); + + OSPF_INTERFACE_TIMER_ON (oi->t_network_lsa_self, + ospf_network_lsa_refresh_timer, + OSPF_LS_REFRESH_TIME); + + ospf_lsa_unlock (oi->network_lsa_self); + oi->network_lsa_self = ospf_lsa_lock (new); + } + + return new; +} + +/* Install summary-LSA to an area. */ +struct ospf_lsa * +ospf_summary_lsa_install (struct ospf *ospf, struct ospf_lsa *new, + int rt_recalc) +{ + if (rt_recalc && !IS_LSA_SELF (new)) + { + /* RFC 2328 Section 13.2 Summary-LSAs + The best route to the destination described by the summary- + LSA must be recalculated (see Section 16.5). If this + destination is an AS boundary router, it may also be + necessary to re-examine all the AS-external-LSAs. + */ + ospf_spf_calculate_schedule (ospf); + + if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) + zlog_info ("ospf_summary_lsa_install(): SPF scheduled"); + } + + if (IS_LSA_SELF (new)) + ospf_refresher_register_lsa (ospf, new); + + return new; +} + +/* Install ASBR-summary-LSA to an area. */ +struct ospf_lsa * +ospf_summary_asbr_lsa_install (struct ospf *ospf, struct ospf_lsa *new, + int rt_recalc) +{ + if (rt_recalc && !IS_LSA_SELF (new)) + { + /* RFC 2328 Section 13.2 Summary-LSAs + The best route to the destination described by the summary- + LSA must be recalculated (see Section 16.5). If this + destination is an AS boundary router, it may also be + necessary to re-examine all the AS-external-LSAs. + */ + ospf_spf_calculate_schedule (ospf); + } + + /* register LSA to refresh-list. */ + if (IS_LSA_SELF (new)) + ospf_refresher_register_lsa (ospf, new); + + return new; +} + +/* Install AS-external-LSA. */ +struct ospf_lsa * +ospf_external_lsa_install (struct ospf *ospf, struct ospf_lsa *new, + int rt_recalc) +{ + ospf_ase_register_external_lsa (new, ospf); + /* If LSA is not self-originated, calculate an external route. */ + if (rt_recalc) + { + /* RFC 2328 Section 13.2 AS-external-LSAs + The best route to the destination described by the AS- + external-LSA must be recalculated (see Section 16.6). + */ + + if (!IS_LSA_SELF (new)) + ospf_ase_incremental_update (ospf, new); + } + +#ifdef HAVE_NSSA + /* There is no point to register selforiginate Type-7 LSA for + * refreshing. We rely on refreshing Type-5 LSA's */ + if (IS_LSA_SELF (new) && (new->data->type == OSPF_AS_NSSA_LSA)) + return new; +#endif /* HAVE_NSSA */ + + /* Register self-originated LSA to refresh queue. */ + if (IS_LSA_SELF (new)) + ospf_refresher_register_lsa (ospf, new); + + return new; +} + +void +ospf_discard_from_db (struct ospf *ospf, + struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) +{ + struct ospf_lsa *old; + + old = ospf_lsdb_lookup (lsdb, lsa); + + if (!old) + return; + + if (old->refresh_list >= 0) + ospf_refresher_unregister_lsa (ospf, old); + + switch (old->data->type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + ospf_ls_retransmit_delete_nbr_as (ospf, old); + ospf_ase_unregister_external_lsa (old, ospf); + break; +#ifdef HAVE_NSSA + case OSPF_AS_NSSA_LSA: + ospf_ls_retransmit_delete_nbr_area (old->area, old); + ospf_ase_unregister_external_lsa (old, ospf); + break; +#endif /* HAVE_NSSA */ + default: + ospf_ls_retransmit_delete_nbr_area (old->area, old); + break; + } + + ospf_lsa_maxage_delete (ospf, old); + ospf_lsa_discard (old); +} + +struct ospf_lsa * +ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, + struct ospf_lsa *lsa) +{ + struct ospf_lsa *new = NULL; + struct ospf_lsa *old = NULL; + struct ospf_lsdb *lsdb = NULL; + int rt_recalc; + + /* Set LSDB. */ + switch (lsa->data->type) + { +#ifdef HAVE_NSSA + /* kevinm */ + case OSPF_AS_NSSA_LSA: + if (lsa->area) + lsdb = lsa->area->lsdb; + else + lsdb = ospf->lsdb; + break; +#endif /* HAVE_NSSA */ + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + lsdb = ospf->lsdb; + break; + default: + lsdb = lsa->area->lsdb; + break; + } + + assert (lsdb); + + /* RFC 2328 13.2. Installing LSAs in the database + + Installing a new LSA in the database, either as the result of + flooding or a newly self-originated LSA, may cause the OSPF + routing table structure to be recalculated. The contents of the + new LSA should be compared to the old instance, if present. If + there is no difference, there is no need to recalculate the + routing table. When comparing an LSA to its previous instance, + the following are all considered to be differences in contents: + + o The LSA's Options field has changed. + + o One of the LSA instances has LS age set to MaxAge, and + the other does not. + + o The length field in the LSA header has changed. + + o The body of the LSA (i.e., anything outside the 20-byte + LSA header) has changed. Note that this excludes changes + in LS Sequence Number and LS Checksum. + + */ + /* Look up old LSA and determine if any SPF calculation or incremental + update is needed */ + old = ospf_lsdb_lookup (lsdb, lsa); + + /* Do comparision and record if recalc needed. */ + rt_recalc = 0; + if ( old == NULL || ospf_lsa_different(old, lsa)) + rt_recalc = 1; + + /* discard old LSA from LSDB */ + if (old != NULL) + ospf_discard_from_db (ospf, lsdb, lsa); + + /* Insert LSA to LSDB. */ + ospf_lsdb_add (lsdb, lsa); + lsa->lsdb = lsdb; + + /* Calculate Checksum if self-originated?. */ + if (IS_LSA_SELF (lsa)) + ospf_lsa_checksum (lsa->data); + + /* Do LSA specific installation process. */ + switch (lsa->data->type) + { + case OSPF_ROUTER_LSA: + new = ospf_router_lsa_install (ospf, lsa, rt_recalc); + break; + case OSPF_NETWORK_LSA: + assert (oi); + new = ospf_network_lsa_install (ospf, oi, lsa, rt_recalc); + break; + case OSPF_SUMMARY_LSA: + new = ospf_summary_lsa_install (ospf, lsa, rt_recalc); + break; + case OSPF_ASBR_SUMMARY_LSA: + new = ospf_summary_asbr_lsa_install (ospf, lsa, rt_recalc); + break; + case OSPF_AS_EXTERNAL_LSA: + new = ospf_external_lsa_install (ospf, lsa, rt_recalc); + break; +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + if (IS_LSA_SELF (lsa)) + lsa->oi = oi; /* Specify outgoing ospf-interface for this LSA. */ + else + ; /* Incoming "oi" for this LSA has set at LSUpd reception. */ + /* Fallthrough */ + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + new = ospf_opaque_lsa_install (lsa, rt_recalc); + break; +#endif /* HAVE_OPAQUE_LSA */ + default: /* NSSA, or type-6,8,9....nothing special */ +#ifdef HAVE_NSSA + new = ospf_external_lsa_install (ospf, lsa, rt_recalc); +#endif /* HAVE_NSSA */ + break; + } + + if (new == NULL) + return new; /* Installation failed, cannot proceed further -- endo. */ + + /* Debug logs. */ + if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) + { + char area_str[INET_ADDRSTRLEN]; + + switch (lsa->data->type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ +#ifdef HAVE_NSSA + case OSPF_AS_NSSA_LSA: +#endif /* HAVE_NSSA */ + zlog_info ("LSA[%s]: Install %s", + dump_lsa_key (new), + LOOKUP (ospf_lsa_type_msg, new->data->type)); + break; + default: + strcpy (area_str, inet_ntoa (new->area->area_id)); + zlog_info ("LSA[%s]: Install %s to Area %s", + dump_lsa_key (new), + LOOKUP (ospf_lsa_type_msg, new->data->type), area_str); + break; + } + } + + /* If received LSA' ls_age is MaxAge, set LSA on MaxAge LSA list. */ + if (IS_LSA_MAXAGE (new) && !IS_LSA_SELF (new)) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA[Type%d:%s]: Install LSA, MaxAge", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_maxage (ospf, lsa); + } + + return new; +} + + +int +ospf_check_nbr_status (struct ospf *ospf) +{ + listnode node; + + for (node = listhead (ospf->oiflist); node; node = nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + struct route_node *rn; + struct ospf_neighbor *nbr; + + if (ospf_if_is_enable (oi)) + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + if (nbr->state == NSM_Exchange || nbr->state == NSM_Loading) + { + route_unlock_node (rn); + return 0; + } + } + + return 1; +} + + +int +ospf_maxage_lsa_remover (struct thread *thread) +{ + struct ospf *ospf = THREAD_ARG (thread); + listnode node; + listnode next; + int reschedule = 0; + + ospf->t_maxage = NULL; + + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA[MaxAge]: remover Start"); + + reschedule = !ospf_check_nbr_status (ospf); + + if (!reschedule) + for (node = listhead (ospf->maxage_lsa); node; node = next) + { + struct ospf_lsa *lsa = getdata (node); + next = node->next; + + if (lsa->retransmit_counter > 0) + { + reschedule = 1; + continue; + } + + /* Remove LSA from the LSDB */ + if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)) + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA[Type%d:%s]: This LSA is self-originated: ", + lsa->data->type, inet_ntoa (lsa->data->id)); + + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA[Type%d:%s]: MaxAge LSA removed from list", + lsa->data->type, inet_ntoa (lsa->data->id)); + + /* Flood max age LSA. */ + ospf_flood_through (ospf, NULL, lsa); + + /* Remove from lsdb. */ + ospf_discard_from_db (ospf, lsa->lsdb, lsa); + ospf_lsdb_delete (lsa->lsdb, lsa); + } + + /* A MaxAge LSA must be removed immediately from the router's link + state database as soon as both a) it is no longer contained on any + neighbor Link state retransmission lists and b) none of the router's + neighbors are in states Exchange or Loading. */ + if (reschedule) + OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, 2); + + return 0; +} + +int +ospf_lsa_maxage_exist (struct ospf *ospf, struct ospf_lsa *new) +{ + listnode node; + + for (node = listhead (ospf->maxage_lsa); node; nextnode (node)) + if (((struct ospf_lsa *) node->data) == new) + return 1; + + return 0; +} + +void +ospf_lsa_maxage_delete (struct ospf *ospf, struct ospf_lsa *lsa) +{ + listnode n; + + if ((n = listnode_lookup (ospf->maxage_lsa, lsa))) + { + list_delete_node (ospf->maxage_lsa, n); + ospf_lsa_unlock (lsa); + } +} + +void +ospf_lsa_maxage (struct ospf *ospf, struct ospf_lsa *lsa) +{ + /* When we saw a MaxAge LSA flooded to us, we put it on the list + and schedule the MaxAge LSA remover. */ + if (ospf_lsa_maxage_exist (ospf, lsa)) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA[Type%d:%s]: %p already exists on MaxAge LSA list", + lsa->data->type, inet_ntoa (lsa->data->id), lsa); + return; + } + + listnode_add (ospf->maxage_lsa, ospf_lsa_lock (lsa)); + + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info ("LSA[%s]: MaxAge LSA remover scheduled.", dump_lsa_key (lsa)); + + OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, 2); +} + +int +ospf_lsa_maxage_walker_remover (struct ospf *ospf, struct ospf_lsa *lsa) +{ +#ifdef HAVE_NSSA + /* Stay away from any Local Translated Type-7 LSAs */ + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) + return 0; +#endif /* HAVE_NSSA */ + + if (IS_LSA_MAXAGE (lsa)) + /* Self-originated LSAs should NOT time-out instead, + they're flushed and submitted to the max_age list explicitly. */ + if (!ospf_lsa_is_self_originated (ospf, lsa)) + { + if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) + zlog_info("LSA[%s]: is MaxAge", dump_lsa_key (lsa)); + + switch (lsa->data->type) + { +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + /* + * As a general rule, whenever network topology has changed + * (due to an LSA removal in this case), routing recalculation + * should be triggered. However, this is not true for opaque + * LSAs. Even if an opaque LSA instance is going to be removed + * from the routing domain, it does not mean a change in network + * topology, and thus, routing recalculation is not needed here. + */ + break; +#endif /* HAVE_OPAQUE_LSA */ + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_NSSA + case OSPF_AS_NSSA_LSA: +#endif /* HAVE_NSSA */ + ospf_ase_incremental_update (ospf, lsa); + break; + default: + ospf_spf_calculate_schedule (ospf); + break; + } + + ospf_lsa_maxage (ospf, lsa); + } + + return 0; +} + +/* Periodical check of MaxAge LSA. */ +int +ospf_lsa_maxage_walker (struct thread *thread) +{ + struct ospf *ospf = THREAD_ARG (thread); + struct route_node *rn; + struct ospf_lsa *lsa; + listnode node; + + ospf->t_maxage_walker = NULL; + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + struct ospf_area *area = node->data; + + LSDB_LOOP (ROUTER_LSDB (area), rn, lsa) + ospf_lsa_maxage_walker_remover (ospf, lsa); + LSDB_LOOP (NETWORK_LSDB (area), rn, lsa) + ospf_lsa_maxage_walker_remover (ospf, lsa); + LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) + ospf_lsa_maxage_walker_remover (ospf, lsa); + LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) + ospf_lsa_maxage_walker_remover (ospf, lsa); +#ifdef HAVE_OPAQUE_LSA + LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) + ospf_lsa_maxage_walker_remover (ospf, lsa); + LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) + ospf_lsa_maxage_walker_remover (ospf, lsa); +#endif /* HAVE_OPAQUE_LSA */ +#ifdef HAVE_NSSA + LSDB_LOOP (NSSA_LSDB (area), rn, lsa) + ospf_lsa_maxage_walker_remover (ospf, lsa); +#endif /* HAVE_NSSA */ + + } + + /* for AS-eternal-LSAs. */ + if (ospf->lsdb) + { + LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) + ospf_lsa_maxage_walker_remover (ospf, lsa); +#ifdef HAVE_OPAQUE_LSA + LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) + ospf_lsa_maxage_walker_remover (ospf, lsa); +#endif /* HAVE_OPAQUE_LSA */ + } + + OSPF_TIMER_ON (ospf->t_maxage_walker, ospf_lsa_maxage_walker, + OSPF_LSA_MAXAGE_CHECK_INTERVAL); + return 0; +} + +struct ospf_lsa * +ospf_lsa_lookup_by_prefix (struct ospf_lsdb *lsdb, u_char type, + struct prefix_ipv4 *p, struct in_addr router_id) +{ + struct ospf_lsa *lsa; + struct in_addr mask, id; + struct lsa_header_mask + { + struct lsa_header header; + struct in_addr mask; + } *hmask; + + lsa = ospf_lsdb_lookup_by_id (lsdb, type, p->prefix, router_id); + if (lsa == NULL) + return NULL; + + masklen2ip (p->prefixlen, &mask); + + hmask = (struct lsa_header_mask *) lsa->data; + + if (mask.s_addr != hmask->mask.s_addr) + { + id.s_addr = p->prefix.s_addr | (~mask.s_addr); + lsa = ospf_lsdb_lookup_by_id (lsdb, type, id, router_id); + if (!lsa) + return NULL; + } + + return lsa; +} + +struct ospf_lsa * +ospf_lsa_lookup (struct ospf_area *area, u_int32_t type, + struct in_addr id, struct in_addr adv_router) +{ + switch (type) + { + case OSPF_ROUTER_LSA: + case OSPF_NETWORK_LSA: + case OSPF_SUMMARY_LSA: + case OSPF_ASBR_SUMMARY_LSA: +#ifdef HAVE_NSSA + case OSPF_AS_NSSA_LSA: +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: +#endif /* HAVE_OPAQUE_LSA */ + return ospf_lsdb_lookup_by_id (area->lsdb, type, id, adv_router); + break; + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + return ospf_lsdb_lookup_by_id (area->ospf->lsdb, type, id, adv_router); + break; + default: + break; + } + + return NULL; +} + +struct ospf_lsa * +ospf_lsa_lookup_by_id (struct ospf_area *area, u_int32_t type, + struct in_addr id) +{ + struct ospf_lsa *lsa; + struct route_node *rn; + + switch (type) + { + case OSPF_ROUTER_LSA: + return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id); + break; + case OSPF_NETWORK_LSA: + for (rn = route_top (NETWORK_LSDB (area)); rn; rn = route_next (rn)) + if ((lsa = rn->info)) + if (IPV4_ADDR_SAME (&lsa->data->id, &id)) + { + route_unlock_node (rn); + return lsa; + } + break; + case OSPF_SUMMARY_LSA: + case OSPF_ASBR_SUMMARY_LSA: + /* Currently not used. */ + assert (1); + return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id); + break; + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + /* Currently not used. */ + break; +#endif /* HAVE_OPAQUE_LSA */ + default: + break; + } + + return NULL; +} + +struct ospf_lsa * +ospf_lsa_lookup_by_header (struct ospf_area *area, struct lsa_header *lsah) +{ + struct ospf_lsa *match; + +#ifdef HAVE_OPAQUE_LSA + /* + * Strictly speaking, the LSA-ID field for Opaque-LSAs (type-9/10/11) + * is redefined to have two subfields; opaque-type and opaque-id. + * However, it is harmless to treat the two sub fields together, as if + * they two were forming a unique LSA-ID. + */ +#endif /* HAVE_OPAQUE_LSA */ + + match = ospf_lsa_lookup (area, lsah->type, lsah->id, lsah->adv_router); + + if (match == NULL) + if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) + zlog_info ("LSA[Type%d:%s]: Lookup by header, NO MATCH", + lsah->type, inet_ntoa (lsah->id)); + + return match; +} + +/* return +n, l1 is more recent. + return -n, l2 is more recent. + return 0, l1 and l2 is identical. */ +int +ospf_lsa_more_recent (struct ospf_lsa *l1, struct ospf_lsa *l2) +{ + int r; + int x, y; + + if (l1 == NULL && l2 == NULL) + return 0; + if (l1 == NULL) + return -1; + if (l2 == NULL) + return 1; + + /* compare LS sequence number. */ + x = (int) ntohl (l1->data->ls_seqnum); + y = (int) ntohl (l2->data->ls_seqnum); + if (x > y) + return 1; + if (x < y) + return -1; + + /* compare LS checksum. */ + r = ntohs (l1->data->checksum) - ntohs (l2->data->checksum); + if (r) + return r; + + /* compare LS age. */ + if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2)) + return 1; + else if (!IS_LSA_MAXAGE (l1) && IS_LSA_MAXAGE (l2)) + return -1; + + /* compare LS age with MaxAgeDiff. */ + if (LS_AGE (l1) - LS_AGE (l2) > OSPF_LSA_MAXAGE_DIFF) + return -1; + else if (LS_AGE (l2) - LS_AGE (l1) > OSPF_LSA_MAXAGE_DIFF) + return 1; + + /* LSAs are identical. */ + return 0; +} + +/* If two LSAs are different, return 1, otherwise return 0. */ +int +ospf_lsa_different (struct ospf_lsa *l1, struct ospf_lsa *l2) +{ + char *p1, *p2; + assert (l1); + assert (l2); + assert (l1->data); + assert (l2->data); + + if (l1->data->options != l2->data->options) + return 1; + + if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2)) + return 1; + + if (IS_LSA_MAXAGE (l2) && !IS_LSA_MAXAGE (l1)) + return 1; + + if (l1->data->length != l2->data->length) + return 1; + + if (l1->data->length == 0) + return 1; + + assert (ntohs (l1->data->length) > OSPF_LSA_HEADER_SIZE); + + p1 = (char *) l1->data; + p2 = (char *) l2->data; + + if (memcmp (p1 + OSPF_LSA_HEADER_SIZE, p2 + OSPF_LSA_HEADER_SIZE, + ntohs (l1->data->length) - OSPF_LSA_HEADER_SIZE) != 0) + return 1; + + return 0; +} + +static int +ospf_lsa_flush_schedule (struct ospf *ospf, struct ospf_lsa *lsa) +{ + if (lsa == NULL || !IS_LSA_SELF (lsa)) + return 0; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id)); + + /* Force given lsa's age to MaxAge. */ + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + + switch (lsa->data->type) + { +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + ospf_opaque_lsa_refresh (lsa); + break; +#endif /* HAVE_OPAQUE_LSA */ + default: + ospf_lsa_maxage (ospf, lsa); + break; + } + + return 0; +} + +void +ospf_flush_self_originated_lsas_now (struct ospf *ospf) +{ + listnode n1, n2; + struct ospf_area *area; + struct ospf_interface *oi; + struct ospf_lsa *lsa; + struct route_node *rn; + int need_to_flush_ase = 0; + + for (n1 = listhead (ospf->areas); n1; nextnode (n1)) + { + if ((area = getdata (n1)) == NULL) + continue; + + if ((lsa = area->router_lsa_self) != NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id)); + + ospf_lsa_flush_area (lsa, area); + ospf_lsa_unlock (area->router_lsa_self); + area->router_lsa_self = NULL; + OSPF_TIMER_OFF (area->t_router_lsa_self); + } + + for (n2 = listhead (area->oiflist); n2; nextnode (n2)) + { + if ((oi = getdata (n2)) == NULL) + continue; + + if ((lsa = oi->network_lsa_self) != NULL + && oi->state == ISM_DR + && oi->full_nbrs > 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id)); + + ospf_lsa_flush_area (oi->network_lsa_self, area); + ospf_lsa_unlock (oi->network_lsa_self); + oi->network_lsa_self = NULL; + OSPF_TIMER_OFF (oi->t_network_lsa_self); + } + + if (oi->type != OSPF_IFTYPE_VIRTUALLINK + && area->external_routing == OSPF_AREA_DEFAULT) + need_to_flush_ase = 1; + } + + LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) + ospf_lsa_flush_schedule (ospf, lsa); + LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) + ospf_lsa_flush_schedule (ospf, lsa); +#ifdef HAVE_OPAQUE_LSA + LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) + ospf_lsa_flush_schedule (ospf, lsa); + LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) + ospf_lsa_flush_schedule (ospf, lsa); +#endif /* HAVE_OPAQUE_LSA */ + } + + if (need_to_flush_ase) + { + LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) + ospf_lsa_flush_schedule (ospf, lsa); +#ifdef HAVE_OPAQUE_LSA + LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) + ospf_lsa_flush_schedule (ospf, lsa); +#endif /* HAVE_OPAQUE_LSA */ + } + + /* + * Make sure that the MaxAge LSA remover is executed immediately, + * without conflicting to other threads. + */ + if (ospf->t_maxage != NULL) + { + OSPF_TIMER_OFF (ospf->t_maxage); + thread_execute (master, ospf_maxage_lsa_remover, ospf, 0); + } + + return; +} + +/* If there is self-originated LSA, then return 1, otherwise return 0. */ +/* An interface-independent version of ospf_lsa_is_self_originated */ +int +ospf_lsa_is_self_originated (struct ospf *ospf, struct ospf_lsa *lsa) +{ + listnode node; + + /* This LSA is already checked. */ + if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED)) + return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF); + + /* Make sure LSA is self-checked. */ + SET_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED); + + /* AdvRouter and Router ID is the same. */ + if (IPV4_ADDR_SAME (&lsa->data->adv_router, &ospf->router_id)) + SET_FLAG (lsa->flags, OSPF_LSA_SELF); + + /* LSA is router-LSA. */ + else if (lsa->data->type == OSPF_ROUTER_LSA && + IPV4_ADDR_SAME (&lsa->data->id, &ospf->router_id)) + SET_FLAG (lsa->flags, OSPF_LSA_SELF); + + /* LSA is network-LSA. Compare Link ID with all interfaces. */ + else if (lsa->data->type == OSPF_NETWORK_LSA) + for (node = listhead (ospf->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + + /* Ignore virtual link. */ + if (oi->type != OSPF_IFTYPE_VIRTUALLINK) + if (oi->address->family == AF_INET) + if (IPV4_ADDR_SAME (&lsa->data->id, &oi->address->u.prefix4)) + { + /* to make it easier later */ + SET_FLAG (lsa->flags, OSPF_LSA_SELF); + return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF); + } + } + + return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF); +} + +/* Get unique Link State ID. */ +struct in_addr +ospf_lsa_unique_id (struct ospf *ospf, + struct ospf_lsdb *lsdb, u_char type, struct prefix_ipv4 *p) +{ + struct ospf_lsa *lsa; + struct in_addr mask, id; + + id = p->prefix; + + /* Check existence of LSA instance. */ + lsa = ospf_lsdb_lookup_by_id (lsdb, type, id, ospf->router_id); + if (lsa) + { + struct as_external_lsa *al = (struct as_external_lsa *) lsa->data; + if (ip_masklen (al->mask) == p->prefixlen) + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_warn ("ospf_lsa_unique_id(): " + "Can't get Link State ID for %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + /* id.s_addr = 0; */ + id.s_addr = 0xffffffff; + return id; + } + /* Masklen differs, then apply wildcard mask to Link State ID. */ + else + { + masklen2ip (p->prefixlen, &mask); + + id.s_addr = p->prefix.s_addr | (~mask.s_addr); + lsa = ospf_lsdb_lookup_by_id (ospf->lsdb, type, + id, ospf->router_id); + if (lsa) + { + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_warn ("ospf_lsa_unique_id(): " + "Can't get Link State ID for %s/%d", + inet_ntoa (p->prefix), p->prefixlen); + /* id.s_addr = 0; */ + id.s_addr = 0xffffffff; + return id; + } + } + } + + return id; +} + + +#define LSA_ACTION_ORIGN_RTR 1 +#define LSA_ACTION_ORIGN_NET 2 +#define LSA_ACTION_FLOOD_AREA 3 +#define LSA_ACTION_FLOOD_AS 4 +#define LSA_ACTION_FLUSH_AREA 5 +#define LSA_ACTION_FLUSH_AS 6 + +struct lsa_action +{ + u_char action; + struct ospf_area *area; + struct ospf_interface *oi; + struct ospf_lsa *lsa; +}; + +int +ospf_lsa_action (struct thread *t) +{ + struct lsa_action *data; + struct ospf *ospf; + + ospf = ospf_lookup (); + + data = THREAD_ARG (t); + + if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) + zlog_info ("LSA[Action]: Performing scheduled LSA action: %d", + data->action); + + switch (data->action) + { + case LSA_ACTION_ORIGN_RTR: + ospf_router_lsa_refresh (data->area->router_lsa_self); + break; + case LSA_ACTION_ORIGN_NET: + ospf_network_lsa_originate (data->oi); + break; + case LSA_ACTION_FLOOD_AREA: + ospf_flood_through_area (data->area, NULL, data->lsa); + break; + case LSA_ACTION_FLOOD_AS: + ospf_flood_through_as (ospf, NULL, data->lsa); + break; + case LSA_ACTION_FLUSH_AREA: + ospf_lsa_flush_area (data->lsa, data->area); + break; + case LSA_ACTION_FLUSH_AS: + ospf_lsa_flush_as (ospf, data->lsa); + break; + } + + ospf_lsa_unlock (data->lsa); + XFREE (MTYPE_OSPF_MESSAGE, data); + return 0; +} + +void +ospf_schedule_lsa_flood_area (struct ospf_area *area, struct ospf_lsa *lsa) +{ + struct lsa_action *data; + + data = XMALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action)); + memset (data, 0, sizeof (struct lsa_action)); + + data->action = LSA_ACTION_FLOOD_AREA; + data->area = area; + data->lsa = ospf_lsa_lock (lsa); + + thread_add_event (master, ospf_lsa_action, data, 0); +} + +void +ospf_schedule_lsa_flush_area (struct ospf_area *area, struct ospf_lsa *lsa) +{ + struct lsa_action *data; + + data = XMALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action)); + memset (data, 0, sizeof (struct lsa_action)); + + data->action = LSA_ACTION_FLUSH_AREA; + data->area = area; + data->lsa = ospf_lsa_lock (lsa); + + thread_add_event (master, ospf_lsa_action, data, 0); +} + + +/* LSA Refreshment functions. */ +void +ospf_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) +{ + struct external_info *ei; + assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)); + + switch (lsa->data->type) + { + /* Router and Network LSAs are processed differently. */ + case OSPF_ROUTER_LSA: + case OSPF_NETWORK_LSA: + break; + case OSPF_SUMMARY_LSA: + ospf_summary_lsa_refresh (ospf, lsa); + break; + case OSPF_ASBR_SUMMARY_LSA: + ospf_summary_asbr_lsa_refresh (ospf, lsa); + break; + case OSPF_AS_EXTERNAL_LSA: + ei = ospf_external_info_check (lsa); + if (ei) + ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_FORCE); + else + ospf_lsa_flush_as (ospf, lsa); + break; +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + ospf_opaque_lsa_refresh (lsa); + break; +#endif /* HAVE_OPAQUE_LSA */ + default: + break; + } +} + +void +ospf_refresher_register_lsa (struct ospf *ospf, struct ospf_lsa *lsa) +{ + u_int16_t index, current_index; + + assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)); + + if (lsa->refresh_list < 0) + { + int delay; + + if (LS_AGE (lsa) == 0 && + ntohl (lsa->data->ls_seqnum) == OSPF_INITIAL_SEQUENCE_NUMBER) + /* Randomize first update by OSPF_LS_REFRESH_SHIFT factor */ + delay = OSPF_LS_REFRESH_SHIFT + (random () % OSPF_LS_REFRESH_TIME); + else + /* Randomize another updates by +-OSPF_LS_REFRESH_JITTER factor */ + delay = OSPF_LS_REFRESH_TIME - LS_AGE (lsa) - OSPF_LS_REFRESH_JITTER + + (random () % (2*OSPF_LS_REFRESH_JITTER)); + + if (delay < 0) + delay = 0; + + current_index = ospf->lsa_refresh_queue.index + + (time (NULL) - ospf->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY; + + index = (current_index + delay/OSPF_LSA_REFRESHER_GRANULARITY) + % (OSPF_LSA_REFRESHER_SLOTS); + + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + zlog_info ("LSA[Refresh]: lsa with age %d added to index %d", + LS_AGE (lsa), index); + if (!ospf->lsa_refresh_queue.qs[index]) + ospf->lsa_refresh_queue.qs[index] = list_new (); + listnode_add (ospf->lsa_refresh_queue.qs[index], ospf_lsa_lock (lsa)); + lsa->refresh_list = index; + } +} + +void +ospf_refresher_unregister_lsa (struct ospf *ospf, struct ospf_lsa *lsa) +{ + assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)); + if (lsa->refresh_list >= 0) + { + list refresh_list = ospf->lsa_refresh_queue.qs[lsa->refresh_list]; + listnode_delete (refresh_list, lsa); + if (!listcount (refresh_list)) + { + list_free (refresh_list); + ospf->lsa_refresh_queue.qs[lsa->refresh_list] = NULL; + } + ospf_lsa_unlock (lsa); + lsa->refresh_list = -1; + } +} + +int +ospf_lsa_refresh_walker (struct thread *t) +{ + list refresh_list; + listnode node; + struct ospf *ospf = THREAD_ARG (t); + int i; + list lsa_to_refresh = list_new (); + + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + zlog_info ("LSA[Refresh]:ospf_lsa_refresh_walker(): start"); + + + i = ospf->lsa_refresh_queue.index; + + ospf->lsa_refresh_queue.index = + (ospf->lsa_refresh_queue.index + + (time (NULL) - ospf->lsa_refresher_started) / OSPF_LSA_REFRESHER_GRANULARITY) + % OSPF_LSA_REFRESHER_SLOTS; + + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): next index %d", + ospf->lsa_refresh_queue.index); + + for (;i != ospf->lsa_refresh_queue.index; + i = (i + 1) % OSPF_LSA_REFRESHER_SLOTS) + { + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): refresh index %d", i); + + refresh_list = ospf->lsa_refresh_queue.qs [i]; + + ospf->lsa_refresh_queue.qs [i] = NULL; + + if (refresh_list) + { + for (node = listhead (refresh_list); node;) + { + listnode next; + struct ospf_lsa *lsa = getdata (node); + next = node->next; + + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): refresh lsa %p", lsa); + + list_delete_node (refresh_list, node); + ospf_lsa_unlock (lsa); + lsa->refresh_list = -1; + listnode_add (lsa_to_refresh, lsa); + node = next; + } + list_free (refresh_list); + } + } + + ospf->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, + ospf, ospf->lsa_refresh_interval); + ospf->lsa_refresher_started = time (NULL); + + for (node = listhead (lsa_to_refresh); node; nextnode (node)) + ospf_lsa_refresh (ospf, getdata (node)); + + list_delete (lsa_to_refresh); + + if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) + zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): end"); + + return 0; +} + diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h new file mode 100644 index 0000000..878b107 --- /dev/null +++ b/ospfd/ospf_lsa.h @@ -0,0 +1,323 @@ +/* + * OSPF Link State Advertisement + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_LSA_H +#define _ZEBRA_OSPF_LSA_H + +/* OSPF LSA Range definition. */ +#define OSPF_MIN_LSA 1 /* begin range here */ +#if defined (HAVE_OPAQUE_LSA) +#define OSPF_MAX_LSA 12 +#elif defined (HAVE_NSSA) +#define OSPF_MAX_LSA 8 +#else +#define OSPF_MAX_LSA 6 +#endif + +/* OSPF LSA Type definition. */ +#define OSPF_UNKNOWN_LSA 0 +#define OSPF_ROUTER_LSA 1 +#define OSPF_NETWORK_LSA 2 +#define OSPF_SUMMARY_LSA 3 +#define OSPF_ASBR_SUMMARY_LSA 4 +#define OSPF_AS_EXTERNAL_LSA 5 +#define OSPF_GROUP_MEMBER_LSA 6 /* Not supported. */ +#define OSPF_AS_NSSA_LSA 7 +#define OSPF_EXTERNAL_ATTRIBUTES_LSA 8 /* Not supported. */ +#define OSPF_OPAQUE_LINK_LSA 9 +#define OSPF_OPAQUE_AREA_LSA 10 +#define OSPF_OPAQUE_AS_LSA 11 + +#define OSPF_LSA_HEADER_SIZE 20 +#define OSPF_MAX_LSA_SIZE 1500 + +/* AS-external-LSA refresh method. */ +#define LSA_REFRESH_IF_CHANGED 0 +#define LSA_REFRESH_FORCE 1 + +/* OSPF LSA header. */ +struct lsa_header +{ + u_int16_t ls_age; + u_char options; + u_char type; + struct in_addr id; + struct in_addr adv_router; + int ls_seqnum; + u_int16_t checksum; + u_int16_t length; +}; + +/* OSPF LSA. */ +struct ospf_lsa +{ + /* LSA origination flag. */ + u_char flags; +#define OSPF_LSA_SELF 0x01 +#define OSPF_LSA_SELF_CHECKED 0x02 +#define OSPF_LSA_RECEIVED 0x04 +#define OSPF_LSA_APPROVED 0x08 +#define OSPF_LSA_DISCARD 0x10 +#ifdef HAVE_NSSA +#define OSPF_LSA_LOCAL_XLT 0x20 +#endif /* HAVE_NSSA */ + + /* LSA data. */ + struct lsa_header *data; + + /* Received time stamp. */ + struct timeval tv_recv; + + /* Last time it was originated */ + struct timeval tv_orig; + + /* All of reference count, also lock to remove. */ + int lock; + + /* References to this LSA in neighbor retransmission lists*/ + int retransmit_counter; + + /* Area the LSA belongs to, may be NULL if AS-external-LSA. */ + struct ospf_area *area; + + /* Parent LSDB. */ + struct ospf_lsdb *lsdb; + + /* Related Route. */ + void *route; + + /* Refreshement List or Queue */ + int refresh_list; + +#ifdef HAVE_OPAQUE_LSA + /* For Type-9 Opaque-LSAs, reference to ospf-interface is required. */ + struct ospf_interface *oi; +#endif /* HAVE_OPAQUE_LSA */ +}; + +/* OSPF LSA Link Type. */ +#define LSA_LINK_TYPE_POINTOPOINT 1 +#define LSA_LINK_TYPE_TRANSIT 2 +#define LSA_LINK_TYPE_STUB 3 +#define LSA_LINK_TYPE_VIRTUALLINK 4 + +/* OSPF Router LSA Flag. */ +#define ROUTER_LSA_BORDER 0x01 /* The router is an ABR */ +#define ROUTER_LSA_EXTERNAL 0x02 /* The router is an ASBR */ +#define ROUTER_LSA_VIRTUAL 0x04 /* The router has a VL in this area */ +#define ROUTER_LSA_NT 0x10 /* NSSA-specific flag */ +#define ROUTER_LSA_SHORTCUT 0x20 /* Shortcut-ABR specific flag */ + +#define IS_ROUTER_LSA_VIRTUAL(x) ((x)->flags & ROUTER_LSA_VIRTUAL) +#define IS_ROUTER_LSA_EXTERNAL(x) ((x)->flags & ROUTER_LSA_EXTERNAL) +#define IS_ROUTER_LSA_BORDER(x) ((x)->flags & ROUTER_LSA_BORDER) +#define IS_ROUTER_LSA_SHORTCUT(x) ((x)->flags & ROUTER_LSA_SHORTCUT) + +/* OSPF Router-LSA Link information. */ +struct router_lsa_link +{ + struct in_addr link_id; + struct in_addr link_data; + struct + { + u_char type; + u_char tos_count; + u_int16_t metric; + } m[1]; +}; + +/* OSPF Router-LSAs structure. */ +struct router_lsa +{ + struct lsa_header header; + u_char flags; + u_char zero; + u_int16_t links; + struct + { + struct in_addr link_id; + struct in_addr link_data; + u_char type; + u_char tos; + u_int16_t metric; + } link[1]; +}; + +/* OSPF Network-LSAs structure. */ +struct network_lsa +{ + struct lsa_header header; + struct in_addr mask; + struct in_addr routers[1]; +}; + +/* OSPF Summary-LSAs structure. */ +struct summary_lsa +{ + struct lsa_header header; + struct in_addr mask; + u_char tos; + u_char metric[3]; +}; + +/* OSPF AS-external-LSAs structure. */ +struct as_external_lsa +{ + struct lsa_header header; + struct in_addr mask; + struct + { + u_char tos; + u_char metric[3]; + struct in_addr fwd_addr; + u_int32_t route_tag; + } e[1]; +}; + +#ifdef HAVE_OPAQUE_LSA +#include "ospfd/ospf_opaque.h" +#endif /* HAVE_OPAQUE_LSA */ + +/* Macros. */ +#define GET_METRIC(x) get_metric(x) +#define IS_EXTERNAL_METRIC(x) ((x) & 0x80) + +#define GET_AGE(x) (ntohs ((x)->data->ls_age) + time (NULL) - (x)->tv_recv) +#define LS_AGE(x) (OSPF_LSA_MAXAGE < get_age(x) ? \ + OSPF_LSA_MAXAGE : get_age(x)) +#define IS_LSA_SELF(L) (CHECK_FLAG ((L)->flags, OSPF_LSA_SELF)) +#define IS_LSA_MAXAGE(L) (LS_AGE ((L)) == OSPF_LSA_MAXAGE) + +#define OSPF_LSA_UPDATE_DELAY 2 + +#define OSPF_LSA_UPDATE_TIMER_ON(T,F) \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), 0, 2) + +struct ospf_route; +struct ospf_lsdb; + +/* Prototypes. */ +struct timeval tv_adjust (struct timeval); +int tv_ceil (struct timeval); +int tv_floor (struct timeval); +struct timeval int2tv (int); +struct timeval tv_add (struct timeval, struct timeval); +struct timeval tv_sub (struct timeval, struct timeval); +int tv_cmp (struct timeval, struct timeval); + +int get_age (struct ospf_lsa *); +u_int16_t ospf_lsa_checksum (struct lsa_header *); + +struct stream; +const char *dump_lsa_key (struct ospf_lsa *); +u_int32_t lsa_seqnum_increment (struct ospf_lsa *); +void lsa_header_set (struct stream *, u_char, u_char, struct in_addr, + struct in_addr); +struct ospf_neighbor *ospf_nbr_lookup_ptop (struct ospf_interface *); + +/* Prototype for LSA primitive. */ +struct ospf_lsa *ospf_lsa_new (); +struct ospf_lsa *ospf_lsa_dup (); +void ospf_lsa_free (struct ospf_lsa *); +struct ospf_lsa *ospf_lsa_lock (struct ospf_lsa *); +void ospf_lsa_unlock (struct ospf_lsa *); +void ospf_lsa_discard (struct ospf_lsa *); + +struct lsa_header *ospf_lsa_data_new (size_t); +struct lsa_header *ospf_lsa_data_dup (struct lsa_header *); +void ospf_lsa_data_free (struct lsa_header *); + +/* Prototype for various LSAs */ +struct ospf_lsa *ospf_router_lsa_originate (struct ospf_area *); +int ospf_router_lsa_update_timer (struct thread *); +void ospf_router_lsa_timer_add (struct ospf_area *); + +int ospf_network_lsa_refresh (struct ospf_lsa *, struct ospf_interface *); +void ospf_network_lsa_timer_add (struct ospf_interface *); + +struct ospf_lsa *ospf_summary_lsa_originate (struct prefix_ipv4 *, u_int32_t, + struct ospf_area *); +struct ospf_lsa *ospf_summary_asbr_lsa_originate (struct prefix_ipv4 *, + u_int32_t, + struct ospf_area *); +struct ospf_lsa *ospf_summary_lsa_refresh (struct ospf *, struct ospf_lsa *); +struct ospf_lsa *ospf_summary_asbr_lsa_refresh (struct ospf *, struct ospf_lsa *); + +struct ospf_lsa *ospf_lsa_install (struct ospf *, + struct ospf_interface *, struct ospf_lsa *); + +void ospf_nssa_lsa_flush (struct ospf *ospf, struct prefix_ipv4 *p); +void ospf_external_lsa_flush (struct ospf *, u_char, struct prefix_ipv4 *, + unsigned int, struct in_addr); + +struct in_addr ospf_get_ip_from_ifp (struct ospf_interface *); + +struct ospf_lsa *ospf_external_lsa_originate (struct ospf *, struct external_info *); +int ospf_external_lsa_originate_timer (struct thread *); +struct ospf_lsa *ospf_lsa_lookup (struct ospf_area *, u_int32_t, + struct in_addr, struct in_addr); +struct ospf_lsa *ospf_lsa_lookup_by_id (struct ospf_area *,u_int32_t, struct in_addr); +struct ospf_lsa *ospf_lsa_lookup_by_header (struct ospf_area *, + struct lsa_header *); +int ospf_lsa_more_recent (struct ospf_lsa *, struct ospf_lsa *); +int ospf_lsa_different (struct ospf_lsa *, struct ospf_lsa *); +void ospf_flush_self_originated_lsas_now (struct ospf *); + +int ospf_lsa_is_self_originated (struct ospf *, struct ospf_lsa *); + +struct ospf_lsa *ospf_lsa_lookup_by_prefix (struct ospf_lsdb *, u_char, + struct prefix_ipv4 *, + struct in_addr); + +void ospf_lsa_maxage (struct ospf *, struct ospf_lsa *); +u_int32_t get_metric (u_char *); + +int ospf_lsa_maxage_walker (struct thread *); + +void ospf_external_lsa_refresh_default (struct ospf *); + +void ospf_external_lsa_refresh_type (struct ospf *, u_char, int); +void ospf_external_lsa_refresh (struct ospf *, struct ospf_lsa *, + struct external_info *, int); +struct in_addr ospf_lsa_unique_id (struct ospf *, struct ospf_lsdb *, u_char, + struct prefix_ipv4 *); +void ospf_schedule_lsa_flood_area (struct ospf_area *, struct ospf_lsa *); +void ospf_schedule_lsa_flush_area (struct ospf_area *, struct ospf_lsa *); + +void ospf_refresher_register_lsa (struct ospf *, struct ospf_lsa *); +void ospf_refresher_unregister_lsa (struct ospf *, struct ospf_lsa *); +int ospf_lsa_refresh_walker (struct thread *); + +void ospf_lsa_maxage_delete (struct ospf *, struct ospf_lsa *); + +void ospf_discard_from_db (struct ospf *, struct ospf_lsdb *, struct ospf_lsa*); +int is_prefix_default (struct prefix_ipv4 *); + +int metric_type (struct ospf *, u_char); +int metric_value (struct ospf *, u_char); + +#ifdef HAVE_NSSA +struct in_addr ospf_get_nssa_ip (struct ospf_area *); +#endif /* HAVE NSSA */ + +#endif /* _ZEBRA_OSPF_LSA_H */ diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c new file mode 100644 index 0000000..e4edb2b --- /dev/null +++ b/ospfd/ospf_lsdb.c @@ -0,0 +1,285 @@ +/* + * OSPF LSDB support. + * Copyright (C) 1999, 2000 Alex Zinin, Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" + +struct ospf_lsdb * +ospf_lsdb_new () +{ + struct ospf_lsdb *new; + + new = XCALLOC (MTYPE_OSPF_LSDB, sizeof (struct ospf_lsdb)); + ospf_lsdb_init (new); + + return new; +} + +void +ospf_lsdb_init (struct ospf_lsdb *lsdb) +{ + int i; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + lsdb->type[i].db = route_table_init (); +} + +void +ospf_lsdb_free (struct ospf_lsdb *lsdb) +{ + ospf_lsdb_cleanup (lsdb); + XFREE (MTYPE_OSPF_LSDB, lsdb); +} + +void +ospf_lsdb_cleanup (struct ospf_lsdb *lsdb) +{ + int i; + assert (lsdb); + assert (lsdb->total == 0); + + ospf_lsdb_delete_all (lsdb); + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + route_table_finish (lsdb->type[i].db); +} + +void +lsdb_prefix_set (struct prefix_ls *lp, struct ospf_lsa *lsa) +{ + memset (lp, 0, sizeof (struct prefix_ls)); + lp->family = 0; + lp->prefixlen = 64; + lp->id = lsa->data->id; + lp->adv_router = lsa->data->adv_router; +} + +/* Add new LSA to lsdb. */ +void +ospf_lsdb_add (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) +{ + struct route_table *table; + struct prefix_ls lp; + struct route_node *rn; + + table = lsdb->type[lsa->data->type].db; + lsdb_prefix_set (&lp, lsa); + rn = route_node_get (table, (struct prefix *)&lp); + if (!rn->info) + { + if (IS_LSA_SELF (lsa)) + lsdb->type[lsa->data->type].count_self++; + lsdb->type[lsa->data->type].count++; + lsdb->total++; + } + else + { + if (rn->info == lsa) + return; + + ospf_lsa_unlock (rn->info); + route_unlock_node (rn); + } + +#ifdef MONITOR_LSDB_CHANGE + if (lsdb->new_lsa_hook != NULL) + (* lsdb->new_lsa_hook)(lsa); +#endif /* MONITOR_LSDB_CHANGE */ + rn->info = ospf_lsa_lock (lsa); +} + +void +ospf_lsdb_delete (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) +{ + struct route_table *table; + struct prefix_ls lp; + struct route_node *rn; + + table = lsdb->type[lsa->data->type].db; + lsdb_prefix_set (&lp, lsa); + rn = route_node_lookup (table, (struct prefix *) &lp); + if (rn) + if (rn->info == lsa) + { + if (IS_LSA_SELF (lsa)) + lsdb->type[lsa->data->type].count_self--; + lsdb->type[lsa->data->type].count--; + lsdb->total--; + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); +#ifdef MONITOR_LSDB_CHANGE + if (lsdb->del_lsa_hook != NULL) + (* lsdb->del_lsa_hook)(lsa); +#endif /* MONITOR_LSDB_CHANGE */ + ospf_lsa_unlock (lsa); + return; + } +} + +void +ospf_lsdb_delete_all (struct ospf_lsdb *lsdb) +{ + struct route_table *table; + struct route_node *rn; + struct ospf_lsa *lsa; + int i; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + { + table = lsdb->type[i].db; + for (rn = route_top (table); rn; rn = route_next (rn)) + if ((lsa = (rn->info)) != NULL) + { + if (IS_LSA_SELF (lsa)) + lsdb->type[i].count_self--; + lsdb->type[i].count--; + lsdb->total--; + rn->info = NULL; + route_unlock_node (rn); +#ifdef MONITOR_LSDB_CHANGE + if (lsdb->del_lsa_hook != NULL) + (* lsdb->del_lsa_hook)(lsa); +#endif /* MONITOR_LSDB_CHANGE */ + ospf_lsa_unlock (lsa); + } + } +} + +struct ospf_lsa * +ospf_lsdb_lookup (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) +{ + struct route_table *table; + struct prefix_ls lp; + struct route_node *rn; + struct ospf_lsa *find; + + table = lsdb->type[lsa->data->type].db; + lsdb_prefix_set (&lp, lsa); + rn = route_node_lookup (table, (struct prefix *) &lp); + if (rn) + { + find = rn->info; + route_unlock_node (rn); + return find; + } + return NULL; +} + +struct ospf_lsa * +ospf_lsdb_lookup_by_id (struct ospf_lsdb *lsdb, u_char type, + struct in_addr id, struct in_addr adv_router) +{ + struct route_table *table; + struct prefix_ls lp; + struct route_node *rn; + struct ospf_lsa *find; + + table = lsdb->type[type].db; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = id; + lp.adv_router = adv_router; + + rn = route_node_lookup (table, (struct prefix *) &lp); + if (rn) + { + find = rn->info; + route_unlock_node (rn); + return find; + } + return NULL; +} + +struct ospf_lsa * +ospf_lsdb_lookup_by_id_next (struct ospf_lsdb *lsdb, u_char type, + struct in_addr id, struct in_addr adv_router, + int first) +{ + struct route_table *table; + struct prefix_ls lp; + struct route_node *rn; + struct ospf_lsa *find; + + table = lsdb->type[type].db; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = id; + lp.adv_router = adv_router; + + if (first) + rn = route_top (table); + else + { + rn = route_node_get (table, (struct prefix *) &lp); + rn = route_next (rn); + } + + for (; rn; rn = route_next (rn)) + if (rn->info) + break; + + if (rn && rn->info) + { + find = rn->info; + route_unlock_node (rn); + return find; + } + return NULL; +} + +unsigned long +ospf_lsdb_count_all (struct ospf_lsdb *lsdb) +{ + return lsdb->total; +} + +unsigned long +ospf_lsdb_count (struct ospf_lsdb *lsdb, int type) +{ + return lsdb->type[type].count; +} + +unsigned long +ospf_lsdb_count_self (struct ospf_lsdb *lsdb, int type) +{ + return lsdb->type[type].count_self; +} + +unsigned long +ospf_lsdb_isempty (struct ospf_lsdb *lsdb) +{ + return (lsdb->total == 0); +} diff --git a/ospfd/ospf_lsdb.h b/ospfd/ospf_lsdb.h new file mode 100644 index 0000000..302ddde --- /dev/null +++ b/ospfd/ospf_lsdb.h @@ -0,0 +1,82 @@ +/* + * OSPF LSDB support. + * Copyright (C) 1999, 2000 Alex Zinin, Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_LSDB_H +#define _ZEBRA_OSPF_LSDB_H + +/* OSPF LSDB structure. */ +struct ospf_lsdb +{ + struct + { + unsigned long count; + unsigned long count_self; + struct route_table *db; + } type[OSPF_MAX_LSA]; + unsigned long total; +#define MONITOR_LSDB_CHANGE 1 /* XXX */ +#ifdef MONITOR_LSDB_CHANGE + /* Hooks for callback functions to catch every add/del event. */ + int (* new_lsa_hook)(struct ospf_lsa *); + int (* del_lsa_hook)(struct ospf_lsa *); +#endif /* MONITOR_LSDB_CHANGE */ +}; + +/* Macros. */ +#define LSDB_LOOP(T,N,L) \ + if ((T) != NULL) \ + for ((N) = route_top ((T)); ((N)); ((N)) = route_next ((N))) \ + if (((L) = (N)->info)) + +#define ROUTER_LSDB(A) ((A)->lsdb->type[OSPF_ROUTER_LSA].db) +#define NETWORK_LSDB(A) ((A)->lsdb->type[OSPF_NETWORK_LSA].db) +#define SUMMARY_LSDB(A) ((A)->lsdb->type[OSPF_SUMMARY_LSA].db) +#define ASBR_SUMMARY_LSDB(A) ((A)->lsdb->type[OSPF_ASBR_SUMMARY_LSA].db) +#define EXTERNAL_LSDB(O) ((O)->lsdb->type[OSPF_AS_EXTERNAL_LSA].db) +#define NSSA_LSDB(A) ((A)->lsdb->type[OSPF_AS_NSSA_LSA].db) +#define OPAQUE_LINK_LSDB(A) ((A)->lsdb->type[OSPF_OPAQUE_LINK_LSA].db) +#define OPAQUE_AREA_LSDB(A) ((A)->lsdb->type[OSPF_OPAQUE_AREA_LSA].db) +#define OPAQUE_AS_LSDB(O) ((O)->lsdb->type[OSPF_OPAQUE_AS_LSA].db) + +#define AREA_LSDB(A,T) ((A)->lsdb->type[(T)].db) +#define AS_LSDB(O,T) ((O)->lsdb->type[(T)].db) + +/* OSPF LSDB related functions. */ +struct ospf_lsdb *ospf_lsdb_new (); +void ospf_lsdb_init (struct ospf_lsdb *); +void ospf_lsdb_free (struct ospf_lsdb *); +void ospf_lsdb_cleanup (struct ospf_lsdb *); +void ospf_lsdb_add (struct ospf_lsdb *, struct ospf_lsa *); +void ospf_lsdb_delete (struct ospf_lsdb *, struct ospf_lsa *); +void ospf_lsdb_delete_all (struct ospf_lsdb *); +struct ospf_lsa *ospf_lsdb_lookup (struct ospf_lsdb *, struct ospf_lsa *); +struct ospf_lsa *ospf_lsdb_lookup_by_id (struct ospf_lsdb *, u_char, + struct in_addr, struct in_addr); +struct ospf_lsa *ospf_lsdb_lookup_by_id_next (struct ospf_lsdb *, u_char, + struct in_addr, struct in_addr, + int); +unsigned long ospf_lsdb_count_all (struct ospf_lsdb *); +unsigned long ospf_lsdb_count (struct ospf_lsdb *, int); +unsigned long ospf_lsdb_count_self (struct ospf_lsdb *, int); +unsigned long ospf_lsdb_isempty (struct ospf_lsdb *); + +#endif /* _ZEBRA_OSPF_LSDB_H */ diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c new file mode 100644 index 0000000..e649c17 --- /dev/null +++ b/ospfd/ospf_main.c @@ -0,0 +1,296 @@ +/* + * OSPFd main routine. + * Copyright (C) 1998, 99 Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "version.h" +#include "getopt.h" +#include "thread.h" +#include "prefix.h" +#include "linklist.h" +#include "if.h" +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "filter.h" +#include "plist.h" +#include "stream.h" +#include "log.h" +#include "memory.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_vty.h" + +/* Configuration filename and directory. */ +char config_current[] = OSPF_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR OSPF_DEFAULT_CONFIG; + +/* OSPFd options. */ +struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "log_mode", no_argument, NULL, 'l'}, + { "help", no_argument, NULL, 'h'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "version", no_argument, NULL, 'v'}, + { 0 } +}; + +/* OSPFd program name */ + +/* Master of threads. */ +struct thread_master *master; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_OSPFD_PID; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\ +Daemon which manages OSPF.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + exit (status); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog (NULL, LOG_INFO, "SIGHUP received"); +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + zlog (NULL, LOG_INFO, "Terminating on signal"); + + ospf_terminate (); + + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_rotate (NULL); +} + +/* Signal wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigint); + signal_set (SIGPIPE, SIG_IGN); +#ifdef SIGTSTP + signal_set (SIGTSTP, SIG_IGN); +#endif +#ifdef SIGTTIN + signal_set (SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTTOU + signal_set (SIGTTOU, SIG_IGN); +#endif + signal_set (SIGUSR1, sigusr1); +} + +/* OSPFd main routine. */ +int +main (int argc, char **argv) +{ + char *p; + char *vty_addr = NULL; + int vty_port = 0; + int daemon_mode = 0; + char *config_file = NULL; + char *progname; + struct thread thread; + + /* Set umask before anything for security */ + umask (0027); + + /* get program name */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + /* Invoked by a priviledged user? -- endo. */ + if (getuid () != 0) + { + errno = EPERM; + perror (progname); + exit (1); + } + + zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_OSPF, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + /* OSPF master init. */ + ospf_master_init (); + + while (1) + { + int opt; + + opt = getopt_long (argc, argv, "dlf:hA:P:v", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'd': + daemon_mode = 1; + break; + case 'f': + config_file = optarg; + break; + case 'A': + vty_addr = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'v': + print_version (progname); + exit (0); + break; + case 'h': + usage (progname, 0); + break; + default: + usage (progname, 1); + break; + } + } + + /* Initializations. */ + master = om->master; + + /* Library inits. */ + signal_init (); + cmd_init (1); + debug_init (); + vty_init (); + memory_init (); + + access_list_init (); + prefix_list_init (); + + /* OSPFd inits. */ + ospf_init (); + ospf_if_init (); + ospf_zebra_init (); + + /* OSPF vty inits. */ + ospf_vty_init (); + ospf_vty_show_init (); + + ospf_route_map_init (); +#ifdef HAVE_SNMP + ospf_snmp_init (); +#endif /* HAVE_SNMP */ +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_init (); +#endif /* HAVE_OPAQUE_LSA */ + + sort_node (); + + /* Get configuration file. */ + vty_read_config (config_file, config_current, config_default); + + /* Change to the daemon program. */ + if (daemon_mode) + daemon (0, 0); + + /* Process id file create. */ + pid_output (pid_file); + + /* Create VTY socket */ + vty_serv_sock (vty_addr, + vty_port ? vty_port : OSPF_VTY_PORT, OSPF_VTYSH_PATH); + + /* Print banner. */ + zlog (NULL, LOG_INFO, "OSPFd (%s) starts", ZEBRA_VERSION); + + /* Fetch next active thread. */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Not reached. */ + exit (0); +} + diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c new file mode 100644 index 0000000..ccef055 --- /dev/null +++ b/ospfd/ospf_neighbor.c @@ -0,0 +1,319 @@ +/* + * OSPF Neighbor functions. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "prefix.h" +#include "memory.h" +#include "command.h" +#include "thread.h" +#include "stream.h" +#include "table.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_network.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_dump.h" + +struct ospf_neighbor * +ospf_nbr_new (struct ospf_interface *oi) +{ + struct ospf_neighbor *nbr; + + /* Allcate new neighbor. */ + nbr = XMALLOC (MTYPE_OSPF_NEIGHBOR, sizeof (struct ospf_neighbor)); + memset (nbr, 0, sizeof (struct ospf_neighbor)); + + /* Relate neighbor to the interface. */ + nbr->oi = oi; + + /* Set default values. */ + nbr->state = NSM_Down; + + /* Set inheritance values. */ + nbr->v_inactivity = OSPF_IF_PARAM (oi, v_wait); + nbr->v_db_desc = OSPF_IF_PARAM (oi, retransmit_interval); + nbr->v_ls_req = OSPF_IF_PARAM (oi, retransmit_interval); + nbr->v_ls_upd = OSPF_IF_PARAM (oi, retransmit_interval); + nbr->priority = -1; + + /* DD flags. */ + nbr->dd_flags = OSPF_DD_FLAG_MS|OSPF_DD_FLAG_M|OSPF_DD_FLAG_I; + + /* Last received and sent DD. */ + nbr->last_send = NULL; + + nbr->nbr_nbma = NULL; + + ospf_lsdb_init (&nbr->db_sum); + ospf_lsdb_init (&nbr->ls_rxmt); + ospf_lsdb_init (&nbr->ls_req); + + nbr->crypt_seqnum = 0; + + return nbr; +} + +void +ospf_nbr_free (struct ospf_neighbor *nbr) +{ + /* Free DB summary list. */ + if (ospf_db_summary_count (nbr)) + ospf_db_summary_clear (nbr); + /* ospf_db_summary_delete_all (nbr); */ + + /* Free ls request list. */ + if (ospf_ls_request_count (nbr)) + ospf_ls_request_delete_all (nbr); + + /* Free retransmit list. */ + if (ospf_ls_retransmit_count (nbr)) + ospf_ls_retransmit_clear (nbr); + + /* Cleanup LSDBs. */ + ospf_lsdb_cleanup (&nbr->db_sum); + ospf_lsdb_cleanup (&nbr->ls_req); + ospf_lsdb_cleanup (&nbr->ls_rxmt); + + /* Clear last send packet. */ + if (nbr->last_send) + ospf_packet_free (nbr->last_send); + + if (nbr->nbr_nbma) + { + nbr->nbr_nbma->nbr = NULL; + nbr->nbr_nbma = NULL; + } + + /* Cancel all timers. */ + OSPF_NSM_TIMER_OFF (nbr->t_inactivity); + OSPF_NSM_TIMER_OFF (nbr->t_db_desc); + OSPF_NSM_TIMER_OFF (nbr->t_ls_req); + OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); + + /* Cancel all events. *//* Thread lookup cost would be negligible. */ + thread_cancel_event (master, nbr); + + XFREE (MTYPE_OSPF_NEIGHBOR, nbr); +} + +/* Delete specified OSPF neighbor from interface. */ +void +ospf_nbr_delete (struct ospf_neighbor *nbr) +{ + struct ospf_interface *oi; + struct route_node *rn; + struct prefix p; + + oi = nbr->oi; + + /* Unlink ospf neighbor from the interface. */ + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = nbr->src; + + rn = route_node_lookup (oi->nbrs, &p); + if (rn) + { + if (rn->info) + { + rn->info = NULL; + route_unlock_node (rn); + } + else + zlog_info ("Can't find neighbor %s in the interface %s", + inet_ntoa (nbr->src), IF_NAME (oi)); + + route_unlock_node (rn); + } + + /* Free ospf_neighbor structure. */ + ospf_nbr_free (nbr); +} + +/* Check myself is in the neighbor list. */ +int +ospf_nbr_bidirectional (struct in_addr *router_id, + struct in_addr *neighbors, int size) +{ + int i; + int max; + + max = size / sizeof (struct in_addr); + + for (i = 0; i < max; i ++) + if (IPV4_ADDR_SAME (router_id, &neighbors[i])) + return 1; + + return 0; +} + +/* Add self to nbr list. */ +void +ospf_nbr_add_self (struct ospf_interface *oi) +{ + struct ospf_neighbor *nbr; + struct prefix p; + struct route_node *rn; + + p.family = AF_INET; + p.prefixlen = 32; + p.u.prefix4 = oi->address->u.prefix4; + + rn = route_node_get (oi->nbrs, &p); + if (rn->info) + { + /* There is already pseudo neighbor. */ + nbr = rn->info; + route_unlock_node (rn); + } + else + rn->info = oi->nbr_self; +} + +/* Get neighbor count by status. + Specify status = 0, get all neighbor other than myself. */ +int +ospf_nbr_count (struct ospf_interface *oi, int state) +{ + struct ospf_neighbor *nbr; + struct route_node *rn; + int count = 0; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id)) + if (state == 0 || nbr->state == state) + count++; + + return count; +} + +#ifdef HAVE_OPAQUE_LSA +int +ospf_nbr_count_opaque_capable (struct ospf_interface *oi) +{ + struct ospf_neighbor *nbr; + struct route_node *rn; + int count = 0; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id)) + if (nbr->state == NSM_Full) + if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) + count++; + + return count; +} +#endif /* HAVE_OPAQUE_LSA */ + +struct ospf_neighbor * +ospf_nbr_lookup_by_addr (struct route_table *nbrs, + struct in_addr *addr) +{ + struct prefix p; + struct route_node *rn; + struct ospf_neighbor *nbr; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = *addr; + + rn = route_node_lookup (nbrs, &p); + if (! rn) + return NULL; + + if (rn->info == NULL) + { + route_unlock_node (rn); + return NULL; + } + + nbr = (struct ospf_neighbor *) rn->info; + route_unlock_node (rn); + + return nbr; +} + +struct ospf_neighbor * +ospf_nbr_lookup_by_routerid (struct route_table *nbrs, + struct in_addr *id) +{ + struct route_node *rn; + struct ospf_neighbor *nbr; + + for (rn = route_top (nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + if (IPV4_ADDR_SAME (&nbr->router_id, id)) + { + route_unlock_node(rn); + return nbr; + } + + return NULL; +} + +void +ospf_renegotiate_optional_capabilities (struct ospf *top) +{ + listnode node; + struct ospf_interface *oi; + struct route_table *nbrs; + struct route_node *rn; + struct ospf_neighbor *nbr; + + /* At first, flush self-originated LSAs from routing domain. */ + ospf_flush_self_originated_lsas_now (top); + + /* Revert all neighbor status to ExStart. */ + for (node = listhead (top->oiflist); node; nextnode (node)) + { + if ((oi = getdata (node)) == NULL || (nbrs = oi->nbrs) == NULL) + continue; + + for (rn = route_top (nbrs); rn; rn = route_next (rn)) + { + if ((nbr = rn->info) == NULL || nbr == oi->nbr_self) + continue; + + if (nbr->state < NSM_ExStart) + continue; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Renegotiate optional capabilities with neighbor(%s)", inet_ntoa (nbr->router_id)); + + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + } + } + + return; +} diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h new file mode 100644 index 0000000..485b548 --- /dev/null +++ b/ospfd/ospf_neighbor.h @@ -0,0 +1,106 @@ +/* + * OSPF Neighbor functions. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your + * option) any later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_NEIGHBOR_H +#define _ZEBRA_OSPF_NEIGHBOR_H + +/* Neighbor Data Structure */ +struct ospf_neighbor +{ + /* This neighbor's parent ospf interface. */ + struct ospf_interface *oi; + + /* OSPF neighbor Information */ + u_char state; /* NSM status. */ + u_char dd_flags; /* DD bit flags. */ + u_int32_t dd_seqnum; /* DD Sequence Number. */ + + /* Neighbor Information from Hello. */ + struct prefix address; /* Neighbor Interface Address. */ + + struct in_addr src; /* Src address. */ + struct in_addr router_id; /* Router ID. */ + u_char options; /* Options. */ + int priority; /* Router Priority. */ + struct in_addr d_router; /* Designated Router. */ + struct in_addr bd_router; /* Backup Designated Router. */ + + /* Last sent Database Description packet. */ + struct ospf_packet *last_send; + /* Timestemp when last Database Description packet was sent */ + struct timeval last_send_ts; + + /* Last received Databse Description packet. */ + struct + { + u_char options; + u_char flags; + u_int32_t dd_seqnum; + } last_recv; + + /* LSA data. */ + struct ospf_lsdb ls_rxmt; + struct ospf_lsdb db_sum; + struct ospf_lsdb ls_req; + struct ospf_lsa *ls_req_last; + + u_int32_t crypt_seqnum; /* Cryptographic Sequence Number. */ + + /* Timer values. */ + u_int32_t v_inactivity; + u_int32_t v_db_desc; + u_int32_t v_ls_req; + u_int32_t v_ls_upd; + + /* Threads. */ + struct thread *t_inactivity; + struct thread *t_db_desc; + struct thread *t_ls_req; + struct thread *t_ls_upd; + struct thread *t_hello_reply; + + /* Statistics Field */ + u_int32_t state_change; + struct ospf_nbr_nbma *nbr_nbma; +}; + +/* Macros. */ +#define NBR_IS_DR(n) IPV4_ADDR_SAME (&n->address.u.prefix4, &n->d_router) +#define NBR_IS_BDR(n) IPV4_ADDR_SAME (&n->address.u.prefix4, &n->bd_router) + +/* Prototypes. */ +struct ospf_neighbor *ospf_nbr_new (struct ospf_interface *); +void ospf_nbr_free (struct ospf_neighbor *); +void ospf_nbr_delete (struct ospf_neighbor *); +int ospf_nbr_bidirectional (struct in_addr *, struct in_addr *, int); +void ospf_nbr_add_self (struct ospf_interface *); +int ospf_nbr_count (struct ospf_interface *, int); +#ifdef HAVE_OPAQUE_LSA +int ospf_nbr_count_opaque_capable (struct ospf_interface *); +#endif /* HAVE_OPAQUE_LSA */ +struct ospf_neighbor *ospf_nbr_lookup_by_addr (struct route_table *, + struct in_addr *); +struct ospf_neighbor *ospf_nbr_lookup_by_routerid (struct route_table *, + struct in_addr *); +void ospf_renegotiate_optional_capabilities (struct ospf *top); + +#endif /* _ZEBRA_OSPF_NEIGHBOR_H */ diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c new file mode 100644 index 0000000..56ec864 --- /dev/null +++ b/ospfd/ospf_network.c @@ -0,0 +1,192 @@ +/* + * OSPF network related functions + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "sockunion.h" +#include "log.h" +#include "sockopt.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_network.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_packet.h" + +/* Join to the OSPF ALL SPF ROUTERS multicast group. */ +int +ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p, + unsigned int ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP, + p->u.prefix4, htonl (OSPF_ALLSPFROUTERS), + ifindex); + if (ret < 0) + zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (AllSPFRouters): %s", + strerror (errno)); + else + zlog_info ("interface %s join AllSPFRouters Multicast group.", + inet_ntoa (p->u.prefix4)); + + return ret; +} + +int +ospf_if_drop_allspfrouters (struct ospf *top, struct prefix *p, + unsigned int ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP, + p->u.prefix4, htonl (OSPF_ALLSPFROUTERS), + ifindex); + if (ret < 0) + zlog_warn("can't setsockopt IP_DROP_MEMBERSHIP (AllSPFRouters): %s", + strerror (errno)); + else + zlog_info ("interface %s leave AllSPFRouters Multicast group.", + inet_ntoa (p->u.prefix4)); + + return ret; +} + +/* Join to the OSPF ALL Designated ROUTERS multicast group. */ +int +ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, unsigned int + ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP, + p->u.prefix4, htonl (OSPF_ALLDROUTERS), + ifindex); + if (ret < 0) + zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (AllDRouters): %s", + strerror (errno)); + else + zlog_info ("interface %s join AllDRouters Multicast group.", + inet_ntoa (p->u.prefix4)); + + return ret; +} + +int +ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, unsigned int + ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP, + p->u.prefix4, htonl (OSPF_ALLDROUTERS), + ifindex); + if (ret < 0) + zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (AllDRouters): %s", + strerror (errno)); + else + zlog_info ("interface %s leave AllDRouters Multicast group.", + inet_ntoa (p->u.prefix4)); + + return ret; +} + +int +ospf_if_ipmulticast (struct ospf *top, struct prefix *p, unsigned int ifindex) +{ + u_char val; + int ret, len; + + val = 0; + len = sizeof (val); + + /* Prevent receiving self-origined multicast packets. */ + ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val, len); + if (ret < 0) + zlog_warn ("can't setsockopt IP_MULTICAST_LOOP(0): %s", strerror (errno)); + + /* Explicitly set multicast ttl to 1 -- endo. */ + val = 1; + ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val, len); + if (ret < 0) + zlog_warn ("can't setsockopt IP_MULTICAST_TTL(1): %s", strerror (errno)); + + ret = setsockopt_multicast_ipv4 (top->fd, IP_MULTICAST_IF, + p->u.prefix4, 0, ifindex); + if (ret < 0) + zlog_warn ("can't setsockopt IP_MULTICAST_IF: %s", strerror (errno)); + + return ret; +} + +int +ospf_sock_init (void) +{ + int ospf_sock; + int ret, tos, hincl = 1; + + ospf_sock = socket (AF_INET, SOCK_RAW, IPPROTO_OSPFIGP); + if (ospf_sock < 0) + { + zlog_warn ("ospf_read_sock_init: socket: %s", strerror (errno)); + return -1; + } + + /* Set precedence field. */ +#ifdef IPTOS_PREC_INTERNETCONTROL + tos = IPTOS_PREC_INTERNETCONTROL; + ret = setsockopt (ospf_sock, IPPROTO_IP, IP_TOS, + (char *) &tos, sizeof (int)); + if (ret < 0) + { + zlog_warn ("can't set sockopt IP_TOS %d to socket %d", tos, ospf_sock); + close (ospf_sock); /* Prevent sd leak. */ + return ret; + } +#endif /* IPTOS_PREC_INTERNETCONTROL */ + + /* we will include IP header with packet */ + ret = setsockopt (ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof (hincl)); + if (ret < 0) + zlog_warn ("Can't set IP_HDRINCL option"); + +#if defined (IP_PKTINFO) + ret = setsockopt (ospf_sock, IPPROTO_IP, IP_PKTINFO, &hincl, sizeof (hincl)); + if (ret < 0) + zlog_warn ("Can't set IP_PKTINFO option"); +#elif defined (IP_RECVIF) + ret = setsockopt (ospf_sock, IPPROTO_IP, IP_RECVIF, &hincl, sizeof (hincl)); + if (ret < 0) + zlog_warn ("Can't set IP_RECVIF option"); +#else +#warning "cannot be able to receive link information on this OS" +#endif + + return ospf_sock; +} diff --git a/ospfd/ospf_network.h b/ospfd/ospf_network.h new file mode 100644 index 0000000..52a25fd --- /dev/null +++ b/ospfd/ospf_network.h @@ -0,0 +1,34 @@ +/* + * OSPF network related functions. + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_NETWORK_H +#define _ZEBRA_OSPF_NETWORK_H + +/* Prototypes. */ +int ospf_if_add_allspfrouters (struct ospf *, struct prefix *, unsigned int); +int ospf_if_drop_allspfrouters (struct ospf *, struct prefix *, unsigned int); +int ospf_if_add_alldrouters (struct ospf *, struct prefix *, unsigned int); +int ospf_if_drop_alldrouters (struct ospf *, struct prefix *, unsigned int); +int ospf_if_ipmulticast (struct ospf *, struct prefix *, unsigned int); +int ospf_sock_init (void); + +#endif /* _ZEBRA_OSPF_NETWORK_H */ diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c new file mode 100644 index 0000000..a8efdcc --- /dev/null +++ b/ospfd/ospf_nsm.c @@ -0,0 +1,877 @@ +/* + * OSPF version 2 Neighbor State Machine + * From RFC2328 [OSPF Version 2] + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "memory.h" +#include "hash.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "stream.h" +#include "table.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_network.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_abr.h" + +void nsm_reset_nbr (struct ospf_neighbor *); + + +/* OSPF NSM Timer functions. */ +int +ospf_inactivity_timer (struct thread *thread) +{ + struct ospf_neighbor *nbr; + + nbr = THREAD_ARG (thread); + nbr->t_inactivity = NULL; + + if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) + zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (Inactivity timer expire)", + IF_NAME (nbr->oi), inet_ntoa (nbr->router_id)); + + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_InactivityTimer); + + return 0; +} + +int +ospf_db_desc_timer (struct thread *thread) +{ + struct ospf_interface *oi; + struct ospf_neighbor *nbr; + + nbr = THREAD_ARG (thread); + nbr->t_db_desc = NULL; + + oi = nbr->oi; + + if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) + zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (DD Retransmit timer expire)", + IF_NAME (nbr->oi), inet_ntoa (nbr->src)); + + /* resent last send DD packet. */ + assert (nbr->last_send); + ospf_db_desc_resend (nbr); + + /* DD Retransmit timer set. */ + OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc); + + return 0; +} + +/* Hook function called after ospf NSM event is occured. */ + +void +nsm_timer_set (struct ospf_neighbor *nbr) +{ + switch (nbr->state) + { + case NSM_Down: + OSPF_NSM_TIMER_OFF (nbr->t_db_desc); + OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); + break; + case NSM_Attempt: + OSPF_NSM_TIMER_OFF (nbr->t_db_desc); + OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); + break; + case NSM_Init: + OSPF_NSM_TIMER_OFF (nbr->t_db_desc); + OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); + break; + case NSM_TwoWay: + OSPF_NSM_TIMER_OFF (nbr->t_db_desc); + OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); + break; + case NSM_ExStart: + OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc); + OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); + break; + case NSM_Exchange: + OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd); + if (!IS_SET_DD_MS (nbr->dd_flags)) + OSPF_NSM_TIMER_OFF (nbr->t_db_desc); + break; + case NSM_Loading: + OSPF_NSM_TIMER_OFF (nbr->t_db_desc); + break; + case NSM_Full: + OSPF_NSM_TIMER_OFF (nbr->t_db_desc); + break; + default: + OSPF_NSM_TIMER_OFF (nbr->t_db_desc); + break; + } +} + + +/* OSPF NSM functions. */ +int +nsm_ignore (struct ospf_neighbor *nbr) +{ + if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) + zlog (NULL, LOG_INFO, "NSM[%s:%s]: nsm_ignore called", + IF_NAME (nbr->oi), inet_ntoa (nbr->router_id)); + + return 0; +} + +int +nsm_hello_received (struct ospf_neighbor *nbr) +{ + /* Start or Restart Inactivity Timer. */ + OSPF_NSM_TIMER_OFF (nbr->t_inactivity); + + OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer, + nbr->v_inactivity); + + if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma) + OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll); + + return 0; +} + +int +nsm_start (struct ospf_neighbor *nbr) +{ + + nsm_reset_nbr (nbr); + + if (nbr->nbr_nbma) + OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll); + + OSPF_NSM_TIMER_OFF (nbr->t_inactivity); + + OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer, + nbr->v_inactivity); + + return 0; +} + +int +nsm_twoway_received (struct ospf_neighbor *nbr) +{ + struct ospf_interface *oi; + int next_state = NSM_TwoWay; + + oi = nbr->oi; + + /* These netowork types must be adjacency. */ + if (oi->type == OSPF_IFTYPE_POINTOPOINT || + oi->type == OSPF_IFTYPE_POINTOMULTIPOINT || + oi->type == OSPF_IFTYPE_VIRTUALLINK) + next_state = NSM_ExStart; + + /* Router itself is the DRouter or the BDRouter. */ + if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) || + IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi))) + next_state = NSM_ExStart; + + /* Neighboring Router is the DRouter or the BDRouter. */ + if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->d_router) || + IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->bd_router)) + next_state = NSM_ExStart; + + return next_state; +} + +int +ospf_db_summary_count (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_count_all (&nbr->db_sum); +} + +int +ospf_db_summary_isempty (struct ospf_neighbor *nbr) +{ + return ospf_lsdb_isempty (&nbr->db_sum); +} + +int +ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ +#ifdef HAVE_OPAQUE_LSA + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */ + if (lsa->oi != nbr->oi) + return 0; + break; + case OSPF_OPAQUE_AREA_LSA: + /* + * It is assured by the caller function "nsm_negotiation_done()" + * that every given LSA belongs to the same area with "nbr". + */ + break; + case OSPF_OPAQUE_AS_LSA: + default: + break; + } +#endif /* HAVE_OPAQUE_LSA */ + +#ifdef HAVE_NSSA + /* Stay away from any Local Translated Type-7 LSAs */ + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) + return 0; +#endif /* HAVE_NSSA */ + + if (IS_LSA_MAXAGE (lsa)) + ospf_ls_retransmit_add (nbr, lsa); + else + ospf_lsdb_add (&nbr->db_sum, lsa); + + return 0; +} + +void +ospf_db_summary_clear (struct ospf_neighbor *nbr) +{ + struct ospf_lsdb *lsdb; + int i; + + lsdb = &nbr->db_sum; + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + { + struct route_table *table = lsdb->type[i].db; + struct route_node *rn; + + for (rn = route_top (table); rn; rn = route_next (rn)) + if (rn->info) + ospf_lsdb_delete (&nbr->db_sum, rn->info); + } +} + + + +/* The area link state database consists of the router-LSAs, + network-LSAs and summary-LSAs contained in the area structure, + along with the AS-external-LSAs contained in the global structure. + AS-external-LSAs are omitted from a virtual neighbor's Database + summary list. AS-external-LSAs are omitted from the Database + summary list if the area has been configured as a stub. */ +int +nsm_negotiation_done (struct ospf_neighbor *nbr) +{ + struct ospf_area *area = nbr->oi->area; + struct ospf_lsa *lsa; + struct route_node *rn; + + LSDB_LOOP (ROUTER_LSDB (area), rn, lsa) + ospf_db_summary_add (nbr, lsa); + LSDB_LOOP (NETWORK_LSDB (area), rn, lsa) + ospf_db_summary_add (nbr, lsa); + LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) + ospf_db_summary_add (nbr, lsa); + LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) + ospf_db_summary_add (nbr, lsa); + +#ifdef HAVE_OPAQUE_LSA + /* Process only if the neighbor is opaque capable. */ + if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) + { + LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) + ospf_db_summary_add (nbr, lsa); + LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) + ospf_db_summary_add (nbr, lsa); + } +#endif /* HAVE_OPAQUE_LSA */ + + if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK + && area->external_routing == OSPF_AREA_DEFAULT) + LSDB_LOOP (EXTERNAL_LSDB (nbr->oi->ospf), rn, lsa) + ospf_db_summary_add (nbr, lsa); + +#ifdef HAVE_OPAQUE_LSA + if (CHECK_FLAG (nbr->options, OSPF_OPTION_O) + && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK + && area->external_routing == OSPF_AREA_DEFAULT)) + LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa) + ospf_db_summary_add (nbr, lsa); +#endif /* HAVE_OPAQUE_LSA */ + + return 0; +} + +int +nsm_exchange_done (struct ospf_neighbor *nbr) +{ + if (ospf_ls_request_isempty (nbr)) + return NSM_Full; + + /* Cancel dd retransmit timer. */ + /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */ + + /* Send Link State Request. */ + ospf_ls_req_send (nbr); + + return NSM_Loading; +} + +int +nsm_bad_ls_req (struct ospf_neighbor *nbr) +{ + /* Clear neighbor. */ + nsm_reset_nbr (nbr); + + return 0; +} + +int +nsm_adj_ok (struct ospf_neighbor *nbr) +{ + struct ospf_interface *oi; + int next_state; + int flag = 0; + + oi = nbr->oi; + next_state = nbr->state; + + /* These netowork types must be adjacency. */ + if (oi->type == OSPF_IFTYPE_POINTOPOINT + || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT + || oi->type == OSPF_IFTYPE_VIRTUALLINK) + flag = 1; + + /* Router itself is the DRouter or the BDRouter. */ + if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) + || IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi))) + flag = 1; + + if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi)) + || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi))) + flag = 1; + + if (nbr->state == NSM_TwoWay && flag == 1) + next_state = NSM_ExStart; + else if (nbr->state >= NSM_ExStart && flag == 0) + next_state = NSM_TwoWay; + + return next_state; +} + +int +nsm_seq_number_mismatch (struct ospf_neighbor *nbr) +{ + /* Clear neighbor. */ + nsm_reset_nbr (nbr); + + return 0; +} + +int +nsm_oneway_received (struct ospf_neighbor *nbr) +{ + /* Clear neighbor. */ + nsm_reset_nbr (nbr); + + return 0; +} + +void +nsm_reset_nbr (struct ospf_neighbor *nbr) +{ + /* Clear Database Summary list. */ + if (!ospf_db_summary_isempty (nbr)) + ospf_db_summary_clear (nbr); + + /* Clear Link State Request list. */ + if (!ospf_ls_request_isempty (nbr)) + ospf_ls_request_delete_all (nbr); + + /* Clear Link State Retransmission list. */ + if (!ospf_ls_retransmit_isempty (nbr)) + ospf_ls_retransmit_clear (nbr); + + /* Cancel thread. */ + OSPF_NSM_TIMER_OFF (nbr->t_db_desc); + OSPF_NSM_TIMER_OFF (nbr->t_ls_req); + OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); + OSPF_NSM_TIMER_OFF (nbr->t_hello_reply); + +#ifdef HAVE_OPAQUE_LSA + if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) + UNSET_FLAG (nbr->options, OSPF_OPTION_O); +#endif /* HAVE_OPAQUE_LSA */ +} + +int +nsm_kill_nbr (struct ospf_neighbor *nbr) +{ + /* call it here because we cannot call it from ospf_nsm_event */ + nsm_change_state (nbr, NSM_Down); + + /* Reset neighbor. */ + nsm_reset_nbr (nbr); + + if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL) + { + struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma; + + nbr_nbma->nbr = NULL; + nbr_nbma->state_change = nbr->state_change; + + nbr->nbr_nbma = NULL; + + OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer, + nbr_nbma->v_poll); + + if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) + zlog_info ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)", + IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4)); + } + + /* Delete neighbor from interface. */ + ospf_nbr_delete (nbr); + + return 0; +} + +int +nsm_inactivity_timer (struct ospf_neighbor *nbr) +{ + /* Kill neighbor. */ + nsm_kill_nbr (nbr); + + return 0; +} + +int +nsm_ll_down (struct ospf_neighbor *nbr) +{ + /* Reset neighbor. */ + /*nsm_reset_nbr (nbr);*/ + + /* Kill neighbor. */ + nsm_kill_nbr (nbr); + + return 0; +} + +/* Neighbor State Machine */ +struct { + int (*func) (); + int next_state; +} NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] = +{ + { + /* DependUpon: dummy state. */ + { nsm_ignore, NSM_DependUpon }, /* NoEvent */ + { nsm_ignore, NSM_DependUpon }, /* HelloReceived */ + { nsm_ignore, NSM_DependUpon }, /* Start */ + { nsm_ignore, NSM_DependUpon }, /* 2-WayReceived */ + { nsm_ignore, NSM_DependUpon }, /* NegotiationDone */ + { nsm_ignore, NSM_DependUpon }, /* ExchangeDone */ + { nsm_ignore, NSM_DependUpon }, /* BadLSReq */ + { nsm_ignore, NSM_DependUpon }, /* LoadingDone */ + { nsm_ignore, NSM_DependUpon }, /* AdjOK? */ + { nsm_ignore, NSM_DependUpon }, /* SeqNumberMismatch */ + { nsm_ignore, NSM_DependUpon }, /* 1-WayReceived */ + { nsm_ignore, NSM_DependUpon }, /* KillNbr */ + { nsm_ignore, NSM_DependUpon }, /* InactivityTimer */ + { nsm_ignore, NSM_DependUpon }, /* LLDown */ + }, + { + /* Down: */ + { nsm_ignore, NSM_DependUpon }, /* NoEvent */ + { nsm_hello_received, NSM_Init }, /* HelloReceived */ + { nsm_start, NSM_Attempt }, /* Start */ + { nsm_ignore, NSM_Down }, /* 2-WayReceived */ + { nsm_ignore, NSM_Down }, /* NegotiationDone */ + { nsm_ignore, NSM_Down }, /* ExchangeDone */ + { nsm_ignore, NSM_Down }, /* BadLSReq */ + { nsm_ignore, NSM_Down }, /* LoadingDone */ + { nsm_ignore, NSM_Down }, /* AdjOK? */ + { nsm_ignore, NSM_Down }, /* SeqNumberMismatch */ + { nsm_ignore, NSM_Down }, /* 1-WayReceived */ + { nsm_kill_nbr, NSM_Down }, /* KillNbr */ + { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ + { nsm_ll_down, NSM_Down }, /* LLDown */ + }, + { + /* Attempt: */ + { nsm_ignore, NSM_DependUpon }, /* NoEvent */ + { nsm_hello_received, NSM_Init }, /* HelloReceived */ + { nsm_ignore, NSM_Attempt }, /* Start */ + { nsm_ignore, NSM_Attempt }, /* 2-WayReceived */ + { nsm_ignore, NSM_Attempt }, /* NegotiationDone */ + { nsm_ignore, NSM_Attempt }, /* ExchangeDone */ + { nsm_ignore, NSM_Attempt }, /* BadLSReq */ + { nsm_ignore, NSM_Attempt }, /* LoadingDone */ + { nsm_ignore, NSM_Attempt }, /* AdjOK? */ + { nsm_ignore, NSM_Attempt }, /* SeqNumberMismatch */ + { nsm_ignore, NSM_Attempt }, /* 1-WayReceived */ + { nsm_kill_nbr, NSM_Down }, /* KillNbr */ + { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ + { nsm_ll_down, NSM_Down }, /* LLDown */ + }, + { + /* Init: */ + { nsm_ignore, NSM_DependUpon }, /* NoEvent */ + { nsm_hello_received, NSM_Init }, /* HelloReceived */ + { nsm_ignore, NSM_Init }, /* Start */ + { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */ + { nsm_ignore, NSM_Init }, /* NegotiationDone */ + { nsm_ignore, NSM_Init }, /* ExchangeDone */ + { nsm_ignore, NSM_Init }, /* BadLSReq */ + { nsm_ignore, NSM_Init }, /* LoadingDone */ + { nsm_ignore, NSM_Init }, /* AdjOK? */ + { nsm_ignore, NSM_Init }, /* SeqNumberMismatch */ + { nsm_ignore, NSM_Init }, /* 1-WayReceived */ + { nsm_kill_nbr, NSM_Down }, /* KillNbr */ + { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ + { nsm_ll_down, NSM_Down }, /* LLDown */ + }, + { + /* 2-Way: */ + { nsm_ignore, NSM_DependUpon }, /* NoEvent */ + { nsm_hello_received, NSM_TwoWay }, /* HelloReceived */ + { nsm_ignore, NSM_TwoWay }, /* Start */ + { nsm_ignore, NSM_TwoWay }, /* 2-WayReceived */ + { nsm_ignore, NSM_TwoWay }, /* NegotiationDone */ + { nsm_ignore, NSM_TwoWay }, /* ExchangeDone */ + { nsm_ignore, NSM_TwoWay }, /* BadLSReq */ + { nsm_ignore, NSM_TwoWay }, /* LoadingDone */ + { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ + { nsm_ignore, NSM_TwoWay }, /* SeqNumberMismatch */ + { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */ + { nsm_kill_nbr, NSM_Down }, /* KillNbr */ + { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ + { nsm_ll_down, NSM_Down }, /* LLDown */ + }, + { + /* ExStart: */ + { nsm_ignore, NSM_DependUpon }, /* NoEvent */ + { nsm_hello_received, NSM_ExStart }, /* HelloReceived */ + { nsm_ignore, NSM_ExStart }, /* Start */ + { nsm_ignore, NSM_ExStart }, /* 2-WayReceived */ + { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */ + { nsm_ignore, NSM_ExStart }, /* ExchangeDone */ + { nsm_ignore, NSM_ExStart }, /* BadLSReq */ + { nsm_ignore, NSM_ExStart }, /* LoadingDone */ + { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ + { nsm_ignore, NSM_ExStart }, /* SeqNumberMismatch */ + { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */ + { nsm_kill_nbr, NSM_Down }, /* KillNbr */ + { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ + { nsm_ll_down, NSM_Down }, /* LLDown */ + }, + { + /* Exchange: */ + { nsm_ignore, NSM_DependUpon }, /* NoEvent */ + { nsm_hello_received, NSM_Exchange }, /* HelloReceived */ + { nsm_ignore, NSM_Exchange }, /* Start */ + { nsm_ignore, NSM_Exchange }, /* 2-WayReceived */ + { nsm_ignore, NSM_Exchange }, /* NegotiationDone */ + { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */ + { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */ + { nsm_ignore, NSM_Exchange }, /* LoadingDone */ + { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ + { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */ + { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */ + { nsm_kill_nbr, NSM_Down }, /* KillNbr */ + { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ + { nsm_ll_down, NSM_Down }, /* LLDown */ + }, + { + /* Loading: */ + { nsm_ignore, NSM_DependUpon }, /* NoEvent */ + { nsm_hello_received, NSM_Loading }, /* HelloReceived */ + { nsm_ignore, NSM_Loading }, /* Start */ + { nsm_ignore, NSM_Loading }, /* 2-WayReceived */ + { nsm_ignore, NSM_Loading }, /* NegotiationDone */ + { nsm_ignore, NSM_Loading }, /* ExchangeDone */ + { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */ + { nsm_ignore, NSM_Full }, /* LoadingDone */ + { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ + { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */ + { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */ + { nsm_kill_nbr, NSM_Down }, /* KillNbr */ + { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ + { nsm_ll_down, NSM_Down }, /* LLDown */ + }, + { /* Full: */ + { nsm_ignore, NSM_DependUpon }, /* NoEvent */ + { nsm_hello_received, NSM_Full }, /* HelloReceived */ + { nsm_ignore, NSM_Full }, /* Start */ + { nsm_ignore, NSM_Full }, /* 2-WayReceived */ + { nsm_ignore, NSM_Full }, /* NegotiationDone */ + { nsm_ignore, NSM_Full }, /* ExchangeDone */ + { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */ + { nsm_ignore, NSM_Full }, /* LoadingDone */ + { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ + { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */ + { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */ + { nsm_kill_nbr, NSM_Down }, /* KillNbr */ + { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */ + { nsm_ll_down, NSM_Down }, /* LLDown */ + }, +}; + +static char *ospf_nsm_event_str[] = +{ + "NoEvent", + "HelloReceived", + "Start", + "2-WayReceived", + "NegotiationDone", + "ExchangeDone", + "BadLSReq", + "LoadingDone", + "AdjOK?", + "SeqNumberMismatch", + "1-WayReceived", + "KillNbr", + "InactivityTimer", + "LLDown", +}; + +void +nsm_change_state (struct ospf_neighbor *nbr, int state) +{ + struct ospf_interface *oi = nbr->oi; + struct ospf_area *vl_area = NULL; + u_char old_state; + int x; + int force = 1; + + /* Logging change of status. */ + if (IS_DEBUG_OSPF (nsm, NSM_STATUS)) + zlog_info ("NSM[%s:%s]: State change %s -> %s", + IF_NAME (nbr->oi), inet_ntoa (nbr->router_id), + LOOKUP (ospf_nsm_state_msg, nbr->state), + LOOKUP (ospf_nsm_state_msg, state)); + + /* Preserve old status. */ + old_state = nbr->state; + + /* Change to new status. */ + nbr->state = state; + + /* Statistics. */ + nbr->state_change++; + + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id); + + /* One of the neighboring routers changes to/from the FULL state. */ + if ((old_state != NSM_Full && state == NSM_Full) || + (old_state == NSM_Full && state != NSM_Full)) + { + if (state == NSM_Full) + { + oi->full_nbrs++; + oi->area->full_nbrs++; + + ospf_check_abr_status (oi->ospf); + + if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area) + if (++vl_area->full_vls == 1) + ospf_schedule_abr_task (oi->ospf); + + /* kevinm: refresh any redistributions */ + for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++) + { + if (x == ZEBRA_ROUTE_OSPF || x == ZEBRA_ROUTE_OSPF6) + continue; + ospf_external_lsa_refresh_type (oi->ospf, x, force); + } + } + else + { + oi->full_nbrs--; + oi->area->full_nbrs--; + + ospf_check_abr_status (oi->ospf); + + if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area) + if (vl_area->full_vls > 0) + if (--vl_area->full_vls == 0) + ospf_schedule_abr_task (oi->ospf); + + /* clear neighbor retransmit list */ + if (!ospf_ls_retransmit_isempty (nbr)) + ospf_ls_retransmit_clear (nbr); + } + + zlog_info ("nsm_change_state(): " + "scheduling new router-LSA origination"); + + ospf_router_lsa_timer_add (oi->area); + + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + { + struct ospf_area *vl_area = + ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id); + + if (vl_area) + ospf_router_lsa_timer_add (vl_area); + } + + /* Originate network-LSA. */ + if (oi->state == ISM_DR) + { + if (oi->network_lsa_self && oi->full_nbrs == 0) + { + ospf_lsa_flush_area (oi->network_lsa_self, oi->area); + ospf_lsa_unlock (oi->network_lsa_self); + oi->network_lsa_self = NULL; + OSPF_TIMER_OFF (oi->t_network_lsa_self); + } + else + ospf_network_lsa_timer_add (oi); + } + } + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_nsm_change (nbr, old_state); +#endif /* HAVE_OPAQUE_LSA */ + + /* Start DD exchange protocol */ + if (state == NSM_ExStart) + { + if (nbr->dd_seqnum == 0) + nbr->dd_seqnum = time (NULL); + else + nbr->dd_seqnum++; + + nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS; + ospf_db_desc_send (nbr); + } + + /* clear cryptographic sequence number */ + if (state == NSM_Down) + nbr->crypt_seqnum = 0; + + /* Generete NeighborChange ISM event. */ +#ifdef BUGGY_ISM_TRANSITION + if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) || + (old_state >= NSM_TwoWay && state < NSM_TwoWay)) + OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange); +#else /* BUGGY_ISM_TRANSITION */ + switch (oi->state) { + case ISM_DROther: + case ISM_Backup: + case ISM_DR: + if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) || + (old_state >= NSM_TwoWay && state < NSM_TwoWay)) + OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange); + break; + default: + /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */ + break; + } +#endif /* BUGGY_ISM_TRANSITION */ + + /* Performance hack. Send hello immideately when some neighbor enter + Init state. This whay we decrease neighbor discovery time. Gleb.*/ + if (state == NSM_Init) + { + OSPF_ISM_TIMER_OFF (oi->t_hello); + OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, 1); + } + + /* Preserve old status? */ +} + +/* Execute NSM event process. */ +int +ospf_nsm_event (struct thread *thread) +{ + int event; + int next_state; + struct ospf_neighbor *nbr; + struct in_addr router_id; + int old_state; + struct ospf_interface *oi; + + nbr = THREAD_ARG (thread); + event = THREAD_VAL (thread); + router_id = nbr->router_id; + + old_state = nbr->state; + oi = nbr->oi ; + + /* Call function. */ + next_state = (*(NSM [nbr->state][event].func))(nbr); + + /* When event is NSM_KillNbr or InactivityTimer, the neighbor is + deleted. */ + if (event == NSM_KillNbr || event == NSM_InactivityTimer) + { + if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) + zlog_info ("NSM[%s:%s]: neighbor deleted", + IF_NAME (oi), inet_ntoa (router_id)); + + /* Timers are canceled in ospf_nbr_free, moreover we cannot call + nsm_timer_set here because nbr is freed already!!!*/ + /*nsm_timer_set (nbr);*/ + + return 0; + } + + if (! next_state) + next_state = NSM [nbr->state][event].next_state; + + if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) + zlog_info ("NSM[%s:%s]: %s (%s)", IF_NAME (oi), + inet_ntoa (nbr->router_id), + LOOKUP (ospf_nsm_state_msg, nbr->state), + ospf_nsm_event_str [event]); + + /* If state is changed. */ + if (next_state != nbr->state) + nsm_change_state (nbr, next_state); + + /* Make sure timer is set. */ + nsm_timer_set (nbr); + + return 0; +} + +/* Check loading state. */ +void +ospf_check_nbr_loading (struct ospf_neighbor *nbr) +{ + if (nbr->state == NSM_Loading) + { + if (ospf_ls_request_isempty (nbr)) + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone); + else if (nbr->ls_req_last == NULL) + ospf_ls_req_event (nbr); + } +} diff --git a/ospfd/ospf_nsm.h b/ospfd/ospf_nsm.h new file mode 100644 index 0000000..6c3dc4d --- /dev/null +++ b/ospfd/ospf_nsm.h @@ -0,0 +1,90 @@ +/* + * OSPF version 2 Neighbor State Machine + * From RFC2328 [OSPF Version 2] + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_NSM_H +#define _ZEBRA_OSPF_NSM_H + +/* OSPF Neighbor State Machine State. */ +#define NSM_DependUpon 0 +#define NSM_Down 1 +#define NSM_Attempt 2 +#define NSM_Init 3 +#define NSM_TwoWay 4 +#define NSM_ExStart 5 +#define NSM_Exchange 6 +#define NSM_Loading 7 +#define NSM_Full 8 +#define OSPF_NSM_STATE_MAX 9 + +/* OSPF Neighbor State Machine Event. */ +#define NSM_NoEvent 0 +#define NSM_HelloReceived 1 +#define NSM_Start 2 +#define NSM_TwoWayReceived 3 +#define NSM_NegotiationDone 4 +#define NSM_ExchangeDone 5 +#define NSM_BadLSReq 6 +#define NSM_LoadingDone 7 +#define NSM_AdjOK 8 +#define NSM_SeqNumberMismatch 9 +#define NSM_OneWayReceived 10 +#define NSM_KillNbr 11 +#define NSM_InactivityTimer 12 +#define NSM_LLDown 13 +#define OSPF_NSM_EVENT_MAX 14 + +/* Macro for OSPF NSM timer turn on. */ +#define OSPF_NSM_TIMER_ON(T,F,V) \ + do { \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), nbr, (V)); \ + } while (0) + +/* Macro for OSPF NSM timer turn off. */ +#define OSPF_NSM_TIMER_OFF(X) \ + do { \ + if (X) \ + { \ + thread_cancel (X); \ + (X) = NULL; \ + } \ + } while (0) + +/* Macro for OSPF NSM schedule event. */ +#define OSPF_NSM_EVENT_SCHEDULE(N,E) \ + thread_add_event (master, ospf_nsm_event, (N), (E)) + +/* Macro for OSPF NSM execute event. */ +#define OSPF_NSM_EVENT_EXECUTE(N,E) \ + thread_execute (master, ospf_nsm_event, (N), (E)) + +/* Prototypes. */ +int ospf_nsm_event (struct thread *); +void nsm_change_state (struct ospf_neighbor *, int); +void ospf_check_nbr_loading (struct ospf_neighbor *); +int ospf_db_summary_isempty (struct ospf_neighbor *); +int ospf_db_summary_count (struct ospf_neighbor *); +void ospf_db_summary_clear (struct ospf_neighbor *); + +#endif /* _ZEBRA_OSPF_NSM_H */ + diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c new file mode 100644 index 0000000..a05160a --- /dev/null +++ b/ospfd/ospf_opaque.c @@ -0,0 +1,2487 @@ +/* + * This is an implementation of rfc2370. + * Copyright (C) 2001 KDD R&D Laboratories, Inc. + * http://www.kddlabs.co.jp/ + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/***** MTYPE definitions are not reflected to "memory.h" yet. *****/ +#define MTYPE_OSPF_OPAQUE_FUNCTAB 0 +#define MTYPE_OPAQUE_INFO_PER_TYPE 0 +#define MTYPE_OPAQUE_INFO_PER_ID 0 + +#include +#ifdef HAVE_OPAQUE_LSA + +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "memory.h" +#include "command.h" +#include "vty.h" +#include "stream.h" +#include "log.h" +#include "thread.h" +#include "hash.h" +#include "sockunion.h" /* for inet_aton() */ + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" + +/*------------------------------------------------------------------------* + * Followings are initialize/terminate functions for Opaque-LSAs handling. + *------------------------------------------------------------------------*/ + +#ifdef HAVE_OSPF_TE +#include "ospfd/ospf_te.h" +#endif /* HAVE_OSPF_TE */ + +static void ospf_opaque_register_vty (void); +static void ospf_opaque_funclist_init (void); +static void ospf_opaque_funclist_term (void); +static void free_opaque_info_per_type (void *val); +static void free_opaque_info_per_id (void *val); +static int ospf_opaque_lsa_install_hook (struct ospf_lsa *lsa); +static int ospf_opaque_lsa_delete_hook (struct ospf_lsa *lsa); + +void +ospf_opaque_init (void) +{ + ospf_opaque_register_vty (); + ospf_opaque_funclist_init (); + +#ifdef HAVE_OSPF_TE + if (ospf_mpls_te_init () != 0) + exit (1); +#endif /* HAVE_OSPF_TE */ + + return; +} + +void +ospf_opaque_term (void) +{ +#ifdef HAVE_OSPF_TE + ospf_mpls_te_term (); +#endif /* HAVE_OSPF_TE */ + + ospf_opaque_funclist_term (); + return; +} + +int +ospf_opaque_type9_lsa_init (struct ospf_interface *oi) +{ + if (oi->opaque_lsa_self != NULL) + list_delete (oi->opaque_lsa_self); + + oi->opaque_lsa_self = list_new (); + oi->opaque_lsa_self->del = free_opaque_info_per_type; + oi->t_opaque_lsa_self = NULL; + return 0; +} + +void +ospf_opaque_type9_lsa_term (struct ospf_interface *oi) +{ + OSPF_TIMER_OFF (oi->t_opaque_lsa_self); + if (oi->opaque_lsa_self != NULL) + list_delete (oi->opaque_lsa_self); + oi->opaque_lsa_self = NULL; + return; +} + +int +ospf_opaque_type10_lsa_init (struct ospf_area *area) +{ + if (area->opaque_lsa_self != NULL) + list_delete (area->opaque_lsa_self); + + area->opaque_lsa_self = list_new (); + area->opaque_lsa_self->del = free_opaque_info_per_type; + area->t_opaque_lsa_self = NULL; + +#ifdef MONITOR_LSDB_CHANGE + area->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook; + area->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook; +#endif /* MONITOR_LSDB_CHANGE */ + return 0; +} + +void +ospf_opaque_type10_lsa_term (struct ospf_area *area) +{ +#ifdef MONITOR_LSDB_CHANGE + area->lsdb->new_lsa_hook = + area->lsdb->del_lsa_hook = NULL; +#endif /* MONITOR_LSDB_CHANGE */ + + OSPF_TIMER_OFF (area->t_opaque_lsa_self); + if (area->opaque_lsa_self != NULL) + list_delete (area->opaque_lsa_self); + area->opaque_lsa_self = NULL; + return; +} + +int +ospf_opaque_type11_lsa_init (struct ospf *top) +{ + if (top->opaque_lsa_self != NULL) + list_delete (top->opaque_lsa_self); + + top->opaque_lsa_self = list_new (); + top->opaque_lsa_self->del = free_opaque_info_per_type; + top->t_opaque_lsa_self = NULL; + +#ifdef MONITOR_LSDB_CHANGE + top->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook; + top->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook; +#endif /* MONITOR_LSDB_CHANGE */ + return 0; +} + +void +ospf_opaque_type11_lsa_term (struct ospf *top) +{ +#ifdef MONITOR_LSDB_CHANGE + top->lsdb->new_lsa_hook = + top->lsdb->del_lsa_hook = NULL; +#endif /* MONITOR_LSDB_CHANGE */ + + OSPF_TIMER_OFF (top->t_opaque_lsa_self); + if (top->opaque_lsa_self != NULL) + list_delete (top->opaque_lsa_self); + top->opaque_lsa_self = NULL; + return; +} + +static const char * +ospf_opaque_type_name (u_char opaque_type) +{ + const char *name = "Unknown"; + + switch (opaque_type) + { + case OPAQUE_TYPE_WILDCARD: /* This is a special assignment! */ + name = "Wildcard"; + break; + case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA: + name = "Traffic Engineering LSA"; + break; + case OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC: + name = "Sycamore optical topology description"; + break; + case OPAQUE_TYPE_GRACE_LSA: + name = "Grace-LSA"; + break; + default: + if (OPAQUE_TYPE_RANGE_UNASSIGNED (opaque_type)) + name = "Unassigned"; + else if (OPAQUE_TYPE_RANGE_RESERVED (opaque_type)) + name = "Private/Experimental"; + break; + } + return name; +} + +/*------------------------------------------------------------------------* + * Followings are management functions to store user specified callbacks. + *------------------------------------------------------------------------*/ + +struct opaque_info_per_type; /* Forward declaration. */ + +struct ospf_opaque_functab +{ + u_char opaque_type; + struct opaque_info_per_type *oipt; + + int (* new_if_hook)(struct interface *ifp); + int (* del_if_hook)(struct interface *ifp); + void (* ism_change_hook)(struct ospf_interface *oi, int old_status); + void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status); + void (* config_write_router)(struct vty *vty); + void (* config_write_if )(struct vty *vty, struct interface *ifp); + void (* config_write_debug )(struct vty *vty); + void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa); + int (* lsa_originator)(void *arg); + void (* lsa_refresher )(struct ospf_lsa *lsa); + int (* new_lsa_hook)(struct ospf_lsa *lsa); + int (* del_lsa_hook)(struct ospf_lsa *lsa); +}; + +static list ospf_opaque_wildcard_funclist; /* Handle LSA-9/10/11 altogether. */ +static list ospf_opaque_type9_funclist; +static list ospf_opaque_type10_funclist; +static list ospf_opaque_type11_funclist; + +static void +ospf_opaque_del_functab (void *val) +{ + XFREE (MTYPE_OSPF_OPAQUE_FUNCTAB, val); + return; +} + +static void +ospf_opaque_funclist_init (void) +{ + list funclist; + + funclist = ospf_opaque_wildcard_funclist = list_new (); + funclist->del = ospf_opaque_del_functab; + + funclist = ospf_opaque_type9_funclist = list_new (); + funclist->del = ospf_opaque_del_functab; + + funclist = ospf_opaque_type10_funclist = list_new (); + funclist->del = ospf_opaque_del_functab; + + funclist = ospf_opaque_type11_funclist = list_new (); + funclist->del = ospf_opaque_del_functab; + return; +} + +static void +ospf_opaque_funclist_term (void) +{ + list funclist; + + funclist = ospf_opaque_wildcard_funclist; + list_delete (funclist); + + funclist = ospf_opaque_type9_funclist; + list_delete (funclist); + + funclist = ospf_opaque_type10_funclist; + list_delete (funclist); + + funclist = ospf_opaque_type11_funclist; + list_delete (funclist); + return; +} + +static list +ospf_get_opaque_funclist (u_char lsa_type) +{ + list funclist = NULL; + + switch (lsa_type) + { + case OPAQUE_TYPE_WILDCARD: + /* XXX + * This is an ugly trick to handle type-9/10/11 LSA altogether. + * Yes, "OPAQUE_TYPE_WILDCARD (value 0)" is not an LSA-type, nor + * an officially assigned opaque-type. + * Though it is possible that the value might be officially used + * in the future, we use it internally as a special label, for now. + */ + funclist = ospf_opaque_wildcard_funclist; + break; + case OSPF_OPAQUE_LINK_LSA: + funclist = ospf_opaque_type9_funclist; + break; + case OSPF_OPAQUE_AREA_LSA: + funclist = ospf_opaque_type10_funclist; + break; + case OSPF_OPAQUE_AS_LSA: + funclist = ospf_opaque_type11_funclist; + break; + default: + zlog_warn ("ospf_get_opaque_funclist: Unexpected LSA-type(%u)", lsa_type); + break; + } + return funclist; +} + +int +ospf_register_opaque_functab ( + u_char lsa_type, + u_char opaque_type, + int (* new_if_hook)(struct interface *ifp), + int (* del_if_hook)(struct interface *ifp), + void (* ism_change_hook)(struct ospf_interface *oi, int old_status), + void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status), + void (* config_write_router)(struct vty *vty), + void (* config_write_if )(struct vty *vty, struct interface *ifp), + void (* config_write_debug )(struct vty *vty), + void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa), + int (* lsa_originator)(void *arg), + void (* lsa_refresher )(struct ospf_lsa *lsa), + int (* new_lsa_hook)(struct ospf_lsa *lsa), + int (* del_lsa_hook)(struct ospf_lsa *lsa)) +{ + list funclist; + struct ospf_opaque_functab *new; + int rc = -1; + + if ((funclist = ospf_get_opaque_funclist (lsa_type)) == NULL) + { + zlog_warn ("ospf_register_opaque_functab: Cannot get funclist for Type-%u LSAs?", lsa_type); + goto out; + } + else + { + listnode node; + struct ospf_opaque_functab *functab; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->opaque_type == opaque_type) + { + zlog_warn ("ospf_register_opaque_functab: Duplicated entry?: lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type); + goto out; + } + } + + if ((new = XCALLOC (MTYPE_OSPF_OPAQUE_FUNCTAB, + sizeof (struct ospf_opaque_functab))) == NULL) + { + zlog_warn ("ospf_register_opaque_functab: XMALLOC: %s", strerror (errno)); + goto out; + } + + new->opaque_type = opaque_type; + new->oipt = NULL; + new->new_if_hook = new_if_hook; + new->del_if_hook = del_if_hook; + new->ism_change_hook = ism_change_hook; + new->nsm_change_hook = nsm_change_hook; + new->config_write_router = config_write_router; + new->config_write_if = config_write_if; + new->config_write_debug = config_write_debug; + new->show_opaque_info = show_opaque_info; + new->lsa_originator = lsa_originator; + new->lsa_refresher = lsa_refresher; + new->new_lsa_hook = new_lsa_hook; + new->del_lsa_hook = del_lsa_hook; + + listnode_add (funclist, new); + rc = 0; + +out: + return rc; +} + +void +ospf_delete_opaque_functab (u_char lsa_type, u_char opaque_type) +{ + list funclist; + listnode node; + struct ospf_opaque_functab *functab; + + if ((funclist = ospf_get_opaque_funclist (lsa_type)) != NULL) + for (node = listhead (funclist); node; nextnode (node)) + { + if ((functab = getdata (node)) != NULL + && functab->opaque_type == opaque_type) + { + /* Cleanup internal control information, if it still remains. */ + if (functab->oipt != NULL) + free_opaque_info_per_type (functab->oipt); + + /* Dequeue listnode entry from the list. */ + listnode_delete (funclist, functab); + + /* Avoid misjudgement in the next lookup. */ + if (listcount (funclist) == 0) + funclist->head = funclist->tail = NULL; + + XFREE (MTYPE_OSPF_OPAQUE_FUNCTAB, functab); + goto out; + } + } +out: + return; +} + +static struct ospf_opaque_functab * +ospf_opaque_functab_lookup (struct ospf_lsa *lsa) +{ + list funclist; + listnode node; + struct ospf_opaque_functab *functab; + u_char key = GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)); + + if ((funclist = ospf_get_opaque_funclist (lsa->data->type)) != NULL) + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->opaque_type == key) + return functab; + + return NULL; +} + +/*------------------------------------------------------------------------* + * Followings are management functions for self-originated LSA entries. + *------------------------------------------------------------------------*/ + +/* + * Opaque-LSA control information per opaque-type. + * Single Opaque-Type may have multiple instances; each of them will be + * identified by their opaque-id. + */ +struct opaque_info_per_type +{ + u_char lsa_type; + u_char opaque_type; + + enum { PROC_NORMAL, PROC_SUSPEND } status; + + /* + * Thread for (re-)origination scheduling for this opaque-type. + * + * Initial origination of Opaque-LSAs is controlled by generic + * Opaque-LSA handling module so that same opaque-type entries are + * called all at once when certain conditions are met. + * However, there might be cases that some Opaque-LSA clients need + * to (re-)originate their own Opaque-LSAs out-of-sync with others. + * This thread is prepared for that specific purpose. + */ + struct thread *t_opaque_lsa_self; + + /* + * Backpointer to an "owner" which is LSA-type dependent. + * type-9: struct ospf_interface + * type-10: struct ospf_area + * type-11: struct ospf + */ + void *owner; + + /* Collection of callback functions for this opaque-type. */ + struct ospf_opaque_functab *functab; + + /* List of Opaque-LSA control informations per opaque-id. */ + list id_list; +}; + +/* Opaque-LSA control information per opaque-id. */ +struct opaque_info_per_id +{ + u_int32_t opaque_id; + + /* Thread for refresh/flush scheduling for this opaque-type/id. */ + struct thread *t_opaque_lsa_self; + + /* Backpointer to Opaque-LSA control information per opaque-type. */ + struct opaque_info_per_type *opqctl_type; + + /* Here comes an actual Opaque-LSA entry for this opaque-type/id. */ + struct ospf_lsa *lsa; +}; + +static struct opaque_info_per_type *register_opaque_info_per_type (struct ospf_opaque_functab *functab, struct ospf_lsa *new); +static struct opaque_info_per_type *lookup_opaque_info_by_type (struct ospf_lsa *lsa); +static struct opaque_info_per_id *register_opaque_info_per_id (struct opaque_info_per_type *oipt, struct ospf_lsa *new); +static struct opaque_info_per_id *lookup_opaque_info_by_id (struct opaque_info_per_type *oipt, struct ospf_lsa *lsa); +static struct opaque_info_per_id *register_opaque_lsa (struct ospf_lsa *new); + + +static struct opaque_info_per_type * +register_opaque_info_per_type (struct ospf_opaque_functab *functab, + struct ospf_lsa *new) +{ + struct ospf *top; + struct opaque_info_per_type *oipt; + + if ((oipt = XCALLOC (MTYPE_OPAQUE_INFO_PER_TYPE, + sizeof (struct opaque_info_per_type))) == NULL) + { + zlog_warn ("register_opaque_info_per_type: XMALLOC: %s", strerror (errno)); + goto out; + } + + switch (new->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + oipt->owner = new->oi; + listnode_add (new->oi->opaque_lsa_self, oipt); + break; + case OSPF_OPAQUE_AREA_LSA: + oipt->owner = new->area; + listnode_add (new->area->opaque_lsa_self, oipt); + break; + case OSPF_OPAQUE_AS_LSA: + top = ospf_lookup (); + if (new->area != NULL && (top = new->area->ospf) == NULL) + { + free_opaque_info_per_type ((void *) oipt); + oipt = NULL; + goto out; /* This case may not exist. */ + } + oipt->owner = top; + listnode_add (top->opaque_lsa_self, oipt); + break; + default: + zlog_warn ("register_opaque_info_per_type: Unexpected LSA-type(%u)", new->data->type); + free_opaque_info_per_type ((void *) oipt); + oipt = NULL; + goto out; /* This case may not exist. */ + } + + oipt->lsa_type = new->data->type; + oipt->opaque_type = GET_OPAQUE_TYPE (ntohl (new->data->id.s_addr)); + oipt->status = PROC_NORMAL; + oipt->t_opaque_lsa_self = NULL; + oipt->functab = functab; + functab->oipt = oipt; + oipt->id_list = list_new (); + oipt->id_list->del = free_opaque_info_per_id; + +out: + return oipt; +} + +static void +free_opaque_info_per_type (void *val) +{ + struct opaque_info_per_type *oipt = (struct opaque_info_per_type *) val; + struct opaque_info_per_id *oipi; + struct ospf_lsa *lsa; + listnode node; + + /* Control information per opaque-id may still exist. */ + for (node = listhead (oipt->id_list); node; nextnode (node)) + { + if ((oipi = getdata (node)) == NULL) + continue; + if ((lsa = oipi->lsa) == NULL) + continue; + if (IS_LSA_MAXAGE (lsa)) + continue; + ospf_opaque_lsa_flush_schedule (lsa); + } + + /* Remove "oipt" from its owner's self-originated LSA list. */ + switch (oipt->lsa_type) + { + case OSPF_OPAQUE_LINK_LSA: + { + struct ospf_interface *oi = (struct ospf_interface *)(oipt->owner); + listnode_delete (oi->opaque_lsa_self, oipt); + break; + } + case OSPF_OPAQUE_AREA_LSA: + { + struct ospf_area *area = (struct ospf_area *)(oipt->owner); + listnode_delete (area->opaque_lsa_self, oipt); + break; + } + case OSPF_OPAQUE_AS_LSA: + { + struct ospf *top = (struct ospf *)(oipt->owner); + listnode_delete (top->opaque_lsa_self, oipt); + break; + } + default: + zlog_warn ("free_opaque_info_per_type: Unexpected LSA-type(%u)", oipt->lsa_type); + break; /* This case may not exist. */ + } + + OSPF_TIMER_OFF (oipt->t_opaque_lsa_self); + list_delete (oipt->id_list); + XFREE (MTYPE_OPAQUE_INFO_PER_TYPE, oipt); + return; +} + +static struct opaque_info_per_type * +lookup_opaque_info_by_type (struct ospf_lsa *lsa) +{ + struct ospf *top; + struct ospf_area *area; + struct ospf_interface *oi; + list listtop = NULL; + listnode node; + struct opaque_info_per_type *oipt = NULL; + u_char key = GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)); + + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + if ((oi = lsa->oi) != NULL) + listtop = oi->opaque_lsa_self; + else + zlog_warn ("Type-9 Opaque-LSA: Reference to OI is missing?"); + break; + case OSPF_OPAQUE_AREA_LSA: + if ((area = lsa->area) != NULL) + listtop = area->opaque_lsa_self; + else + zlog_warn ("Type-10 Opaque-LSA: Reference to AREA is missing?"); + break; + case OSPF_OPAQUE_AS_LSA: + top = ospf_lookup (); + if ((area = lsa->area) != NULL && (top = area->ospf) == NULL) + { + zlog_warn ("Type-11 Opaque-LSA: Reference to OSPF is missing?"); + break; /* Unlikely to happen. */ + } + listtop = top->opaque_lsa_self; + break; + default: + zlog_warn ("lookup_opaque_info_by_type: Unexpected LSA-type(%u)", lsa->data->type); + break; + } + + if (listtop != NULL) + for (node = listhead (listtop); node; nextnode (node)) + if ((oipt = getdata (node)) != NULL) + if (oipt->opaque_type == key) + return oipt; + + return NULL; +} + +static struct opaque_info_per_id * +register_opaque_info_per_id (struct opaque_info_per_type *oipt, + struct ospf_lsa *new) +{ + struct opaque_info_per_id *oipi; + + if ((oipi = XCALLOC (MTYPE_OPAQUE_INFO_PER_ID, + sizeof (struct opaque_info_per_id))) == NULL) + { + zlog_warn ("register_opaque_info_per_id: XMALLOC: %s", strerror (errno)); + goto out; + } + oipi->opaque_id = GET_OPAQUE_ID (ntohl (new->data->id.s_addr)); + oipi->t_opaque_lsa_self = NULL; + oipi->opqctl_type = oipt; + oipi->lsa = ospf_lsa_lock (new); + + listnode_add (oipt->id_list, oipi); + +out: + return oipi; +} + +static void +free_opaque_info_per_id (void *val) +{ + struct opaque_info_per_id *oipi = (struct opaque_info_per_id *) val; + + OSPF_TIMER_OFF (oipi->t_opaque_lsa_self); + if (oipi->lsa != NULL) + ospf_lsa_unlock (oipi->lsa); + XFREE (MTYPE_OPAQUE_INFO_PER_ID, oipi); + return; +} + +static struct opaque_info_per_id * +lookup_opaque_info_by_id (struct opaque_info_per_type *oipt, + struct ospf_lsa *lsa) +{ + listnode node; + struct opaque_info_per_id *oipi; + u_int32_t key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)); + + for (node = listhead (oipt->id_list); node; nextnode (node)) + if ((oipi = getdata (node)) != NULL) + if (oipi->opaque_id == key) + return oipi; + + return NULL; +} + +static struct opaque_info_per_id * +register_opaque_lsa (struct ospf_lsa *new) +{ + struct ospf_opaque_functab *functab; + struct opaque_info_per_type *oipt; + struct opaque_info_per_id *oipi = NULL; + + if ((functab = ospf_opaque_functab_lookup (new)) == NULL) + goto out; + + if ((oipt = lookup_opaque_info_by_type (new)) == NULL + && (oipt = register_opaque_info_per_type (functab, new)) == NULL) + goto out; + + if ((oipi = register_opaque_info_per_id (oipt, new)) == NULL) + goto out; + +out: + return oipi; +} + +/*------------------------------------------------------------------------* + * Followings are (vty) configuration functions for Opaque-LSAs handling. + *------------------------------------------------------------------------*/ + +DEFUN (capability_opaque, + capability_opaque_cmd, + "capability opaque", + "Enable specific OSPF feature\n" + "Opaque LSA\n") +{ + struct ospf *ospf = (struct ospf *) vty->index; + + /* Turn on the "master switch" of opaque-lsa capability. */ + if (!CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Opaque capability: OFF -> ON"); + + SET_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE); + ospf_renegotiate_optional_capabilities (ospf); + } + return CMD_SUCCESS; +} + +ALIAS (capability_opaque, + ospf_opaque_capable_cmd, + "ospf opaque-lsa", + "OSPF specific commands\n" + "Enable the Opaque-LSA capability (rfc2370)\n"); + +DEFUN (no_capability_opaque, + no_capability_opaque_cmd, + "no capability opaque", + NO_STR + "Enable specific OSPF feature\n" + "Opaque LSA\n") +{ + struct ospf *ospf = (struct ospf *) vty->index; + + /* Turn off the "master switch" of opaque-lsa capability. */ + if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Opaque capability: ON -> OFF"); + + UNSET_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE); + ospf_renegotiate_optional_capabilities (ospf); + } + return CMD_SUCCESS; +} + +ALIAS (no_capability_opaque, + no_ospf_opaque_capable_cmd, + "no ospf opaque-lsa", + NO_STR + "OSPF specific commands\n" + "Disable the Opaque-LSA capability (rfc2370)\n"); + +static void +ospf_opaque_register_vty (void) +{ + install_element (OSPF_NODE, &capability_opaque_cmd); + install_element (OSPF_NODE, &no_capability_opaque_cmd); + install_element (OSPF_NODE, &ospf_opaque_capable_cmd); + install_element (OSPF_NODE, &no_ospf_opaque_capable_cmd); + return; +} + +/*------------------------------------------------------------------------* + * Followings are collection of user-registered function callers. + *------------------------------------------------------------------------*/ + +static int +opaque_lsa_new_if_callback (list funclist, struct interface *ifp) +{ + listnode node; + struct ospf_opaque_functab *functab; + int rc = -1; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->new_if_hook != NULL) + if ((* functab->new_if_hook)(ifp) != 0) + goto out; + rc = 0; +out: + return rc; +} + +static int +opaque_lsa_del_if_callback (list funclist, struct interface *ifp) +{ + listnode node; + struct ospf_opaque_functab *functab; + int rc = -1; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->del_if_hook != NULL) + if ((* functab->del_if_hook)(ifp) != 0) + goto out; + rc = 0; +out: + return rc; +} + +static void +opaque_lsa_ism_change_callback (list funclist, + struct ospf_interface *oi, int old_status) +{ + listnode node; + struct ospf_opaque_functab *functab; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->ism_change_hook != NULL) + (* functab->ism_change_hook)(oi, old_status); + return; +} + +static void +opaque_lsa_nsm_change_callback (list funclist, + struct ospf_neighbor *nbr, int old_status) +{ + listnode node; + struct ospf_opaque_functab *functab; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->nsm_change_hook != NULL) + (* functab->nsm_change_hook)(nbr, old_status); + return; +} + +static void +opaque_lsa_config_write_router_callback (list funclist, struct vty *vty) +{ + listnode node; + struct ospf_opaque_functab *functab; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->config_write_router != NULL) + (* functab->config_write_router)(vty); + return; +} + +static void +opaque_lsa_config_write_if_callback (list funclist, + struct vty *vty, struct interface *ifp) +{ + listnode node; + struct ospf_opaque_functab *functab; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->config_write_if != NULL) + (* functab->config_write_if)(vty, ifp); + return; +} + +static void +opaque_lsa_config_write_debug_callback (list funclist, struct vty *vty) +{ + listnode node; + struct ospf_opaque_functab *functab; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->config_write_debug != NULL) + (* functab->config_write_debug)(vty); + return; +} + +static int +opaque_lsa_originate_callback (list funclist, void *lsa_type_dependent) +{ + listnode node; + struct ospf_opaque_functab *functab; + int rc = -1; + + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->lsa_originator != NULL) + if ((* functab->lsa_originator)(lsa_type_dependent) != 0) + goto out; + rc = 0; +out: + return rc; +} + +static int +new_lsa_callback (list funclist, struct ospf_lsa *lsa) +{ + listnode node; + struct ospf_opaque_functab *functab; + int rc = -1; + + /* This function handles ALL types of LSAs, not only opaque ones. */ + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->new_lsa_hook != NULL) + if ((* functab->new_lsa_hook)(lsa) != 0) + goto out; + rc = 0; +out: + return rc; +} + +static int +del_lsa_callback (list funclist, struct ospf_lsa *lsa) +{ + listnode node; + struct ospf_opaque_functab *functab; + int rc = -1; + + /* This function handles ALL types of LSAs, not only opaque ones. */ + for (node = listhead (funclist); node; nextnode (node)) + if ((functab = getdata (node)) != NULL) + if (functab->del_lsa_hook != NULL) + if ((* functab->del_lsa_hook)(lsa) != 0) + goto out; + rc = 0; +out: + return rc; +} + +/*------------------------------------------------------------------------* + * Followings are glue functions to call Opaque-LSA specific processing. + *------------------------------------------------------------------------*/ + +int +ospf_opaque_new_if (struct interface *ifp) +{ + list funclist; + int rc = -1; + + funclist = ospf_opaque_wildcard_funclist; + if (opaque_lsa_new_if_callback (funclist, ifp) != 0) + goto out; + + funclist = ospf_opaque_type9_funclist; + if (opaque_lsa_new_if_callback (funclist, ifp) != 0) + goto out; + + funclist = ospf_opaque_type10_funclist; + if (opaque_lsa_new_if_callback (funclist, ifp) != 0) + goto out; + + funclist = ospf_opaque_type11_funclist; + if (opaque_lsa_new_if_callback (funclist, ifp) != 0) + goto out; + + rc = 0; +out: + return rc; +} + +int +ospf_opaque_del_if (struct interface *ifp) +{ + list funclist; + int rc = -1; + + funclist = ospf_opaque_wildcard_funclist; + if (opaque_lsa_del_if_callback (funclist, ifp) != 0) + goto out; + + funclist = ospf_opaque_type9_funclist; + if (opaque_lsa_del_if_callback (funclist, ifp) != 0) + goto out; + + funclist = ospf_opaque_type10_funclist; + if (opaque_lsa_del_if_callback (funclist, ifp) != 0) + goto out; + + funclist = ospf_opaque_type11_funclist; + if (opaque_lsa_del_if_callback (funclist, ifp) != 0) + goto out; + + rc = 0; +out: + return rc; +} + +void +ospf_opaque_ism_change (struct ospf_interface *oi, int old_status) +{ + list funclist; + + funclist = ospf_opaque_wildcard_funclist; + opaque_lsa_ism_change_callback (funclist, oi, old_status); + + funclist = ospf_opaque_type9_funclist; + opaque_lsa_ism_change_callback (funclist, oi, old_status); + + funclist = ospf_opaque_type10_funclist; + opaque_lsa_ism_change_callback (funclist, oi, old_status); + + funclist = ospf_opaque_type11_funclist; + opaque_lsa_ism_change_callback (funclist, oi, old_status); + + return; +} + +void +ospf_opaque_nsm_change (struct ospf_neighbor *nbr, int old_state) +{ + struct ospf *top; + list funclist; + + if ((top = oi_to_top (nbr->oi)) == NULL) + goto out; + + if (old_state != NSM_Full && nbr->state == NSM_Full) + { + if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) + { + if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Opaque-LSA: Now get operational!"); + + SET_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT); + } + + ospf_opaque_lsa_originate_schedule (nbr->oi, NULL); + } + } + else + if (old_state == NSM_Full && nbr->state != NSM_Full) + { +#ifdef NOTYET + /* + * If no more opaque-capable full-state neighbor remains in the + * flooding scope which corresponds to Opaque-LSA type, periodic + * LS flooding should be stopped. + */ +#endif /* NOTYET */ + ; + } + + funclist = ospf_opaque_wildcard_funclist; + opaque_lsa_nsm_change_callback (funclist, nbr, old_state); + + funclist = ospf_opaque_type9_funclist; + opaque_lsa_nsm_change_callback (funclist, nbr, old_state); + + funclist = ospf_opaque_type10_funclist; + opaque_lsa_nsm_change_callback (funclist, nbr, old_state); + + funclist = ospf_opaque_type11_funclist; + opaque_lsa_nsm_change_callback (funclist, nbr, old_state); + +out: + return; +} + +void +ospf_opaque_config_write_router (struct vty *vty, struct ospf *ospf) +{ + list funclist; + + if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE)) + vty_out (vty, " capability opaque%s", VTY_NEWLINE); + + funclist = ospf_opaque_wildcard_funclist; + opaque_lsa_config_write_router_callback (funclist, vty); + + funclist = ospf_opaque_type9_funclist; + opaque_lsa_config_write_router_callback (funclist, vty); + + funclist = ospf_opaque_type10_funclist; + opaque_lsa_config_write_router_callback (funclist, vty); + + funclist = ospf_opaque_type11_funclist; + opaque_lsa_config_write_router_callback (funclist, vty); + + return; +} + +void +ospf_opaque_config_write_if (struct vty *vty, struct interface *ifp) +{ + list funclist; + + funclist = ospf_opaque_wildcard_funclist; + opaque_lsa_config_write_if_callback (funclist, vty, ifp); + + funclist = ospf_opaque_type9_funclist; + opaque_lsa_config_write_if_callback (funclist, vty, ifp); + + funclist = ospf_opaque_type10_funclist; + opaque_lsa_config_write_if_callback (funclist, vty, ifp); + + funclist = ospf_opaque_type11_funclist; + opaque_lsa_config_write_if_callback (funclist, vty, ifp); + + return; +} + +void +ospf_opaque_config_write_debug (struct vty *vty) +{ + list funclist; + + funclist = ospf_opaque_wildcard_funclist; + opaque_lsa_config_write_debug_callback (funclist, vty); + + funclist = ospf_opaque_type9_funclist; + opaque_lsa_config_write_debug_callback (funclist, vty); + + funclist = ospf_opaque_type10_funclist; + opaque_lsa_config_write_debug_callback (funclist, vty); + + funclist = ospf_opaque_type11_funclist; + opaque_lsa_config_write_debug_callback (funclist, vty); + + return; +} + +void +show_opaque_info_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + struct lsa_header *lsah = (struct lsa_header *) lsa->data; + u_int32_t lsid = ntohl (lsah->id.s_addr); + u_char opaque_type = GET_OPAQUE_TYPE (lsid); + u_int32_t opaque_id = GET_OPAQUE_ID (lsid); + struct ospf_opaque_functab *functab; + + /* Switch output functionality by vty address. */ + if (vty != NULL) + { + vty_out (vty, " Opaque-Type %u (%s)%s", opaque_type, + ospf_opaque_type_name (opaque_type), VTY_NEWLINE); + vty_out (vty, " Opaque-ID 0x%x%s", opaque_id, VTY_NEWLINE); + + vty_out (vty, " Opaque-Info: %u octets of data%s%s", + ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE, + VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)", + VTY_NEWLINE); + } + else + { + zlog_info (" Opaque-Type %u (%s)", opaque_type, + ospf_opaque_type_name (opaque_type)); + zlog_info (" Opaque-ID 0x%x", opaque_id); + + zlog_info (" Opaque-Info: %u octets of data%s", + ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE, + VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)"); + } + + /* Call individual output functions. */ + if ((functab = ospf_opaque_functab_lookup (lsa)) != NULL) + if (functab->show_opaque_info != NULL) + (* functab->show_opaque_info)(vty, lsa); + + return; +} + +void +ospf_opaque_lsa_dump (struct stream *s, u_int16_t length) +{ + struct ospf_lsa lsa; + + lsa.data = (struct lsa_header *) STREAM_PNT (s); + show_opaque_info_detail (NULL, &lsa); + return; +} + +static int +ospf_opaque_lsa_install_hook (struct ospf_lsa *lsa) +{ + list funclist; + int rc = -1; + + /* + * Some Opaque-LSA user may want to monitor every LSA installation + * into the LSDB, regardless with target LSA type. + */ + funclist = ospf_opaque_wildcard_funclist; + if (new_lsa_callback (funclist, lsa) != 0) + goto out; + + funclist = ospf_opaque_type9_funclist; + if (new_lsa_callback (funclist, lsa) != 0) + goto out; + + funclist = ospf_opaque_type10_funclist; + if (new_lsa_callback (funclist, lsa) != 0) + goto out; + + funclist = ospf_opaque_type11_funclist; + if (new_lsa_callback (funclist, lsa) != 0) + goto out; + + rc = 0; +out: + return rc; +} + +static int +ospf_opaque_lsa_delete_hook (struct ospf_lsa *lsa) +{ + list funclist; + int rc = -1; + + /* + * Some Opaque-LSA user may want to monitor every LSA deletion + * from the LSDB, regardless with target LSA type. + */ + funclist = ospf_opaque_wildcard_funclist; + if (del_lsa_callback (funclist, lsa) != 0) + goto out; + + funclist = ospf_opaque_type9_funclist; + if (del_lsa_callback (funclist, lsa) != 0) + goto out; + + funclist = ospf_opaque_type10_funclist; + if (del_lsa_callback (funclist, lsa) != 0) + goto out; + + funclist = ospf_opaque_type11_funclist; + if (del_lsa_callback (funclist, lsa) != 0) + goto out; + + rc = 0; +out: + return rc; +} + +/*------------------------------------------------------------------------* + * Followings are Opaque-LSA origination/refresh management functions. + *------------------------------------------------------------------------*/ + +static int ospf_opaque_type9_lsa_originate (struct thread *t); +static int ospf_opaque_type10_lsa_originate (struct thread *t); +static int ospf_opaque_type11_lsa_originate (struct thread *t); +static void ospf_opaque_lsa_reoriginate_resume (list listtop, void *arg); + +void +ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *delay0) +{ + struct ospf *top; + struct ospf_area *area; + listnode node; + struct opaque_info_per_type *oipt; + int delay = 0; + + if ((top = oi_to_top (oi)) == NULL || (area = oi->area) == NULL) + { + zlog_warn ("ospf_opaque_lsa_originate_schedule: Invalid argument?"); + goto out; + } + + /* It may not a right time to schedule origination now. */ + if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_opaque_lsa_originate_schedule: Not operational."); + goto out; /* This is not an error. */ + } + if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_opaque_lsa_originate_schedule: Under blockade."); + goto out; /* This is not an error, too. */ + } + + if (delay0 != NULL) + delay = *delay0; + + /* + * There might be some entries that have been waiting for triggering + * of per opaque-type re-origination get resumed. + */ + ospf_opaque_lsa_reoriginate_resume ( oi->opaque_lsa_self, (void *) oi); + ospf_opaque_lsa_reoriginate_resume (area->opaque_lsa_self, (void *) area); + ospf_opaque_lsa_reoriginate_resume ( top->opaque_lsa_self, (void *) top); + + /* + * Now, schedule origination of all Opaque-LSAs per opaque-type. + */ + if (! list_isempty (ospf_opaque_type9_funclist) + && list_isempty (oi->opaque_lsa_self) + && oi->t_opaque_lsa_self == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Schedule Type-9 Opaque-LSA origination in %d sec later.", delay); + oi->t_opaque_lsa_self = + thread_add_timer (master, ospf_opaque_type9_lsa_originate, oi, delay); + delay += OSPF_MIN_LS_INTERVAL; + } + + if (! list_isempty (ospf_opaque_type10_funclist) + && list_isempty (area->opaque_lsa_self) + && area->t_opaque_lsa_self == NULL) + { + /* + * One AREA may contain multiple OIs, but above 2nd and 3rd + * conditions prevent from scheduling the originate function + * again and again. + */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Schedule Type-10 Opaque-LSA origination in %d sec later.", delay); + area->t_opaque_lsa_self = + thread_add_timer (master, ospf_opaque_type10_lsa_originate, + area, delay); + delay += OSPF_MIN_LS_INTERVAL; + } + + if (! list_isempty (ospf_opaque_type11_funclist) + && list_isempty (top->opaque_lsa_self) + && top->t_opaque_lsa_self == NULL) + { + /* + * One OSPF may contain multiple AREAs, but above 2nd and 3rd + * conditions prevent from scheduling the originate function + * again and again. + */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Schedule Type-11 Opaque-LSA origination in %d sec later.", delay); + top->t_opaque_lsa_self = + thread_add_timer (master, ospf_opaque_type11_lsa_originate, + top, delay); + delay += OSPF_MIN_LS_INTERVAL; + } + + /* + * Following section treats a special situation that this node's + * opaque capability has changed as "ON -> OFF -> ON". + */ + if (! list_isempty (ospf_opaque_type9_funclist) + && ! list_isempty (oi->opaque_lsa_self)) + { + for (node = listhead (oi->opaque_lsa_self); node; nextnode (node)) + { + if ((oipt = getdata (node)) == NULL /* Something wrong? */ + || oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ + || oipt->status == PROC_SUSPEND /* Cannot originate now. */ + || ! list_isempty (oipt->id_list)) /* Handler is already active. */ + continue; + + ospf_opaque_lsa_reoriginate_schedule ((void *) oi, + OSPF_OPAQUE_LINK_LSA, oipt->opaque_type); + } + } + + if (! list_isempty (ospf_opaque_type10_funclist) + && ! list_isempty (area->opaque_lsa_self)) + { + for (node = listhead (area->opaque_lsa_self); node; nextnode (node)) + { + if ((oipt = getdata (node)) == NULL /* Something wrong? */ + || oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ + || oipt->status == PROC_SUSPEND /* Cannot originate now. */ + || ! list_isempty (oipt->id_list)) /* Handler is already active. */ + continue; + + ospf_opaque_lsa_reoriginate_schedule ((void *) area, + OSPF_OPAQUE_AREA_LSA, oipt->opaque_type); + } + } + + if (! list_isempty (ospf_opaque_type11_funclist) + && ! list_isempty (top->opaque_lsa_self)) + { + for (node = listhead (top->opaque_lsa_self); node; nextnode (node)) + { + if ((oipt = getdata (node)) == NULL /* Something wrong? */ + || oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ + || oipt->status == PROC_SUSPEND /* Cannot originate now. */ + || ! list_isempty (oipt->id_list)) /* Handler is already active. */ + continue; + + ospf_opaque_lsa_reoriginate_schedule ((void *) top, + OSPF_OPAQUE_AS_LSA, oipt->opaque_type); + } + } + + if (delay0 != NULL) + *delay0 = delay; + +out: + return; +} + +static int +ospf_opaque_type9_lsa_originate (struct thread *t) +{ + struct ospf_interface *oi; + int rc; + + oi = THREAD_ARG (t); + oi->t_opaque_lsa_self = NULL; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Type9-LSA]: Originate Opaque-LSAs for OI %s", + IF_NAME (oi)); + + rc = opaque_lsa_originate_callback (ospf_opaque_type9_funclist, oi); + + return rc; +} + +static int +ospf_opaque_type10_lsa_originate (struct thread *t) +{ + struct ospf_area *area; + int rc; + + area = THREAD_ARG (t); + area->t_opaque_lsa_self = NULL; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Type10-LSA]: Originate Opaque-LSAs for Area %s", + inet_ntoa (area->area_id)); + + rc = opaque_lsa_originate_callback (ospf_opaque_type10_funclist, area); + + return rc; +} + +static int +ospf_opaque_type11_lsa_originate (struct thread *t) +{ + struct ospf *top; + int rc; + + top = THREAD_ARG (t); + top->t_opaque_lsa_self = NULL; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Type11-LSA]: Originate AS-External Opaque-LSAs"); + + rc = opaque_lsa_originate_callback (ospf_opaque_type11_funclist, top); + + return rc; +} + +static void +ospf_opaque_lsa_reoriginate_resume (list listtop, void *arg) +{ + listnode node; + struct opaque_info_per_type *oipt; + struct ospf_opaque_functab *functab; + + if (listtop == NULL) + goto out; + + /* + * Pickup oipt entries those which in SUSPEND status, and give + * them a chance to start re-origination now. + */ + for (node = listhead (listtop); node; nextnode (node)) + { + if ((oipt = getdata (node)) == NULL + || oipt->status != PROC_SUSPEND) + continue; + + oipt->status = PROC_NORMAL; + + if ((functab = oipt->functab) == NULL + || functab->lsa_originator == NULL) + continue; + + if ((* functab->lsa_originator)(arg) != 0) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_resume: Failed (opaque-type=%u)", oipt->opaque_type); + continue; + } + } + +out: + return; +} + +struct ospf_lsa * +ospf_opaque_lsa_install (struct ospf_lsa *lsa, int rt_recalc) +{ + struct ospf_lsa *new = NULL; + struct opaque_info_per_type *oipt; + struct opaque_info_per_id *oipi; + struct ospf *top; + + /* Don't take "rt_recalc" into consideration for now. *//* XXX */ + + if (! IS_LSA_SELF (lsa)) + { + new = lsa; /* Don't touch this LSA. */ + goto out; + } + + if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) + zlog_info ("Install Type-%u Opaque-LSA: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); + + /* Replace the existing lsa with the new one. */ + if ((oipt = lookup_opaque_info_by_type (lsa)) != NULL + && (oipi = lookup_opaque_info_by_id (oipt, lsa)) != NULL) + { + ospf_lsa_unlock (oipi->lsa); + oipi->lsa = ospf_lsa_lock (lsa); + } + /* Register the new lsa entry and get its control info. */ + else + if ((oipi = register_opaque_lsa (lsa)) == NULL) + { + zlog_warn ("ospf_opaque_lsa_install: register_opaque_lsa() ?"); + goto out; + } + + /* + * Make use of a common mechanism (ospf_lsa_refresh_walker) + * for periodic refresh of self-originated Opaque-LSAs. + */ + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + if ((top = oi_to_top (lsa->oi)) == NULL) + { + /* Above conditions must have passed. */ + zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?"); + goto out; + } + break; + case OSPF_OPAQUE_AREA_LSA: + if (lsa->area == NULL || (top = lsa->area->ospf) == NULL) + { + /* Above conditions must have passed. */ + zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?"); + goto out; + } + break; + case OSPF_OPAQUE_AS_LSA: + top = ospf_lookup (); + if (lsa->area != NULL && (top = lsa->area->ospf) == NULL) + { + /* Above conditions must have passed. */ + zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?"); + goto out; + } + break; + default: + zlog_warn ("ospf_opaque_lsa_install: Unexpected LSA-type(%u)", lsa->data->type); + goto out; + } + + ospf_refresher_register_lsa (top, lsa); + new = lsa; + +out: + return new; +} + +void +ospf_opaque_lsa_refresh (struct ospf_lsa *lsa) +{ + struct ospf *ospf; + struct ospf_opaque_functab *functab; + + ospf = ospf_lookup (); + + if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL + || functab->lsa_refresher == NULL) + { + /* + * Though this LSA seems to have originated on this node, the + * handling module for this "lsa-type and opaque-type" was + * already deleted sometime ago. + * Anyway, this node still has a responsibility to flush this + * LSA from the routing domain. + */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type%d:%s]: Flush stray Opaque-LSA", lsa->data->type, inet_ntoa (lsa->data->id)); + + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + ospf_lsa_maxage (ospf, lsa); + } + else + (* functab->lsa_refresher)(lsa); + + return; +} + +/*------------------------------------------------------------------------* + * Followings are re-origination/refresh/flush operations of Opaque-LSAs, + * triggered by external interventions (vty session, signaling, etc). + *------------------------------------------------------------------------*/ + +#define OSPF_OPAQUE_TIMER_ON(T,F,L,V) \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), (L), (V)) + +static struct ospf_lsa *pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area, u_char lsa_type, u_char opaque_type); +static int ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t); +static int ospf_opaque_type10_lsa_reoriginate_timer (struct thread *t); +static int ospf_opaque_type11_lsa_reoriginate_timer (struct thread *t); +static int ospf_opaque_lsa_refresh_timer (struct thread *t); + +void +ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent, + u_char lsa_type, u_char opaque_type) +{ + struct ospf *top; + struct ospf_area dummy, *area = NULL; + struct ospf_interface *oi = NULL; + + struct ospf_lsa *lsa; + struct opaque_info_per_type *oipt; + int (* func)(struct thread *t) = NULL; + int delay; + + switch (lsa_type) + { + case OSPF_OPAQUE_LINK_LSA: + if ((oi = (struct ospf_interface *) lsa_type_dependent) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Type-9 Opaque-LSA: Invalid parameter?"); + goto out; + } + if ((top = oi_to_top (oi)) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: OI(%s) -> TOP?", IF_NAME (oi)); + goto out; + } + if (! list_isempty (ospf_opaque_type9_funclist) + && list_isempty (oi->opaque_lsa_self) + && oi->t_opaque_lsa_self != NULL) + { + zlog_warn ("Type-9 Opaque-LSA (opaque_type=%u): Common origination for OI(%s) has already started", opaque_type, IF_NAME (oi)); + goto out; + } + func = ospf_opaque_type9_lsa_reoriginate_timer; + break; + case OSPF_OPAQUE_AREA_LSA: + if ((area = (struct ospf_area *) lsa_type_dependent) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Type-10 Opaque-LSA: Invalid parameter?"); + goto out; + } + if ((top = area->ospf) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: AREA(%s) -> TOP?", inet_ntoa (area->area_id)); + goto out; + } + if (! list_isempty (ospf_opaque_type10_funclist) + && list_isempty (area->opaque_lsa_self) + && area->t_opaque_lsa_self != NULL) + { + zlog_warn ("Type-10 Opaque-LSA (opaque_type=%u): Common origination for AREA(%s) has already started", opaque_type, inet_ntoa (area->area_id)); + goto out; + } + func = ospf_opaque_type10_lsa_reoriginate_timer; + break; + case OSPF_OPAQUE_AS_LSA: + if ((top = (struct ospf *) lsa_type_dependent) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Type-11 Opaque-LSA: Invalid parameter?"); + goto out; + } + if (! list_isempty (ospf_opaque_type11_funclist) + && list_isempty (top->opaque_lsa_self) + && top->t_opaque_lsa_self != NULL) + { + zlog_warn ("Type-11 Opaque-LSA (opaque_type=%u): Common origination has already started", opaque_type); + goto out; + } + + /* Fake "area" to pass "ospf" to a lookup function later. */ + dummy.ospf = top; + area = &dummy; + + func = ospf_opaque_type11_lsa_reoriginate_timer; + break; + default: + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Unexpected LSA-type(%u)", lsa_type); + goto out; + } + + /* It may not a right time to schedule reorigination now. */ + if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_opaque_lsa_reoriginate_schedule: Not operational."); + goto out; /* This is not an error. */ + } + if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_opaque_lsa_reoriginate_schedule: Under blockade."); + goto out; /* This is not an error, too. */ + } + + /* Generate a dummy lsa to be passed for a lookup function. */ + lsa = pseudo_lsa (oi, area, lsa_type, opaque_type); + + if ((oipt = lookup_opaque_info_by_type (lsa)) == NULL) + { + struct ospf_opaque_functab *functab; + if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: No associated function?: lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type); + goto out; + } + if ((oipt = register_opaque_info_per_type (functab, lsa)) == NULL) + { + zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: Cannot get a control info?: lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type); + goto out; + } + } + + if (oipt->t_opaque_lsa_self != NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Type-%u Opaque-LSA has already scheduled to RE-ORIGINATE: [opaque-type=%u]", lsa_type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr))); + goto out; + } + + /* + * Different from initial origination time, in which various conditions + * (opaque capability, neighbor status etc) are assured by caller of + * the originating function "ospf_opaque_lsa_originate_schedule ()", + * it is highly possible that these conditions might not be satisfied + * at the time of re-origination function is to be called. + */ + delay = OSPF_MIN_LS_INTERVAL; /* XXX */ + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Schedule Type-%u Opaque-LSA to RE-ORIGINATE in %d sec later: [opaque-type=%u]", lsa_type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr))); + + OSPF_OPAQUE_TIMER_ON (oipt->t_opaque_lsa_self, func, oipt, delay); + +out: + return; +} + +static struct ospf_lsa * +pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area, + u_char lsa_type, u_char opaque_type) +{ + static struct ospf_lsa lsa = { 0 }; + static struct lsa_header lsah = { 0 }; + u_int32_t tmp; + + lsa.oi = oi; + lsa.area = area; + lsa.data = &lsah; + + lsah.type = lsa_type; + tmp = SET_OPAQUE_LSID (opaque_type, 0); /* Opaque-ID is unused here. */ + lsah.id.s_addr = htonl (tmp); + + return &lsa; +} + +static int +ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t) +{ + struct opaque_info_per_type *oipt; + struct ospf_opaque_functab *functab; + struct ospf *top; + struct ospf_interface *oi; + int rc = -1; + + oipt = THREAD_ARG (t); + oipt->t_opaque_lsa_self = NULL; + + if ((functab = oipt->functab) == NULL + || functab->lsa_originator == NULL) + { + zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: No associated function?"); + goto out; + } + + oi = (struct ospf_interface *) oipt->owner; + if ((top = oi_to_top (oi)) == NULL) + { + zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: Something wrong?"); + goto out; + } + + if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE) + || ! ospf_if_is_enable (oi) + || ospf_nbr_count_opaque_capable (oi) == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Suspend re-origination of Type-9 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type); + + oipt->status = PROC_SUSPEND; + rc = 0; + goto out; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Type9-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for OI (%s)", oipt->opaque_type, IF_NAME (oi)); + + rc = (* functab->lsa_originator)(oi); +out: + return rc; +} + +static int +ospf_opaque_type10_lsa_reoriginate_timer (struct thread *t) +{ + struct opaque_info_per_type *oipt; + struct ospf_opaque_functab *functab; + listnode node; + struct ospf *top; + struct ospf_area *area; + struct ospf_interface *oi; + int n, rc = -1; + + oipt = THREAD_ARG (t); + oipt->t_opaque_lsa_self = NULL; + + if ((functab = oipt->functab) == NULL + || functab->lsa_originator == NULL) + { + zlog_warn ("ospf_opaque_type10_lsa_reoriginate_timer: No associated function?"); + goto out; + } + + area = (struct ospf_area *) oipt->owner; + if (area == NULL || (top = area->ospf) == NULL) + { + zlog_warn ("ospf_opaque_type10_lsa_reoriginate_timer: Something wrong?"); + goto out; + } + + /* There must be at least one "opaque-capable, full-state" neighbor. */ + n = 0; + for (node = listhead (area->oiflist); node; nextnode (node)) + { + if ((oi = getdata (node)) == NULL) + continue; + if ((n = ospf_nbr_count_opaque_capable (oi)) > 0) + break; + } + + if (n == 0 || ! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Suspend re-origination of Type-10 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type); + + oipt->status = PROC_SUSPEND; + rc = 0; + goto out; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Type10-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for Area %s", oipt->opaque_type, inet_ntoa (area->area_id)); + + rc = (* functab->lsa_originator)(area); +out: + return rc; +} + +static int +ospf_opaque_type11_lsa_reoriginate_timer (struct thread *t) +{ + struct opaque_info_per_type *oipt; + struct ospf_opaque_functab *functab; + struct ospf *top; + int rc = -1; + + oipt = THREAD_ARG (t); + oipt->t_opaque_lsa_self = NULL; + + if ((functab = oipt->functab) == NULL + || functab->lsa_originator == NULL) + { + zlog_warn ("ospf_opaque_type11_lsa_reoriginate_timer: No associated function?"); + goto out; + } + + if ((top = (struct ospf *) oipt->owner) == NULL) + { + zlog_warn ("ospf_opaque_type11_lsa_reoriginate_timer: Something wrong?"); + goto out; + } + + if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Suspend re-origination of Type-11 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type); + + oipt->status = PROC_SUSPEND; + rc = 0; + goto out; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Type11-LSA]: Re-originate Opaque-LSAs (opaque-type=%u).", oipt->opaque_type); + + rc = (* functab->lsa_originator)(top); +out: + return rc; +} + +extern int ospf_lsa_refresh_delay (struct ospf_lsa *); /* ospf_lsa.c */ + +void +ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa0) +{ + struct ospf *ospf = ospf; + struct opaque_info_per_type *oipt; + struct opaque_info_per_id *oipi; + struct ospf_lsa *lsa; + int delay; + + ospf = ospf_lookup (); + + if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL + || (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL) + { + zlog_warn ("ospf_opaque_lsa_refresh_schedule: Invalid parameter?"); + goto out; + } + + /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */ + if ((lsa = oipi->lsa) == NULL) + { + zlog_warn ("ospf_opaque_lsa_refresh_schedule: Something wrong?"); + goto out; + } + + if (oipi->t_opaque_lsa_self != NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Type-%u Opaque-LSA has already scheduled to REFRESH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); + goto out; + } + + /* Delete this lsa from neighbor retransmit-list. */ + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + ospf_ls_retransmit_delete_nbr_area (lsa->area, lsa); + break; + case OSPF_OPAQUE_AS_LSA: + ospf_ls_retransmit_delete_nbr_as (ospf, lsa); + break; + default: + zlog_warn ("ospf_opaque_lsa_refresh_schedule: Unexpected LSA-type(%u)", lsa->data->type); + goto out; + } + + delay = ospf_lsa_refresh_delay (lsa); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Schedule Type-%u Opaque-LSA to REFRESH in %d sec later: [opaque-type=%u, opaque-id=%x]", lsa->data->type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); + + OSPF_OPAQUE_TIMER_ON (oipi->t_opaque_lsa_self, + ospf_opaque_lsa_refresh_timer, oipi, delay); +out: + return; +} + +static int +ospf_opaque_lsa_refresh_timer (struct thread *t) +{ + struct opaque_info_per_id *oipi; + struct ospf_opaque_functab *functab; + struct ospf_lsa *lsa; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Timer[Opaque-LSA]: (Opaque-LSA Refresh expire)"); + + oipi = THREAD_ARG (t); + oipi->t_opaque_lsa_self = NULL; + + if ((lsa = oipi->lsa) != NULL) + if ((functab = oipi->opqctl_type->functab) != NULL) + if (functab->lsa_refresher != NULL) + (* functab->lsa_refresher)(lsa); + + return 0; +} + +void +ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0) +{ + struct ospf *ospf = ospf; + struct opaque_info_per_type *oipt; + struct opaque_info_per_id *oipi; + struct ospf_lsa *lsa; + + ospf = ospf_lookup (); + + if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL + || (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL) + { + zlog_warn ("ospf_opaque_lsa_flush_schedule: Invalid parameter?"); + goto out; + } + + /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */ + if ((lsa = oipi->lsa) == NULL) + { + zlog_warn ("ospf_opaque_lsa_flush_schedule: Something wrong?"); + goto out; + } + + /* Delete this lsa from neighbor retransmit-list. */ + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + ospf_ls_retransmit_delete_nbr_area (lsa->area, lsa); + break; + case OSPF_OPAQUE_AS_LSA: + ospf_ls_retransmit_delete_nbr_as (ospf, lsa); + break; + default: + zlog_warn ("ospf_opaque_lsa_flush_schedule: Unexpected LSA-type(%u)", lsa->data->type); + goto out; + } + + /* Dequeue listnode entry from the list. */ + listnode_delete (oipt->id_list, oipi); + + /* Avoid misjudgement in the next lookup. */ + if (listcount (oipt->id_list) == 0) + oipt->id_list->head = oipt->id_list->tail = NULL; + + /* Disassociate internal control information with the given lsa. */ + oipi->lsa = NULL; + free_opaque_info_per_id ((void *) oipi); + + /* Force given lsa's age to MaxAge. */ + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); + + /* This lsa will be flushed and removed eventually. */ + ospf_lsa_maxage (ospf, lsa); + +out: + return; +} + +/*------------------------------------------------------------------------* + * Followings are control functions to block origination after restart. + *------------------------------------------------------------------------*/ + +static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa); +static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi); +static void ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area); +static void ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top); +static unsigned long ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type); + +void +ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, list lsas) +{ + struct ospf *top; + struct ospf_area *area; + struct ospf_interface *oi; + listnode node1, node2; + struct ospf_lsa *lsa; + + if ((top = oi_to_top (nbr->oi)) == NULL) + goto out; + + /* + * If an instance of self-originated Opaque-LSA is found in the given + * LSA list, and it is not installed to LSDB yet, exclude it from the + * list "nbr->ls_req". In this way, it is assured that an LSReq message, + * which might be sent in the process of flooding, will not request for + * the LSA to be flushed immediately; otherwise, depending on timing, + * an LSUpd message will carry instances of target LSAs with MaxAge, + * while other LSUpd message might carry old LSA instances (non-MaxAge). + * Obviously, the latter would trigger miserable situations that repeat + * installation and removal of unwanted LSAs indefinitely. + */ + for (node1 = listhead (lsas); node1; nextnode (node1)) + { + if ((lsa = getdata (node1)) == NULL) + continue; + + /* Filter out unwanted LSAs. */ + if (! IS_OPAQUE_LSA (lsa->data->type)) + continue; + if (! IPV4_ADDR_SAME (&lsa->data->adv_router, &top->router_id)) + continue; + + /* + * Don't touch an LSA which has MaxAge; two possible cases. + * + * 1) This LSA has originally flushed by myself (received LSUpd + * message's router-id is equal to my router-id), and flooded + * back by an opaque-capable router. + * + * 2) This LSA has expired in an opaque-capable router and thus + * flushed by the router. + */ + if (IS_LSA_MAXAGE (lsa)) + continue; + + /* If the LSA has installed in the LSDB, nothing to do here. */ + if (ospf_lsa_lookup_by_header (nbr->oi->area, lsa->data) != NULL) + continue; + + /* Ok, here we go. */ + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + oi = nbr->oi; + ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); + break; + case OSPF_OPAQUE_AREA_LSA: + area = nbr->oi->area; + for (node2 = listhead (area->oiflist); node2; nextnode (node2)) + { + if ((oi = getdata (node2)) == NULL) + continue; + ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); + } + break; + case OSPF_OPAQUE_AS_LSA: + for (node2 = listhead (top->oiflist); node2; nextnode (node2)) + { + if ((oi = getdata (node2)) == NULL) + continue; + ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); + } + break; + default: + break; + } + } + +out: + return; +} + +static void +ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, + struct ospf_neighbor *inbr, + struct ospf_lsa *lsa) +{ + struct route_node *rn; + struct ospf_neighbor *onbr; + struct ospf_lsa *ls_req; + + for (rn = route_top (nbrs); rn; rn = route_next (rn)) + { + if ((onbr = rn->info) == NULL) + continue; + if (onbr == inbr) + continue; + if ((ls_req = ospf_ls_request_lookup (onbr, lsa)) == NULL) + continue; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[%s]: Exclude this entry from LSReq to send.", dump_lsa_key (lsa)); + + ospf_ls_request_delete (onbr, ls_req); +/* ospf_check_nbr_loading (onbr);*//* XXX */ + } + + return; +} + +void +ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, list lsas) +{ + struct ospf *top; + listnode node, next; + struct ospf_lsa *lsa; + u_char before; + + if ((top = oi_to_top (nbr->oi)) == NULL) + goto out; + + before = IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque); + + for (node = listhead (lsas); node; node = next) + { + next = node->next; + + if ((lsa = getdata (node)) == NULL) + continue; + + listnode_delete (lsas, lsa); + + /* + * Since these LSA entries are not yet installed into corresponding + * LSDB, just flush them without calling ospf_ls_maxage() afterward. + */ + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); + ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); + break; + case OSPF_OPAQUE_AREA_LSA: + SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); + ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); + break; + case OSPF_OPAQUE_AS_LSA: + SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); + ospf_flood_through_as (top, NULL/*inbr*/, lsa); + break; + default: + zlog_warn ("ospf_opaque_self_originated_lsa_received: Unexpected LSA-type(%u)", lsa->data->type); + goto out; + } + + ospf_lsa_discard (lsa); /* List "lsas" will be deleted by caller. */ + } + + if (before == 0 && IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Block Opaque-LSA origination: OFF -> ON"); + } + +out: + return; +} + +void +ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, list acks) +{ + struct ospf *top; + listnode node; + struct ospf_lsa *lsa; + char type9_lsa_rcv = 0, type10_lsa_rcv = 0, type11_lsa_rcv = 0; + + if ((top = oi_to_top (nbr->oi)) == NULL) + goto out; + + for (node = listhead (acks); node; nextnode (node)) + { + if ((lsa = getdata (node)) == NULL) + continue; + + switch (lsa->data->type) + { + case OSPF_OPAQUE_LINK_LSA: + type9_lsa_rcv = 1; + /* Callback function... */ + break; + case OSPF_OPAQUE_AREA_LSA: + type10_lsa_rcv = 1; + /* Callback function... */ + break; + case OSPF_OPAQUE_AS_LSA: + type11_lsa_rcv = 1; + /* Callback function... */ + break; + default: + zlog_warn ("ospf_opaque_ls_ack_received: Unexpected LSA-type(%u)", lsa->data->type); + goto out; + } + } + + if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) + { + int delay; + struct ospf_interface *oi; + + if (type9_lsa_rcv + && CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT)) + ospf_opaque_type9_lsa_rxmt_nbr_check (nbr->oi); + + if (type10_lsa_rcv + && CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT)) + ospf_opaque_type10_lsa_rxmt_nbr_check (nbr->oi->area); + + if (type11_lsa_rcv + && CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT)) + ospf_opaque_type11_lsa_rxmt_nbr_check (top); + + if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) + goto out; /* Blocking still in progress. */ + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Block Opaque-LSA origination: ON -> OFF"); + + if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) + goto out; /* Opaque capability condition must have changed. */ + + /* Ok, let's start origination of Opaque-LSAs. */ + delay = OSPF_MIN_LS_INTERVAL; + for (node = listhead (top->oiflist); node; nextnode (node)) + { + if ((oi = getdata (node)) == NULL) + continue; + + if (! ospf_if_is_enable (oi) + || ospf_nbr_count_opaque_capable (oi) == 0) + continue; + + ospf_opaque_lsa_originate_schedule (oi, &delay); + } + } + +out: + return; +} + +static void +ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi) +{ + unsigned long n; + + n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_LINK_LSA); + if (n == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Self-originated type-9 Opaque-LSAs: OI(%s): Flush completed", IF_NAME (oi)); + + UNSET_FLAG (oi->area->ospf->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); + } + return; +} + +static void +ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area) +{ + listnode node; + struct ospf_interface *oi; + unsigned long n = 0; + + for (node = listhead (area->oiflist); node; nextnode (node)) + { + if ((oi = getdata (node)) == NULL) + continue; + + if (area->area_id.s_addr != OSPF_AREA_BACKBONE + && oi->type == OSPF_IFTYPE_VIRTUALLINK) + continue; + + n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AREA_LSA); + if (n > 0) + break; + } + + if (n == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Self-originated type-10 Opaque-LSAs: AREA(%s): Flush completed", inet_ntoa (area->area_id)); + + UNSET_FLAG (area->ospf->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); + } + + return; +} + +static void +ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top) +{ + listnode node; + struct ospf_interface *oi; + unsigned long n = 0; + + for (node = listhead (top->oiflist); node; nextnode (node)) + { + if ((oi = getdata (node)) == NULL) + continue; + + switch (oi->type) + { + case OSPF_IFTYPE_VIRTUALLINK: + continue; + default: + break; + } + + n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AS_LSA); + if (n > 0) + goto out; + } + + if (n == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Self-originated type-11 Opaque-LSAs: Flush completed"); + + UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); + } + +out: + return; +} + +static unsigned long +ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type) +{ + struct route_node *rn; + struct ospf_neighbor *nbr; + struct ospf *top; + unsigned long n = 0; + + for (rn = route_top (nbrs); rn; rn = route_next (rn)) + { + if ((nbr = rn->info) == NULL) + continue; + if ((top = oi_to_top (nbr->oi)) == NULL) + continue; + if (IPV4_ADDR_SAME (&nbr->router_id, &top->router_id)) + continue; + n += ospf_ls_retransmit_count_self (nbr, lsa_type); + } + + return n; +} + +/*------------------------------------------------------------------------* + * Followings are util functions; probably be used by Opaque-LSAs only... + *------------------------------------------------------------------------*/ + +void +htonf (float *src, float *dst) +{ + u_int32_t lu1, lu2; + + memcpy (&lu1, src, sizeof (u_int32_t)); + lu2 = htonl (lu1); + memcpy (dst, &lu2, sizeof (u_int32_t)); + return; +} + +void +ntohf (float *src, float *dst) +{ + u_int32_t lu1, lu2; + + memcpy (&lu1, src, sizeof (u_int32_t)); + lu2 = ntohl (lu1); + memcpy (dst, &lu2, sizeof (u_int32_t)); + return; +} + +struct ospf * +oi_to_top (struct ospf_interface *oi) +{ + struct ospf *top = NULL; + struct ospf_area *area; + + if (oi == NULL || (area = oi->area) == NULL || (top = area->ospf) == NULL) + zlog_warn ("Broken relationship for \"OI -> AREA -> OSPF\"?"); + + return top; +} + +#endif /* HAVE_OPAQUE_LSA */ diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h new file mode 100644 index 0000000..9aa08e5 --- /dev/null +++ b/ospfd/ospf_opaque.h @@ -0,0 +1,155 @@ +/* + * This is an implementation of rfc2370. + * Copyright (C) 2001 KDD R&D Laboratories, Inc. + * http://www.kddlabs.co.jp/ + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_OPAQUE_H +#define _ZEBRA_OSPF_OPAQUE_H + +#define IS_OPAQUE_LSA(type) \ + ((type) == OSPF_OPAQUE_LINK_LSA || \ + (type) == OSPF_OPAQUE_AREA_LSA || \ + (type) == OSPF_OPAQUE_AS_LSA) + +/* + * Usage of Opaque-LSA administrative flags in "struct ospf". + * + * 7 6 5 4 3 2 1 0 + * +---+---+---+---+---+---+---+---+ + * |///|///|///|///|B11|B10|B09| O | + * +---+---+---+---+---+---+---+---+ + * |<--------->| A + * | +--- Operation status (operational = 1) + * +----------- Blocking status for each LSA type + */ + +#define IS_OPAQUE_LSA_ORIGINATION_BLOCKED(V) \ + CHECK_FLAG((V), (OPAQUE_BLOCK_TYPE_09_LSA_BIT | \ + OPAQUE_BLOCK_TYPE_10_LSA_BIT | \ + OPAQUE_BLOCK_TYPE_11_LSA_BIT)) + +/* + * Opaque LSA's link state ID is redefined as follows. + * + * 24 16 8 0 + * +--------+--------+--------+--------+ + * |tttttttt|........|........|........| + * +--------+--------+--------+--------+ + * |<-Type->|<------- Opaque ID ------>| + */ +#define LSID_OPAQUE_TYPE_MASK 0xff000000 /* 8 bits */ +#define LSID_OPAQUE_ID_MASK 0x00ffffff /* 24 bits */ + +#define GET_OPAQUE_TYPE(lsid) \ + (((u_int32_t)(lsid) & LSID_OPAQUE_TYPE_MASK) >> 24) + +#define GET_OPAQUE_ID(lsid) \ + ((u_int32_t)(lsid) & LSID_OPAQUE_ID_MASK) + +#define SET_OPAQUE_LSID(type, id) \ + ((((type) << 24) & LSID_OPAQUE_TYPE_MASK) \ + | ((id) & LSID_OPAQUE_ID_MASK)) + +/* + * Opaque LSA types will be assigned by IANA. + * + */ +#define OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA 1 +#define OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC 2 +#define OPAQUE_TYPE_GRACE_LSA 3 + +/* Followings types are proposed in internet-draft documents. */ +#define OPAQUE_TYPE_8021_QOSPF 129 +#define OPAQUE_TYPE_SECONDARY_NEIGHBOR_DISCOVERY 224 +#define OPAQUE_TYPE_FLOODGATE 225 + +/* Ugly hack to make use of an unallocated value for wildcard matching! */ +#define OPAQUE_TYPE_WILDCARD 0 + +#define OPAQUE_TYPE_RANGE_UNASSIGNED(type) \ + ( 4 <= (type) && (type) <= 127) + +#define OPAQUE_TYPE_RANGE_RESERVED(type) \ + (127 < (type) && (type) <= 255) + +#define VALID_OPAQUE_INFO_LEN(lsahdr) \ + ((ntohs((lsahdr)->length) >= sizeof (struct lsa_header)) && \ + ((ntohs((lsahdr)->length) % sizeof (u_int32_t)) == 0)) + +/* Prototypes. */ +struct vty; +struct stream; + +extern void ospf_opaque_init (void); +extern void ospf_opaque_term (void); +extern int ospf_opaque_type9_lsa_init (struct ospf_interface *oi); +extern void ospf_opaque_type9_lsa_term (struct ospf_interface *oi); +extern int ospf_opaque_type10_lsa_init (struct ospf_area *area); +extern void ospf_opaque_type10_lsa_term (struct ospf_area *area); +extern int ospf_opaque_type11_lsa_init (struct ospf *ospf); +extern void ospf_opaque_type11_lsa_term (struct ospf *ospf); + +extern int +ospf_register_opaque_functab ( + u_char lsa_type, + u_char opaque_type, + int (* new_if_hook)(struct interface *ifp), + int (* del_if_hook)(struct interface *ifp), + void (* ism_change_hook)(struct ospf_interface *oi, int old_status), + void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status), + void (* config_write_router)(struct vty *vty), + void (* config_write_if )(struct vty *vty, struct interface *ifp), + void (* config_write_debug )(struct vty *vty), + void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa), + int (* lsa_originator)(void *arg), + void (* lsa_refresher )(struct ospf_lsa *lsa), + int (* new_lsa_hook)(struct ospf_lsa *lsa), + int (* del_lsa_hook)(struct ospf_lsa *lsa) +); +extern void ospf_delete_opaque_functab (u_char lsa_type, u_char opaque_type); + +extern int ospf_opaque_new_if (struct interface *ifp); +extern int ospf_opaque_del_if (struct interface *ifp); +extern void ospf_opaque_ism_change (struct ospf_interface *oi, int old_status); +extern void ospf_opaque_nsm_change (struct ospf_neighbor *nbr, int old_status); +extern void ospf_opaque_config_write_router (struct vty *vty, struct ospf *); +extern void ospf_opaque_config_write_if (struct vty *vty, struct interface *ifp); +extern void ospf_opaque_config_write_debug (struct vty *vty); +extern void show_opaque_info_detail (struct vty *vty, struct ospf_lsa *lsa); +extern void ospf_opaque_lsa_dump (struct stream *s, u_int16_t length); + +extern void ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *init_delay); +extern struct ospf_lsa *ospf_opaque_lsa_install (struct ospf_lsa *new, int rt_recalc); +extern void ospf_opaque_lsa_refresh (struct ospf_lsa *lsa); + +extern void ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent, u_char lsa_type, u_char opaque_type); +extern void ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa); +extern void ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa); + +extern void ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, list lsas); +extern void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, list lsas); +extern void ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, list acks); + +extern void htonf (float *src, float *dst); +extern void ntohf (float *src, float *dst); +extern struct ospf *oi_to_top (struct ospf_interface *oi); + +#endif /* _ZEBRA_OSPF_OPAQUE_H */ diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c new file mode 100644 index 0000000..bf9e69b --- /dev/null +++ b/ospfd/ospf_packet.c @@ -0,0 +1,3249 @@ +/* + * OSPF Sending and Receiving OSPF Packets. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "sockunion.h" +#include "stream.h" +#include "log.h" +#include "checksum.h" +#include "md5-gnu.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_network.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_dump.h" + +static void ospf_ls_ack_send_list (struct ospf_interface *, list, + struct in_addr); + +/* Packet Type String. */ +char *ospf_packet_type_str[] = + { + "unknown", + "Hello", + "Database Description", + "Link State Request", + "Link State Update", + "Link State Acknowledgment", + }; + +/* OSPF authentication checking function */ +int +ospf_auth_type (struct ospf_interface *oi) +{ + int auth_type; + + if (OSPF_IF_PARAM (oi, auth_type) == OSPF_AUTH_NOTSET) + auth_type = oi->area->auth_type; + else + auth_type = OSPF_IF_PARAM (oi, auth_type); + + /* Handle case where MD5 key list is not configured aka Cisco */ + if (auth_type == OSPF_AUTH_CRYPTOGRAPHIC && + list_isempty (OSPF_IF_PARAM (oi, auth_crypt))) + return OSPF_AUTH_NULL; + + return auth_type; + +} + +/* forward output pointer. */ +void +ospf_output_forward (struct stream *s, int size) +{ + s->putp += size; +} + +struct ospf_packet * +ospf_packet_new (size_t size) +{ + struct ospf_packet *new; + + new = XCALLOC (MTYPE_OSPF_PACKET, sizeof (struct ospf_packet)); + new->s = stream_new (size); + + return new; +} + +void +ospf_packet_free (struct ospf_packet *op) +{ + if (op->s) + stream_free (op->s); + + XFREE (MTYPE_OSPF_PACKET, op); + + op = NULL; +} + +struct ospf_fifo * +ospf_fifo_new () +{ + struct ospf_fifo *new; + + new = XCALLOC (MTYPE_OSPF_FIFO, sizeof (struct ospf_fifo)); + return new; +} + +/* Add new packet to fifo. */ +void +ospf_fifo_push (struct ospf_fifo *fifo, struct ospf_packet *op) +{ + if (fifo->tail) + fifo->tail->next = op; + else + fifo->head = op; + + fifo->tail = op; + + fifo->count++; +} + +/* Delete first packet from fifo. */ +struct ospf_packet * +ospf_fifo_pop (struct ospf_fifo *fifo) +{ + struct ospf_packet *op; + + op = fifo->head; + + if (op) + { + fifo->head = op->next; + + if (fifo->head == NULL) + fifo->tail = NULL; + + fifo->count--; + } + + return op; +} + +/* Return first fifo entry. */ +struct ospf_packet * +ospf_fifo_head (struct ospf_fifo *fifo) +{ + return fifo->head; +} + +/* Flush ospf packet fifo. */ +void +ospf_fifo_flush (struct ospf_fifo *fifo) +{ + struct ospf_packet *op; + struct ospf_packet *next; + + for (op = fifo->head; op; op = next) + { + next = op->next; + ospf_packet_free (op); + } + fifo->head = fifo->tail = NULL; + fifo->count = 0; +} + +/* Free ospf packet fifo. */ +void +ospf_fifo_free (struct ospf_fifo *fifo) +{ + ospf_fifo_flush (fifo); + + XFREE (MTYPE_OSPF_FIFO, fifo); +} + +void +ospf_packet_add (struct ospf_interface *oi, struct ospf_packet *op) +{ + /* Add packet to end of queue. */ + ospf_fifo_push (oi->obuf, op); + + /* Debug of packet fifo*/ + /* ospf_fifo_debug (oi->obuf); */ +} + +void +ospf_packet_delete (struct ospf_interface *oi) +{ + struct ospf_packet *op; + + op = ospf_fifo_pop (oi->obuf); + + if (op) + ospf_packet_free (op); +} + +struct stream * +ospf_stream_copy (struct stream *new, struct stream *s) +{ + new->endp = s->endp; + new->putp = s->putp; + new->getp = s->getp; + + memcpy (new->data, s->data, stream_get_endp (s)); + + return new; +} + +struct ospf_packet * +ospf_packet_dup (struct ospf_packet *op) +{ + struct ospf_packet *new; + + if (stream_get_endp(op->s) != op->length) + zlog_warn ("ospf_packet_dup stream %ld ospf_packet %d size mismatch", + STREAM_SIZE(op->s), op->length); + + /* Reserve space for MD5 authentication that may be added later. */ + new = ospf_packet_new (stream_get_endp(op->s) + OSPF_AUTH_MD5_SIZE); + ospf_stream_copy (new->s, op->s); + + new->dst = op->dst; + new->length = op->length; + + return new; +} + +int +ospf_packet_max (struct ospf_interface *oi) +{ + int max; + + if ( ospf_auth_type (oi) == OSPF_AUTH_CRYPTOGRAPHIC) + max = oi->ifp->mtu - OSPF_AUTH_MD5_SIZE - 88; + else + max = oi->ifp->mtu - 88; + + return max; +} + + +int +ospf_check_md5_digest (struct ospf_interface *oi, struct stream *s, + u_int16_t length) +{ + void *ibuf; + struct md5_ctx ctx; + unsigned char digest[OSPF_AUTH_MD5_SIZE]; + unsigned char *pdigest; + struct crypt_key *ck; + struct ospf_header *ospfh; + struct ospf_neighbor *nbr; + + + ibuf = STREAM_PNT (s); + ospfh = (struct ospf_header *) ibuf; + + /* Get pointer to the end of the packet. */ + pdigest = (unsigned char *) ibuf + length; + + /* Get secret key. */ + ck = ospf_crypt_key_lookup (OSPF_IF_PARAM (oi, auth_crypt), + ospfh->u.crypt.key_id); + if (ck == NULL) + { + zlog_warn ("interface %s: ospf_check_md5 no key %d", + IF_NAME (oi), ospfh->u.crypt.key_id); + return 0; + } + + /* check crypto seqnum. */ + nbr = ospf_nbr_lookup_by_routerid (oi->nbrs, &ospfh->router_id); + + if (nbr && ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum)) + { + zlog_warn ("interface %s: ospf_check_md5 bad sequence %d (expect %d)", + IF_NAME (oi), + ntohl(ospfh->u.crypt.crypt_seqnum), + ntohl(nbr->crypt_seqnum)); + return 0; + } + + /* Generate a digest for the ospf packet - their digest + our digest. */ + md5_init_ctx (&ctx); + md5_process_bytes (ibuf, length, &ctx); + md5_process_bytes (ck->auth_key, OSPF_AUTH_MD5_SIZE, &ctx); + md5_finish_ctx (&ctx, digest); + + /* compare the two */ + if (memcmp (pdigest, digest, OSPF_AUTH_MD5_SIZE)) + { + zlog_warn ("interface %s: ospf_check_md5 checksum mismatch", + IF_NAME (oi)); + return 0; + } + + /* save neighbor's crypt_seqnum */ + if (nbr) + nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum; + return 1; +} + +/* This function is called from ospf_write(), it will detect the + authentication scheme and if it is MD5, it will change the sequence + and update the MD5 digest. */ +int +ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op) +{ + struct ospf_header *ospfh; + unsigned char digest[OSPF_AUTH_MD5_SIZE]; + struct md5_ctx ctx; + void *ibuf; + unsigned long oldputp; + u_int32_t t; + struct crypt_key *ck; + char *auth_key; + + ibuf = STREAM_DATA (op->s); + ospfh = (struct ospf_header *) ibuf; + + if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) + return 0; + + /* We do this here so when we dup a packet, we don't have to + waste CPU rewriting other headers. */ + t = (time(NULL) & 0xFFFFFFFF); + oi->crypt_seqnum = ( t > oi->crypt_seqnum ? t : oi->crypt_seqnum++); + ospfh->u.crypt.crypt_seqnum = htonl (oi->crypt_seqnum); + + /* Get MD5 Authentication key from auth_key list. */ + if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt))) + auth_key = ""; + else + { + ck = getdata (OSPF_IF_PARAM (oi, auth_crypt)->tail); + auth_key = ck->auth_key; + } + + /* Generate a digest for the entire packet + our secret key. */ + md5_init_ctx (&ctx); + md5_process_bytes (ibuf, ntohs (ospfh->length), &ctx); + md5_process_bytes (auth_key, OSPF_AUTH_MD5_SIZE, &ctx); + md5_finish_ctx (&ctx, digest); + + /* Append md5 digest to the end of the stream. */ + oldputp = stream_get_putp (op->s); + stream_set_putp (op->s, ntohs (ospfh->length)); + stream_put (op->s, digest, OSPF_AUTH_MD5_SIZE); + stream_set_putp (op->s, oldputp); + + /* We do *NOT* increment the OSPF header length. */ + op->length = ntohs (ospfh->length) + OSPF_AUTH_MD5_SIZE; + + if (stream_get_endp(op->s) != op->length) + zlog_warn("ospf_make_md5_digest: length mismatch stream %ld ospf_packet %d", stream_get_endp(op->s), op->length); + + return OSPF_AUTH_MD5_SIZE; +} + + +int +ospf_ls_req_timer (struct thread *thread) +{ + struct ospf_neighbor *nbr; + + nbr = THREAD_ARG (thread); + nbr->t_ls_req = NULL; + + /* Send Link State Request. */ + if (ospf_ls_request_count (nbr)) + ospf_ls_req_send (nbr); + + /* Set Link State Request retransmission timer. */ + OSPF_NSM_TIMER_ON (nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req); + + return 0; +} + +void +ospf_ls_req_event (struct ospf_neighbor *nbr) +{ + if (nbr->t_ls_req) + { + thread_cancel (nbr->t_ls_req); + nbr->t_ls_req = NULL; + } + nbr->t_ls_req = thread_add_event (master, ospf_ls_req_timer, nbr, 0); +} + +/* Cyclic timer function. Fist registered in ospf_nbr_new () in + ospf_neighbor.c */ +int +ospf_ls_upd_timer (struct thread *thread) +{ + struct ospf_neighbor *nbr; + + nbr = THREAD_ARG (thread); + nbr->t_ls_upd = NULL; + + /* Send Link State Update. */ + if (ospf_ls_retransmit_count (nbr) > 0) + { + list update; + struct ospf_lsdb *lsdb; + int i; + struct timeval now; + int retransmit_interval; + + gettimeofday (&now, NULL); + retransmit_interval = OSPF_IF_PARAM (nbr->oi, retransmit_interval); + + lsdb = &nbr->ls_rxmt; + update = list_new (); + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + { + struct route_table *table = lsdb->type[i].db; + struct route_node *rn; + + for (rn = route_top (table); rn; rn = route_next (rn)) + { + struct ospf_lsa *lsa; + + if ((lsa = rn->info) != NULL) + /* Don't retransmit an LSA if we received it within + the last RxmtInterval seconds - this is to allow the + neighbour a chance to acknowledge the LSA as it may + have ben just received before the retransmit timer + fired. This is a small tweak to what is in the RFC, + but it will cut out out a lot of retransmit traffic + - MAG */ + if (tv_cmp (tv_sub (now, lsa->tv_recv), + int2tv (retransmit_interval)) >= 0) + listnode_add (update, rn->info); + } + } + + if (listcount (update) > 0) + ospf_ls_upd_send (nbr, update, OSPF_SEND_PACKET_DIRECT); + list_delete (update); + } + + /* Set LS Update retransmission timer. */ + OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd); + + return 0; +} + +int +ospf_ls_ack_timer (struct thread *thread) +{ + struct ospf_interface *oi; + + oi = THREAD_ARG (thread); + oi->t_ls_ack = NULL; + + /* Send Link State Acknowledgment. */ + if (listcount (oi->ls_ack) > 0) + ospf_ls_ack_send_delayed (oi); + + /* Set LS Ack timer. */ + OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); + + return 0; +} + +int +ospf_write (struct thread *thread) +{ + struct ospf *ospf = THREAD_ARG (thread); + struct ospf_interface *oi; + struct ospf_packet *op; + struct sockaddr_in sa_dst; + struct ip iph; + struct msghdr msg; + struct iovec iov[2]; + u_char type; + int ret; + int flags = 0; + listnode node; + + ospf->t_write = NULL; + + node = listhead (ospf->oi_write_q); + assert (node); + oi = getdata (node); + assert (oi); + + /* Get one packet from queue. */ + op = ospf_fifo_head (oi->obuf); + assert (op); + assert (op->length >= OSPF_HEADER_SIZE); + + if (op->dst.s_addr == htonl (OSPF_ALLSPFROUTERS) + || op->dst.s_addr == htonl (OSPF_ALLDROUTERS)) + ospf_if_ipmulticast (ospf, oi->address, oi->ifp->ifindex); + + /* Rewrite the md5 signature & update the seq */ + ospf_make_md5_digest (oi, op); + + memset (&sa_dst, 0, sizeof (sa_dst)); + sa_dst.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + sa_dst.sin_len = sizeof(sa_dst); +#endif /* HAVE_SIN_LEN */ + sa_dst.sin_addr = op->dst; + sa_dst.sin_port = htons (0); + + /* Set DONTROUTE flag if dst is unicast. */ + if (oi->type != OSPF_IFTYPE_VIRTUALLINK) + if (!IN_MULTICAST (htonl (op->dst.s_addr))) + flags = MSG_DONTROUTE; + + iph.ip_hl = sizeof (struct ip) >> 2; + iph.ip_v = IPVERSION; + iph.ip_tos = IPTOS_PREC_INTERNETCONTROL; +#if defined(__NetBSD__) || defined(__FreeBSD__) + iph.ip_len = iph.ip_hl*4 + op->length; +#else + iph.ip_len = htons (iph.ip_hl*4 + op->length); +#endif + iph.ip_id = 0; + iph.ip_off = 0; + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + iph.ip_ttl = OSPF_VL_IP_TTL; + else + iph.ip_ttl = OSPF_IP_TTL; + iph.ip_p = IPPROTO_OSPFIGP; + iph.ip_sum = 0; + iph.ip_src.s_addr = oi->address->u.prefix4.s_addr; + iph.ip_dst.s_addr = op->dst.s_addr; + + memset (&msg, 0, sizeof (msg)); + msg.msg_name = &sa_dst; + msg.msg_namelen = sizeof (sa_dst); + msg.msg_iov = iov; + msg.msg_iovlen = 2; + iov[0].iov_base = (char*)&iph; + iov[0].iov_len = iph.ip_hl*4; + iov[1].iov_base = STREAM_DATA (op->s); + iov[1].iov_len = op->length; + + ret = sendmsg (ospf->fd, &msg, flags); + + if (ret < 0) + zlog_warn ("*** sendmsg in ospf_write failed with %s", strerror (errno)); + + /* Retrieve OSPF packet type. */ + stream_set_getp (op->s, 1); + type = stream_getc (op->s); + + /* Show debug sending packet. */ + if (IS_DEBUG_OSPF_PACKET (type - 1, SEND)) + { + if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) + { + zlog_info ("-----------------------------------------------------"); + stream_set_getp (op->s, 0); + ospf_packet_dump (op->s); + } + + zlog_info ("%s sent to [%s] via [%s].", + ospf_packet_type_str[type], inet_ntoa (op->dst), + IF_NAME (oi)); + + if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) + zlog_info ("-----------------------------------------------------"); + } + + /* Now delete packet from queue. */ + ospf_packet_delete (oi); + + if (ospf_fifo_head (oi->obuf) == NULL) + { + oi->on_write_q = 0; + list_delete_node (ospf->oi_write_q, node); + } + + /* If packets still remain in queue, call write thread. */ + if (!list_isempty (ospf->oi_write_q)) + ospf->t_write = + thread_add_write (master, ospf_write, ospf, ospf->fd); + + return 0; +} + +/* OSPF Hello message read -- RFC2328 Section 10.5. */ +void +ospf_hello (struct ip *iph, struct ospf_header *ospfh, + struct stream * s, struct ospf_interface *oi, int size) +{ + struct ospf_hello *hello; + struct ospf_neighbor *nbr; + struct route_node *rn; + struct prefix p, key; + int old_state; + + /* increment statistics. */ + oi->hello_in++; + + hello = (struct ospf_hello *) STREAM_PNT (s); + + /* If Hello is myself, silently discard. */ + if (IPV4_ADDR_SAME (&ospfh->router_id, &oi->ospf->router_id)) + return; + + /* If incoming interface is passive one, ignore Hello. */ + if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE) + return; + + /* get neighbor prefix. */ + p.family = AF_INET; + p.prefixlen = ip_masklen (hello->network_mask); + p.u.prefix4 = iph->ip_src; + + /* Compare network mask. */ + /* Checking is ignored for Point-to-Point and Virtual link. */ + if (oi->type != OSPF_IFTYPE_POINTOPOINT + && oi->type != OSPF_IFTYPE_VIRTUALLINK) + if (oi->address->prefixlen != p.prefixlen) + { + zlog_warn ("Packet %s [Hello:RECV]: NetworkMask mismatch.", + inet_ntoa (ospfh->router_id)); + return; + } + + /* Compare Hello Interval. */ + if (OSPF_IF_PARAM (oi, v_hello) != ntohs (hello->hello_interval)) + { + zlog_warn ("Packet %s [Hello:RECV]: HelloInterval mismatch.", + inet_ntoa (ospfh->router_id)); + return; + } + + /* Compare Router Dead Interval. */ + if (OSPF_IF_PARAM (oi, v_wait) != ntohl (hello->dead_interval)) + { + zlog_warn ("Packet %s [Hello:RECV]: RouterDeadInterval mismatch.", + inet_ntoa (ospfh->router_id)); + return; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Packet %s [Hello:RECV]: Options %s", + inet_ntoa (ospfh->router_id), + ospf_options_dump (hello->options)); + + /* Compare options. */ +#define REJECT_IF_TBIT_ON 1 /* XXX */ +#ifdef REJECT_IF_TBIT_ON + if (CHECK_FLAG (hello->options, OSPF_OPTION_T)) + { + /* + * This router does not support non-zero TOS. + * Drop this Hello packet not to establish neighbor relationship. + */ + zlog_warn ("Packet %s [Hello:RECV]: T-bit on, drop it.", + inet_ntoa (ospfh->router_id)); + return; + } +#endif /* REJECT_IF_TBIT_ON */ + +#ifdef HAVE_OPAQUE_LSA + if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE) + && CHECK_FLAG (hello->options, OSPF_OPTION_O)) + { + /* + * This router does know the correct usage of O-bit + * the bit should be set in DD packet only. + */ + zlog_warn ("Packet %s [Hello:RECV]: O-bit abuse?", + inet_ntoa (ospfh->router_id)); +#ifdef STRICT_OBIT_USAGE_CHECK + return; /* Reject this packet. */ +#else /* STRICT_OBIT_USAGE_CHECK */ + UNSET_FLAG (hello->options, OSPF_OPTION_O); /* Ignore O-bit. */ +#endif /* STRICT_OBIT_USAGE_CHECK */ + } +#endif /* HAVE_OPAQUE_LSA */ + + /* new for NSSA is to ensure that NP is on and E is off */ + +#ifdef HAVE_NSSA + if (oi->area->external_routing == OSPF_AREA_NSSA) + { + if (! (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_NP) + && CHECK_FLAG (hello->options, OSPF_OPTION_NP) + && ! CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_E) + && ! CHECK_FLAG (hello->options, OSPF_OPTION_E))) + { + zlog_warn ("NSSA-Packet-%s[Hello:RECV]: my options: %x, his options %x", inet_ntoa (ospfh->router_id), OPTIONS (oi), hello->options); + return; + } + if (IS_DEBUG_OSPF_NSSA) + zlog_info ("NSSA-Hello:RECV:Packet from %s:", inet_ntoa(ospfh->router_id)); + } + else +#endif /* HAVE_NSSA */ + /* The setting of the E-bit found in the Hello Packet's Options + field must match this area's ExternalRoutingCapability A + mismatch causes processing to stop and the packet to be + dropped. The setting of the rest of the bits in the Hello + Packet's Options field should be ignored. */ + if (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_E) != + CHECK_FLAG (hello->options, OSPF_OPTION_E)) + { + zlog_warn ("Packet[Hello:RECV]: my options: %x, his options %x", + OPTIONS (oi), hello->options); + return; + } + + + /* Get neighbor information from table. */ + key.family = AF_INET; + key.prefixlen = IPV4_MAX_BITLEN; + key.u.prefix4 = iph->ip_src; + + rn = route_node_get (oi->nbrs, &key); + if (rn->info) + { + route_unlock_node (rn); + nbr = rn->info; + + if (oi->type == OSPF_IFTYPE_NBMA && nbr->state == NSM_Attempt) + { + nbr->src = iph->ip_src; + nbr->address = p; + } + } + else + { + /* Create new OSPF Neighbor structure. */ + nbr = ospf_nbr_new (oi); + nbr->state = NSM_Down; + nbr->src = iph->ip_src; + nbr->address = p; + + rn->info = nbr; + + nbr->nbr_nbma = NULL; + + if (oi->type == OSPF_IFTYPE_NBMA) + { + struct ospf_nbr_nbma *nbr_nbma; + listnode node; + + for (node = listhead (oi->nbr_nbma); node; nextnode (node)) + { + nbr_nbma = getdata (node); + assert (nbr_nbma); + + if (IPV4_ADDR_SAME(&nbr_nbma->addr, &iph->ip_src)) + { + nbr_nbma->nbr = nbr; + nbr->nbr_nbma = nbr_nbma; + + if (nbr_nbma->t_poll) + OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll); + + nbr->state_change = nbr_nbma->state_change + 1; + } + } + } + + /* New nbr, save the crypto sequence number if necessary */ + if (ntohs (ospfh->auth_type) == OSPF_AUTH_CRYPTOGRAPHIC) + nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("NSM[%s:%s]: start", IF_NAME (nbr->oi), + inet_ntoa (nbr->router_id)); + } + + nbr->router_id = ospfh->router_id; + + old_state = nbr->state; + + /* Add event to thread. */ + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_HelloReceived); + + /* RFC2328 Section 9.5.1 + If the router is not eligible to become Designated Router, + (snip) It must also send an Hello Packet in reply to an + Hello Packet received from any eligible neighbor (other than + the current Designated Router and Backup Designated Router). */ + if (oi->type == OSPF_IFTYPE_NBMA) + if (PRIORITY(oi) == 0 && hello->priority > 0 + && IPV4_ADDR_CMP(&DR(oi), &iph->ip_src) + && IPV4_ADDR_CMP(&BDR(oi), &iph->ip_src)) + OSPF_NSM_TIMER_ON (nbr->t_hello_reply, ospf_hello_reply_timer, + OSPF_HELLO_REPLY_DELAY); + + /* on NBMA network type, it happens to receive bidirectional Hello packet + without advance 1-Way Received event. + To avoid incorrect DR-seletion, raise 1-Way Received event.*/ + if (oi->type == OSPF_IFTYPE_NBMA && + (old_state == NSM_Down || old_state == NSM_Attempt)) + { + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_OneWayReceived); + nbr->priority = hello->priority; + nbr->d_router = hello->d_router; + nbr->bd_router = hello->bd_router; + return; + } + + if (ospf_nbr_bidirectional (&oi->ospf->router_id, hello->neighbors, + size - OSPF_HELLO_MIN_SIZE)) + { + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_TwoWayReceived); + nbr->options |= hello->options; + } + else + { + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_OneWayReceived); + /* Set neighbor information. */ + nbr->priority = hello->priority; + nbr->d_router = hello->d_router; + nbr->bd_router = hello->bd_router; + return; + } + + /* If neighbor itself declares DR and no BDR exists, + cause event BackupSeen */ + if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->d_router)) + if (hello->bd_router.s_addr == 0 && oi->state == ISM_Waiting) + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_BackupSeen); + + /* neighbor itself declares BDR. */ + if (oi->state == ISM_Waiting && + IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->bd_router)) + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_BackupSeen); + + /* had not previously. */ + if ((IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->d_router) && + IPV4_ADDR_CMP (&nbr->address.u.prefix4, &nbr->d_router)) || + (IPV4_ADDR_CMP (&nbr->address.u.prefix4, &hello->d_router) && + IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->d_router))) + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); + + /* had not previously. */ + if ((IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->bd_router) && + IPV4_ADDR_CMP (&nbr->address.u.prefix4, &nbr->bd_router)) || + (IPV4_ADDR_CMP (&nbr->address.u.prefix4, &hello->bd_router) && + IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->bd_router))) + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); + + /* Neighbor priority check. */ + if (nbr->priority >= 0 && nbr->priority != hello->priority) + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); + + /* Set neighbor information. */ + nbr->priority = hello->priority; + nbr->d_router = hello->d_router; + nbr->bd_router = hello->bd_router; +} + +/* Save DD flags/options/Seqnum received. */ +void +ospf_db_desc_save_current (struct ospf_neighbor *nbr, + struct ospf_db_desc *dd) +{ + nbr->last_recv.flags = dd->flags; + nbr->last_recv.options = dd->options; + nbr->last_recv.dd_seqnum = ntohl (dd->dd_seqnum); +} + +/* Process rest of DD packet. */ +static void +ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi, + struct ospf_neighbor *nbr, struct ospf_db_desc *dd, + u_int16_t size) +{ + struct ospf_lsa *new, *find; + struct lsa_header *lsah; + + stream_forward (s, OSPF_DB_DESC_MIN_SIZE); + for (size -= OSPF_DB_DESC_MIN_SIZE; + size >= OSPF_LSA_HEADER_SIZE; size -= OSPF_LSA_HEADER_SIZE) + { + lsah = (struct lsa_header *) STREAM_PNT (s); + stream_forward (s, OSPF_LSA_HEADER_SIZE); + + /* Unknown LS type. */ + if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA) + { + zlog_warn ("Pakcet [DD:RECV]: Unknown LS type %d.", lsah->type); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + return; + } + +#ifdef HAVE_OPAQUE_LSA + if (IS_OPAQUE_LSA (lsah->type) + && ! CHECK_FLAG (nbr->options, OSPF_OPTION_O)) + { + zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id)); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + return; + } +#endif /* HAVE_OPAQUE_LSA */ + + switch (lsah->type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ +#ifdef HAVE_NSSA + /* Check for stub area. Reject if AS-External from stub but + allow if from NSSA. */ + if (oi->area->external_routing == OSPF_AREA_STUB) +#else /* ! HAVE_NSSA */ + if (oi->area->external_routing != OSPF_AREA_DEFAULT) +#endif /* HAVE_NSSA */ + { + zlog_warn ("Packet [DD:RECV]: LSA[Type%d:%s] from %s area.", + lsah->type, inet_ntoa (lsah->id), + (oi->area->external_routing == OSPF_AREA_STUB) ?\ + "STUB" : "NSSA"); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + return; + } + break; + default: + break; + } + + /* Create LS-request object. */ + new = ospf_ls_request_new (lsah); + + /* Lookup received LSA, then add LS request list. */ + find = ospf_lsa_lookup_by_header (oi->area, lsah); + if (!find || ospf_lsa_more_recent (find, new) < 0) + { + ospf_ls_request_add (nbr, new); + ospf_lsa_discard (new); + } + else + { + /* Received LSA is not recent. */ + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Packet [DD:RECV]: LSA received Type %d, " + "ID %s is not recent.", lsah->type, inet_ntoa (lsah->id)); + ospf_lsa_discard (new); + continue; + } + } + + /* Master */ + if (IS_SET_DD_MS (nbr->dd_flags)) + { + nbr->dd_seqnum++; + /* Entire DD packet sent. */ + if (!IS_SET_DD_M (dd->flags) && !IS_SET_DD_M (nbr->dd_flags)) + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone); + else + /* Send new DD packet. */ + ospf_db_desc_send (nbr); + } + /* Slave */ + else + { + nbr->dd_seqnum = ntohl (dd->dd_seqnum); + + /* When master's more flags is not set. */ + if (!IS_SET_DD_M (dd->flags) && ospf_db_summary_isempty (nbr)) + { + nbr->dd_flags &= ~(OSPF_DD_FLAG_M); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone); + } + + /* Send DD pakcet in reply. */ + ospf_db_desc_send (nbr); + } + + /* Save received neighbor values from DD. */ + ospf_db_desc_save_current (nbr, dd); +} + +int +ospf_db_desc_is_dup (struct ospf_db_desc *dd, struct ospf_neighbor *nbr) +{ + /* Is DD duplicated? */ + if (dd->options == nbr->last_recv.options && + dd->flags == nbr->last_recv.flags && + dd->dd_seqnum == htonl (nbr->last_recv.dd_seqnum)) + return 1; + + return 0; +} + +/* OSPF Database Description message read -- RFC2328 Section 10.6. */ +void +ospf_db_desc (struct ip *iph, struct ospf_header *ospfh, + struct stream *s, struct ospf_interface *oi, u_int16_t size) +{ + struct ospf_db_desc *dd; + struct ospf_neighbor *nbr; + + /* Increment statistics. */ + oi->db_desc_in++; + + dd = (struct ospf_db_desc *) STREAM_PNT (s); + + nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src); + if (nbr == NULL) + { + zlog_warn ("Packet[DD]: Unknown Neighbor %s", + inet_ntoa (ospfh->router_id)); + return; + } + + /* Check MTU. */ + if (ntohs (dd->mtu) > oi->ifp->mtu) + { + zlog_warn ("Packet[DD]: MTU is larger than [%s]'s MTU", IF_NAME (oi)); + return; + } + +#ifdef REJECT_IF_TBIT_ON + if (CHECK_FLAG (dd->options, OSPF_OPTION_T)) + { + /* + * In Hello protocol, optional capability must have checked + * to prevent this T-bit enabled router be my neighbor. + */ + zlog_warn ("Packet[DD]: Neighbor %s: T-bit on?", inet_ntoa (nbr->router_id)); + return; + } +#endif /* REJECT_IF_TBIT_ON */ + +#ifdef HAVE_OPAQUE_LSA + if (CHECK_FLAG (dd->options, OSPF_OPTION_O) + && !CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) + { + /* + * This node is not configured to handle O-bit, for now. + * Clear it to ignore unsupported capability proposed by neighbor. + */ + UNSET_FLAG (dd->options, OSPF_OPTION_O); + } +#endif /* HAVE_OPAQUE_LSA */ + + /* Process DD packet by neighbor status. */ + switch (nbr->state) + { + case NSM_Down: + case NSM_Attempt: + case NSM_TwoWay: + zlog_warn ("Packet[DD]: Neighbor state is %s, packet discarded.", + LOOKUP (ospf_nsm_state_msg, nbr->state)); + break; + case NSM_Init: + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_TwoWayReceived); + /* If the new state is ExStart, the processing of the current + packet should then continue in this new state by falling + through to case ExStart below. */ + if (nbr->state != NSM_ExStart) + break; + case NSM_ExStart: + /* Initial DBD */ + if ((IS_SET_DD_ALL (dd->flags) == OSPF_DD_FLAG_ALL) && + (size == OSPF_DB_DESC_MIN_SIZE)) + { + if (IPV4_ADDR_CMP (&nbr->router_id, &oi->ospf->router_id) > 0) + { + /* We're Slave---obey */ + zlog_warn ("Packet[DD]: Negotiation done (Slave)."); + nbr->dd_seqnum = ntohl (dd->dd_seqnum); + nbr->dd_flags &= ~(OSPF_DD_FLAG_MS|OSPF_DD_FLAG_I); /* Reset I/MS */ + } + else + { + /* We're Master, ignore the initial DBD from Slave */ + zlog_warn ("Packet[DD]: Initial DBD from Slave, ignoring."); + break; + } + } + /* Ack from the Slave */ + else if (!IS_SET_DD_MS (dd->flags) && !IS_SET_DD_I (dd->flags) && + ntohl (dd->dd_seqnum) == nbr->dd_seqnum && + IPV4_ADDR_CMP (&nbr->router_id, &oi->ospf->router_id) < 0) + { + zlog_warn ("Packet[DD]: Negotiation done (Master)."); + nbr->dd_flags &= ~OSPF_DD_FLAG_I; + } + else + { + zlog_warn ("Packet[DD]: Negotiation fails."); + break; + } + + /* This is where the real Options are saved */ + nbr->options = dd->options; + +#ifdef HAVE_OPAQUE_LSA + if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Neighbor[%s] is %sOpaque-capable.", + inet_ntoa (nbr->router_id), + CHECK_FLAG (nbr->options, OSPF_OPTION_O) ? "" : "NOT "); + + if (! CHECK_FLAG (nbr->options, OSPF_OPTION_O) + && IPV4_ADDR_SAME (&DR (oi), &nbr->address.u.prefix4)) + { + zlog_warn ("DR-neighbor[%s] is NOT opaque-capable; Opaque-LSAs cannot be reliably advertised in this network.", inet_ntoa (nbr->router_id)); + /* This situation is undesirable, but not a real error. */ + } + } +#endif /* HAVE_OPAQUE_LSA */ + + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_NegotiationDone); + + /* continue processing rest of packet. */ + ospf_db_desc_proc (s, oi, nbr, dd, size); + break; + case NSM_Exchange: + if (ospf_db_desc_is_dup (dd, nbr)) + { + if (IS_SET_DD_MS (nbr->dd_flags)) + /* Master: discard duplicated DD packet. */ + zlog_warn ("Packet[DD] (Master): packet duplicated."); + else + /* Slave: cause to retransmit the last Database Description. */ + { + zlog_warn ("Packet[DD] [Slave]: packet duplicated."); + ospf_db_desc_resend (nbr); + } + break; + } + + /* Otherwise DD packet should be checked. */ + /* Check Master/Slave bit mismatch */ + if (IS_SET_DD_MS (dd->flags) != IS_SET_DD_MS (nbr->last_recv.flags)) + { + zlog_warn ("Packet[DD]: MS-bit mismatch."); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Packet[DD]: dd->flags=%d, nbr->dd_flags=%d", + dd->flags, nbr->dd_flags); + break; + } + + /* Check initialize bit is set. */ + if (IS_SET_DD_I (dd->flags)) + { + zlog_warn ("Packet[DD]: I-bit set."); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + break; + } + + /* Check DD Options. */ + if (dd->options != nbr->options) + { + zlog_warn ("Packet[DD]: options mismatch."); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + break; + } + + /* Check DD sequence number. */ + if ((IS_SET_DD_MS (nbr->dd_flags) && + ntohl (dd->dd_seqnum) != nbr->dd_seqnum) || + (!IS_SET_DD_MS (nbr->dd_flags) && + ntohl (dd->dd_seqnum) != nbr->dd_seqnum + 1)) + { + zlog_warn ("Pakcet[DD]: sequence number mismatch."); + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + break; + } + + /* Continue processing rest of packet. */ + ospf_db_desc_proc (s, oi, nbr, dd, size); + break; + case NSM_Loading: + case NSM_Full: + if (ospf_db_desc_is_dup (dd, nbr)) + { + if (IS_SET_DD_MS (nbr->dd_flags)) + { + /* Master should discard duplicate DD packet. */ + zlog_warn ("Pakcet[DD]: duplicated, packet discarded."); + break; + } + else + { + struct timeval t, now; + gettimeofday (&now, NULL); + t = tv_sub (now, nbr->last_send_ts); + if (tv_cmp (t, int2tv (nbr->v_inactivity)) < 0) + { + /* In states Loading and Full the slave must resend + its last Database Description packet in response to + duplicate Database Description packets received + from the master. For this reason the slave must + wait RouterDeadInterval seconds before freeing the + last Database Description packet. Reception of a + Database Description packet from the master after + this interval will generate a SeqNumberMismatch + neighbor event. RFC2328 Section 10.8 */ + ospf_db_desc_resend (nbr); + break; + } + } + } + + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); + break; + default: + zlog_warn ("Packet[DD]: NSM illegal status."); + break; + } +} + +#define OSPF_LSA_KEY_SIZE 12 /* type(4) + id(4) + ar(4) */ + +/* OSPF Link State Request Read -- RFC2328 Section 10.7. */ +void +ospf_ls_req (struct ip *iph, struct ospf_header *ospfh, + struct stream *s, struct ospf_interface *oi, u_int16_t size) +{ + struct ospf_neighbor *nbr; + u_int32_t ls_type; + struct in_addr ls_id; + struct in_addr adv_router; + struct ospf_lsa *find; + list ls_upd; + int length; + + /* Increment statistics. */ + oi->ls_req_in++; + + nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src); + if (nbr == NULL) + { + zlog_warn ("Link State Request: Unknown Neighbor %s.", + inet_ntoa (ospfh->router_id)); + return; + } + + /* Neighbor State should be Exchange or later. */ + if (nbr->state != NSM_Exchange && + nbr->state != NSM_Loading && + nbr->state != NSM_Full) + { + zlog_warn ("Link State Request: Neighbor state is %s, packet discarded.", + LOOKUP (ospf_nsm_state_msg, nbr->state)); + return; + } + + /* Send Link State Update for ALL requested LSAs. */ + ls_upd = list_new (); + length = OSPF_HEADER_SIZE + OSPF_LS_UPD_MIN_SIZE; + + while (size >= OSPF_LSA_KEY_SIZE) + { + /* Get one slice of Link State Request. */ + ls_type = stream_getl (s); + ls_id.s_addr = stream_get_ipv4 (s); + adv_router.s_addr = stream_get_ipv4 (s); + + /* Verify LSA type. */ + if (ls_type < OSPF_MIN_LSA || ls_type >= OSPF_MAX_LSA) + { + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq); + list_delete (ls_upd); + return; + } + + /* Search proper LSA in LSDB. */ + find = ospf_lsa_lookup (oi->area, ls_type, ls_id, adv_router); + if (find == NULL) + { + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq); + list_delete (ls_upd); + return; + } + + /* Packet overflows MTU size, send immediatly. */ + if (length + ntohs (find->data->length) > OSPF_PACKET_MAX (oi)) + { + if (oi->type == OSPF_IFTYPE_NBMA) + ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_DIRECT); + else + ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_INDIRECT); + + /* Only remove list contents. Keep ls_upd. */ + list_delete_all_node (ls_upd); + + length = OSPF_HEADER_SIZE + OSPF_LS_UPD_MIN_SIZE; + } + + /* Append LSA to update list. */ + listnode_add (ls_upd, find); + length += ntohs (find->data->length); + + size -= OSPF_LSA_KEY_SIZE; + } + + /* Send rest of Link State Update. */ + if (listcount (ls_upd) > 0) + { + if (oi->type == OSPF_IFTYPE_NBMA) + ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_DIRECT); + else + ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_INDIRECT); + + list_delete (ls_upd); + } + else + list_free (ls_upd); +} + +/* Get the list of LSAs from Link State Update packet. + And process some validation -- RFC2328 Section 13. (1)-(2). */ +static list +ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, + struct ospf_interface *oi, size_t size) +{ + u_int16_t count, sum; + u_int32_t length; + struct lsa_header *lsah; + struct ospf_lsa *lsa; + list lsas; + + lsas = list_new (); + + count = stream_getl (s); + size -= OSPF_LS_UPD_MIN_SIZE; /* # LSAs */ + + for (; size >= OSPF_LSA_HEADER_SIZE && count > 0; + size -= length, stream_forward (s, length), count--) + { + lsah = (struct lsa_header *) STREAM_PNT (s); + length = ntohs (lsah->length); + + if (length > size) + { + zlog_warn ("Link State Update: LSA length exceeds packet size."); + break; + } + + /* Validate the LSA's LS checksum. */ + sum = lsah->checksum; + if (sum != ospf_lsa_checksum (lsah)) + { + zlog_warn ("Link State Update: LSA checksum error %x, %x.", + sum, lsah->checksum); + continue; + } + + /* Examine the LSA's LS type. */ + if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA) + { + zlog_warn ("Link State Update: Unknown LS type %d", lsah->type); + continue; + } + + /* + * What if the received LSA's age is greater than MaxAge? + * Treat it as a MaxAge case -- endo. + */ + if (ntohs (lsah->ls_age) > OSPF_LSA_MAXAGE) + lsah->ls_age = htons (OSPF_LSA_MAXAGE); + +#ifdef HAVE_OPAQUE_LSA + if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) + { +#ifdef STRICT_OBIT_USAGE_CHECK + if ((IS_OPAQUE_LSA(lsah->type) && + ! CHECK_FLAG (lsah->options, OSPF_OPTION_O)) + || (! IS_OPAQUE_LSA(lsah->type) && + CHECK_FLAG (lsah->options, OSPF_OPTION_O))) + { + /* + * This neighbor must know the exact usage of O-bit; + * the bit will be set in Type-9,10,11 LSAs only. + */ + zlog_warn ("LSA[Type%d:%s]: O-bit abuse?", lsah->type, inet_ntoa (lsah->id)); + continue; + } +#endif /* STRICT_OBIT_USAGE_CHECK */ + + /* Do not take in AS External Opaque-LSAs if we are a stub. */ + if (lsah->type == OSPF_OPAQUE_AS_LSA + && nbr->oi->area->external_routing != OSPF_AREA_DEFAULT) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[Type%d:%s]: We are a stub, don't take this LSA.", lsah->type, inet_ntoa (lsah->id)); + continue; + } + } + else if (IS_OPAQUE_LSA(lsah->type)) + { + zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id)); + continue; + } +#endif /* HAVE_OPAQUE_LSA */ + + /* Create OSPF LSA instance. */ + lsa = ospf_lsa_new (); + + /* We may wish to put some error checking if type NSSA comes in + and area not in NSSA mode */ + switch (lsah->type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: + lsa->area = NULL; + break; + case OSPF_OPAQUE_LINK_LSA: + lsa->oi = oi; /* Remember incoming interface for flooding control. */ + /* Fallthrough */ +#endif /* HAVE_OPAQUE_LSA */ + default: + lsa->area = oi->area; + break; + } + + lsa->data = ospf_lsa_data_new (length); + memcpy (lsa->data, lsah, length); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info("LSA[Type%d:%s]: %p new LSA created with Link State Update", + lsa->data->type, inet_ntoa (lsa->data->id), lsa); + listnode_add (lsas, lsa); + } + + return lsas; +} + +/* Cleanup Update list. */ +void +ospf_upd_list_clean (list lsas) +{ + listnode node; + struct ospf_lsa *lsa; + + for (node = listhead (lsas); node; nextnode (node)) + if ((lsa = getdata (node)) != NULL) + ospf_lsa_discard (lsa); + + list_delete (lsas); +} + +/* OSPF Link State Update message read -- RFC2328 Section 13. */ +void +ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, + struct stream *s, struct ospf_interface *oi, u_int16_t size) +{ + struct ospf_neighbor *nbr; + list lsas; +#ifdef HAVE_OPAQUE_LSA + list mylsa_acks, mylsa_upds; +#endif /* HAVE_OPAQUE_LSA */ + listnode node, next; + struct ospf_lsa *lsa = NULL; + /* unsigned long ls_req_found = 0; */ + + /* Dis-assemble the stream, update each entry, re-encapsulate for flooding */ + + /* Increment statistics. */ + oi->ls_upd_in++; + + /* Check neighbor. */ + nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src); + if (nbr == NULL) + { + zlog_warn ("Link State Update: Unknown Neighbor %s on int: %s", + inet_ntoa (ospfh->router_id), IF_NAME (oi)); + return; + } + + /* Check neighbor state. */ + if (nbr->state < NSM_Exchange) + { + zlog_warn ("Link State Update: Neighbor[%s] state is less than Exchange", + inet_ntoa (ospfh->router_id)); + return; + } + + /* Get list of LSAs from Link State Update packet. - Also perorms Stages + * 1 (validate LSA checksum) and 2 (check for LSA consistent type) + * of section 13. + */ + lsas = ospf_ls_upd_list_lsa (nbr, s, oi, size); + +#ifdef HAVE_OPAQUE_LSA + /* + * Prepare two kinds of lists to clean up unwanted self-originated + * Opaque-LSAs from the routing domain as soon as possible. + */ + mylsa_acks = list_new (); /* Let the sender cease retransmission. */ + mylsa_upds = list_new (); /* Flush target LSAs if necessary. */ + + /* + * If self-originated Opaque-LSAs that have flooded before restart + * are contained in the received LSUpd message, corresponding LSReq + * messages to be sent may have to be modified. + * To eliminate possible race conditions such that flushing and normal + * updating for the same LSA would take place alternately, this trick + * must be done before entering to the loop below. + */ + ospf_opaque_adjust_lsreq (nbr, lsas); +#endif /* HAVE_OPAQUE_LSA */ + +#define DISCARD_LSA(L,N) {\ + if (IS_DEBUG_OSPF_EVENT) \ + zlog_info ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p Type-%d", N, lsa, (int) lsa->data->type); \ + ospf_lsa_discard (L); \ + continue; } + + /* Process each LSA received in the one packet. */ + for (node = listhead (lsas); node; node = next) + { + struct ospf_lsa *ls_ret, *current; + int ret = 1; + + next = node->next; + + lsa = getdata (node); + +#ifdef HAVE_NSSA + if (IS_DEBUG_OSPF_NSSA) + { + char buf1[INET_ADDRSTRLEN]; + char buf2[INET_ADDRSTRLEN]; + char buf3[INET_ADDRSTRLEN]; + + zlog_info("LSA Type-%d from %s, ID: %s, ADV: %s", + lsa->data->type, + inet_ntop (AF_INET, &ospfh->router_id, + buf1, INET_ADDRSTRLEN), + inet_ntop (AF_INET, &lsa->data->id, + buf2, INET_ADDRSTRLEN), + inet_ntop (AF_INET, &lsa->data->adv_router, + buf3, INET_ADDRSTRLEN)); + } +#endif /* HAVE_NSSA */ + + listnode_delete (lsas, lsa); /* We don't need it in list anymore */ + + /* Validate Checksum - Done above by ospf_ls_upd_list_lsa() */ + + /* LSA Type - Done above by ospf_ls_upd_list_lsa() */ + + /* Do not take in AS External LSAs if we are a stub or NSSA. */ + + /* Do not take in AS NSSA if this neighbor and we are not NSSA */ + + /* Do take in Type-7's if we are an NSSA */ + + /* If we are also an ABR, later translate them to a Type-5 packet */ + + /* Later, an NSSA Re-fresh can Re-fresh Type-7's and an ABR will + translate them to a separate Type-5 packet. */ + + if (lsa->data->type == OSPF_AS_EXTERNAL_LSA) + /* Reject from STUB or NSSA */ + if (nbr->oi->area->external_routing != OSPF_AREA_DEFAULT) + { + DISCARD_LSA (lsa, 1); +#ifdef HAVE_NSSA + if (IS_DEBUG_OSPF_NSSA) + zlog_info("Incoming External LSA Discarded: We are NSSA/STUB Area"); +#endif /* HAVE_NSSA */ + } + +#ifdef HAVE_NSSA + if (lsa->data->type == OSPF_AS_NSSA_LSA) + if (nbr->oi->area->external_routing != OSPF_AREA_NSSA) + { + DISCARD_LSA (lsa,2); + if (IS_DEBUG_OSPF_NSSA) + zlog_info("Incoming NSSA LSA Discarded: Not NSSA Area"); + } +#endif /* HAVE_NSSA */ + + /* Find the LSA in the current database. */ + + current = ospf_lsa_lookup_by_header (oi->area, lsa->data); + + /* If the LSA's LS age is equal to MaxAge, and there is currently + no instance of the LSA in the router's link state database, + and none of router's neighbors are in states Exchange or Loading, + then take the following actions. */ + + if (IS_LSA_MAXAGE (lsa) && !current && + (ospf_nbr_count (oi, NSM_Exchange) + + ospf_nbr_count (oi, NSM_Loading)) == 0) + { + /* Response Link State Acknowledgment. */ + ospf_ls_ack_send (nbr, lsa); + + /* Discard LSA. */ + zlog_warn ("Link State Update: LS age is equal to MaxAge."); + DISCARD_LSA (lsa, 3); + } + +#ifdef HAVE_OPAQUE_LSA + if (IS_OPAQUE_LSA (lsa->data->type) + && IPV4_ADDR_SAME (&lsa->data->adv_router, &oi->ospf->router_id)) + { + /* + * Even if initial flushing seems to be completed, there might + * be a case that self-originated LSA with MaxAge still remain + * in the routing domain. + * Just send an LSAck message to cease retransmission. + */ + if (IS_LSA_MAXAGE (lsa)) + { + zlog_warn ("LSA[%s]: Boomerang effect?", dump_lsa_key (lsa)); + ospf_ls_ack_send (nbr, lsa); + ospf_lsa_discard (lsa); + + if (current != NULL && ! IS_LSA_MAXAGE (current)) + ospf_opaque_lsa_refresh_schedule (current); + continue; + } + + /* + * If an instance of self-originated Opaque-LSA is not found + * in the LSDB, there are some possible cases here. + * + * 1) This node lost opaque-capability after restart. + * 2) Else, a part of opaque-type is no more supported. + * 3) Else, a part of opaque-id is no more supported. + * + * Anyway, it is still this node's responsibility to flush it. + * Otherwise, the LSA instance remains in the routing domain + * until its age reaches to MaxAge. + */ + if (current == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("LSA[%s]: Previously originated Opaque-LSA, not found in the LSDB.", dump_lsa_key (lsa)); + + SET_FLAG (lsa->flags, OSPF_LSA_SELF); + listnode_add (mylsa_upds, ospf_lsa_dup (lsa)); + listnode_add (mylsa_acks, ospf_lsa_lock (lsa)); + continue; + } + } +#endif /* HAVE_OPAQUE_LSA */ + + /* (5) Find the instance of this LSA that is currently contained + in the router's link state database. If there is no + database copy, or the received LSA is more recent than + the database copy the following steps must be performed. */ + + if (current == NULL || + (ret = ospf_lsa_more_recent (current, lsa)) < 0) + { + /* Actual flooding procedure. */ + if (ospf_flood (oi->ospf, nbr, current, lsa) < 0) /* Trap NSSA later. */ + DISCARD_LSA (lsa, 4); + continue; + } + + /* (6) Else, If there is an instance of the LSA on the sending + neighbor's Link state request list, an error has occurred in + the Database Exchange process. In this case, restart the + Database Exchange process by generating the neighbor event + BadLSReq for the sending neighbor and stop processing the + Link State Update packet. */ + + if (ospf_ls_request_lookup (nbr, lsa)) + { + OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq); + zlog_warn ("LSA instance exists on Link state request list"); + + /* Clean list of LSAs. */ + ospf_upd_list_clean (lsas); + /* this lsa is not on lsas list already. */ + ospf_lsa_discard (lsa); +#ifdef HAVE_OPAQUE_LSA + list_delete (mylsa_acks); + list_delete (mylsa_upds); +#endif /* HAVE_OPAQUE_LSA */ + return; + } + + /* If the received LSA is the same instance as the database copy + (i.e., neither one is more recent) the following two steps + should be performed: */ + + if (ret == 0) + { + /* If the LSA is listed in the Link state retransmission list + for the receiving adjacency, the router itself is expecting + an acknowledgment for this LSA. The router should treat the + received LSA as an acknowledgment by removing the LSA from + the Link state retransmission list. This is termed an + "implied acknowledgment". */ + + ls_ret = ospf_ls_retransmit_lookup (nbr, lsa); + + if (ls_ret != NULL) + { + ospf_ls_retransmit_delete (nbr, ls_ret); + + /* Delayed acknowledgment sent if advertisement received + from Designated Router, otherwise do nothing. */ + if (oi->state == ISM_Backup) + if (NBR_IS_DR (nbr)) + listnode_add (oi->ls_ack, ospf_lsa_lock (lsa)); + + DISCARD_LSA (lsa, 5); + } + else + /* Acknowledge the receipt of the LSA by sending a + Link State Acknowledgment packet back out the receiving + interface. */ + { + ospf_ls_ack_send (nbr, lsa); + DISCARD_LSA (lsa, 6); + } + } + + /* The database copy is more recent. If the database copy + has LS age equal to MaxAge and LS sequence number equal to + MaxSequenceNumber, simply discard the received LSA without + acknowledging it. (In this case, the LSA's LS sequence number is + wrapping, and the MaxSequenceNumber LSA must be completely + flushed before any new LSA instance can be introduced). */ + + else if (ret > 0) /* Database copy is more recent */ + { + if (IS_LSA_MAXAGE (current) && + current->data->ls_seqnum == htonl (OSPF_MAX_SEQUENCE_NUMBER)) + { + DISCARD_LSA (lsa, 7); + } + /* Otherwise, as long as the database copy has not been sent in a + Link State Update within the last MinLSArrival seconds, send the + database copy back to the sending neighbor, encapsulated within + a Link State Update Packet. The Link State Update Packet should + be sent directly to the neighbor. In so doing, do not put the + database copy of the LSA on the neighbor's link state + retransmission list, and do not acknowledge the received (less + recent) LSA instance. */ + else + { + struct timeval now; + + gettimeofday (&now, NULL); + + if (tv_cmp (tv_sub (now, current->tv_orig), + int2tv (OSPF_MIN_LS_ARRIVAL)) > 0) + /* Trap NSSA type later.*/ + ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT); + DISCARD_LSA (lsa, 8); + } + } + } + +#ifdef HAVE_OPAQUE_LSA + /* + * Now that previously originated Opaque-LSAs those which not yet + * installed into LSDB are captured, take several steps to clear + * them completely from the routing domain, before proceeding to + * origination for the current target Opaque-LSAs. + */ + while (listcount (mylsa_acks) > 0) + ospf_ls_ack_send_list (oi, mylsa_acks, nbr->address.u.prefix4); + + if (listcount (mylsa_upds) > 0) + ospf_opaque_self_originated_lsa_received (nbr, mylsa_upds); + + list_delete (mylsa_acks); + list_delete (mylsa_upds); +#endif /* HAVE_OPAQUE_LSA */ + + assert (listcount (lsas) == 0); + list_delete (lsas); +} + +/* OSPF Link State Acknowledgment message read -- RFC2328 Section 13.7. */ +void +ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh, + struct stream *s, struct ospf_interface *oi, u_int16_t size) +{ + struct ospf_neighbor *nbr; +#ifdef HAVE_OPAQUE_LSA + list opaque_acks; +#endif /* HAVE_OPAQUE_LSA */ + + /* increment statistics. */ + oi->ls_ack_in++; + + nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src); + if (nbr == NULL) + { + zlog_warn ("Link State Acknowledgment: Unknown Neighbor %s.", + inet_ntoa (ospfh->router_id)); + return; + } + + if (nbr->state < NSM_Exchange) + { + zlog_warn ("Link State Acknowledgment: State is less than Exchange."); + return; + } + +#ifdef HAVE_OPAQUE_LSA + opaque_acks = list_new (); +#endif /* HAVE_OPAQUE_LSA */ + + while (size >= OSPF_LSA_HEADER_SIZE) + { + struct ospf_lsa *lsa, *lsr; + + lsa = ospf_lsa_new (); + lsa->data = (struct lsa_header *) STREAM_PNT (s); + + /* lsah = (struct lsa_header *) STREAM_PNT (s); */ + size -= OSPF_LSA_HEADER_SIZE; + stream_forward (s, OSPF_LSA_HEADER_SIZE); + + if (lsa->data->type < OSPF_MIN_LSA || lsa->data->type >= OSPF_MAX_LSA) + { + lsa->data = NULL; + ospf_lsa_discard (lsa); + continue; + } + + lsr = ospf_ls_retransmit_lookup (nbr, lsa); + + if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum) + { +#ifdef HAVE_OPAQUE_LSA + /* Keep this LSA entry for later reference. */ + if (IS_OPAQUE_LSA (lsr->data->type)) + listnode_add (opaque_acks, ospf_lsa_dup (lsr)); +#endif /* HAVE_OPAQUE_LSA */ + + ospf_ls_retransmit_delete (nbr, lsr); + } + + lsa->data = NULL; + ospf_lsa_discard (lsa); + } + +#ifdef HAVE_OPAQUE_LSA + if (listcount (opaque_acks) > 0) + ospf_opaque_ls_ack_received (nbr, opaque_acks); + + list_delete (opaque_acks); + return; +#endif /* HAVE_OPAQUE_LSA */ +} + +struct stream * +ospf_recv_packet (int fd, struct interface **ifp) +{ + int ret; + struct ip iph; + u_int16_t ip_len; + struct stream *ibuf; + unsigned int ifindex = 0; + struct iovec iov; + struct cmsghdr *cmsg; +#if defined (IP_PKTINFO) + struct in_pktinfo *pktinfo; +#elif defined (IP_RECVIF) + struct sockaddr_dl *pktinfo; +#else + char *pktinfo; /* dummy */ +#endif + char buff [sizeof (*cmsg) + sizeof (*pktinfo)]; + struct msghdr msgh = {NULL, 0, &iov, 1, buff, + sizeof (*cmsg) + sizeof (*pktinfo), 0}; + + ret = recvfrom (fd, (void *)&iph, sizeof (iph), MSG_PEEK, NULL, 0); + + if (ret != sizeof (iph)) + { + zlog_warn ("ospf_recv_packet packet smaller than ip header"); + return NULL; + } + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(OpenBSD_IP_LEN) + ip_len = iph.ip_len; +#else + ip_len = ntohs (iph.ip_len); +#endif + +#if !defined(GNU_LINUX) && !defined(OpenBSD_IP_LEN) + /* + * Kernel network code touches incoming IP header parameters, + * before protocol specific processing. + * + * 1) Convert byteorder to host representation. + * --> ip_len, ip_id, ip_off + * + * 2) Adjust ip_len to strip IP header size! + * --> If user process receives entire IP packet via RAW + * socket, it must consider adding IP header size to + * the "ip_len" field of "ip" structure. + * + * For more details, see . + */ + ip_len = ip_len + (iph.ip_hl << 2); +#endif + + ibuf = stream_new (ip_len); + iov.iov_base = STREAM_DATA (ibuf); + iov.iov_len = ip_len; + ret = recvmsg (fd, &msgh, 0); + + cmsg = CMSG_FIRSTHDR (&msgh); + + if (cmsg != NULL && //cmsg->cmsg_len == sizeof (*pktinfo) && + cmsg->cmsg_level == IPPROTO_IP && +#if defined (IP_PKTINFO) + cmsg->cmsg_type == IP_PKTINFO +#elif defined (IP_RECVIF) + cmsg->cmsg_type == IP_RECVIF +#else + 0 +#endif + ) + { +#if defined (IP_PKTINFO) + pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); + ifindex = pktinfo->ipi_ifindex; +#elif defined (IP_RECVIF) + pktinfo = (struct sockaddr_dl *)CMSG_DATA(cmsg); + ifindex = pktinfo->sdl_index; +#else + ifindex = 0; +#endif + } + + *ifp = if_lookup_by_index (ifindex); + + if (ret != ip_len) + { + zlog_warn ("ospf_recv_packet short read. " + "ip_len %d bytes read %d", ip_len, ret); + stream_free (ibuf); + return NULL; + } + + return ibuf; +} + +struct ospf_interface * +ospf_associate_packet_vl (struct ospf *ospf, + struct interface *ifp, struct ospf_interface *oi, + struct ip *iph, struct ospf_header *ospfh) +{ + struct ospf_interface *rcv_oi; + struct ospf_vl_data *vl_data; + struct ospf_area *vl_area; + listnode node; + + if (IN_MULTICAST (ntohl (iph->ip_dst.s_addr)) || + !OSPF_IS_AREA_BACKBONE (ospfh)) + return oi; + + if ((rcv_oi = oi) == NULL) + { + if ((rcv_oi = ospf_if_lookup_by_local_addr (ospf, ifp, + iph->ip_dst)) == NULL) + return NULL; + } + + for (node = listhead (ospf->vlinks); node; nextnode (node)) + { + if ((vl_data = getdata (node)) == NULL) + continue; + + vl_area = ospf_area_lookup_by_area_id (ospf, vl_data->vl_area_id); + if (!vl_area) + continue; + + if (OSPF_AREA_SAME (&vl_area, &rcv_oi->area) && + IPV4_ADDR_SAME (&vl_data->vl_peer, &ospfh->router_id)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("associating packet with %s", + IF_NAME (vl_data->vl_oi)); + if (! CHECK_FLAG (vl_data->vl_oi->ifp->flags, IFF_UP)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("This VL is not up yet, sorry"); + return NULL; + } + + return vl_data->vl_oi; + } + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("couldn't find any VL to associate the packet with"); + + return oi; +} + +int +ospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh) +{ + /* Check match the Area ID of the receiving interface. */ + if (OSPF_AREA_SAME (&oi->area, &ospfh)) + return 1; + + return 0; +} + +/* Unbound socket will accept any Raw IP packets if proto is matched. + To prevent it, compare src IP address and i/f address with masking + i/f network mask. */ +int +ospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src) +{ + struct in_addr mask, me, him; + + if (oi->type == OSPF_IFTYPE_POINTOPOINT || + oi->type == OSPF_IFTYPE_VIRTUALLINK) + return 1; + + masklen2ip (oi->address->prefixlen, &mask); + + me.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; + him.s_addr = ip_src.s_addr & mask.s_addr; + + if (IPV4_ADDR_SAME (&me, &him)) + return 1; + + return 0; +} + +int +ospf_check_auth (struct ospf_interface *oi, struct stream *ibuf, + struct ospf_header *ospfh) +{ + int ret = 0; + struct crypt_key *ck; + list list; + listnode node; + + switch (ntohs (ospfh->auth_type)) + { + case OSPF_AUTH_NULL: + ret = 1; + break; + case OSPF_AUTH_SIMPLE: + if (!memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE)) + ret = 1; + else + ret = 0; + break; + case OSPF_AUTH_CRYPTOGRAPHIC: + ret = 0; + list = OSPF_IF_PARAM (oi, auth_crypt); + for (node = listhead (list); node; nextnode (node)) + { + ck = getdata (node); + if (ck == NULL) + continue; + + /* This is very basic, the digest processing is elsewhere */ + if (ospfh->u.crypt.auth_data_len == OSPF_AUTH_MD5_SIZE && + ospfh->u.crypt.key_id == ck->key_id && + ntohs (ospfh->length) + OSPF_AUTH_SIMPLE_SIZE <= + stream_get_size (ibuf)) + { + ret = 1; + break; + } + } + break; + default: + ret = 0; + break; + } + + return ret; +} + +int +ospf_check_sum (struct ospf_header *ospfh) +{ + u_int32_t ret; + u_int16_t sum; + + /* clear auth_data for checksum. */ + memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE); + + /* keep checksum and clear. */ + sum = ospfh->checksum; + memset (&ospfh->checksum, 0, sizeof (u_int16_t)); + + /* calculate checksum. */ + ret = in_cksum (ospfh, ntohs (ospfh->length)); + + if (ret != sum) + { + zlog_info ("ospf_check_sum(): checksum mismatch, my %X, his %X", + ret, sum); + return 0; + } + + return 1; +} + +/* OSPF Header verification. */ +int +ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi, + struct ip *iph, struct ospf_header *ospfh) +{ + /* check version. */ + if (ospfh->version != OSPF_VERSION) + { + zlog_warn ("interface %s: ospf_read version number mismatch.", + IF_NAME (oi)); + return -1; + } + + /* Check Area ID. */ + if (!ospf_check_area_id (oi, ospfh)) + { + zlog_warn ("interface %s: ospf_read invalid Area ID %s.", + IF_NAME (oi), inet_ntoa (ospfh->area_id)); + return -1; + } + + /* Check network mask, Silently discarded. */ + if (! ospf_check_network_mask (oi, iph->ip_src)) + { + zlog_warn ("interface %s: ospf_read network address is not same [%s]", + IF_NAME (oi), inet_ntoa (iph->ip_src)); + return -1; + } + + /* Check authentication. */ + if (ospf_auth_type (oi) != ntohs (ospfh->auth_type)) + { + zlog_warn ("interface %s: ospf_read authentication type mismatch.", + IF_NAME (oi)); + return -1; + } + + if (! ospf_check_auth (oi, ibuf, ospfh)) + { + zlog_warn ("interface %s: ospf_read authentication failed.", + IF_NAME (oi)); + return -1; + } + + /* if check sum is invalid, packet is discarded. */ + if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) + { + if (! ospf_check_sum (ospfh)) + { + zlog_warn ("interface %s: ospf_read packet checksum error %s", + IF_NAME (oi), inet_ntoa (ospfh->router_id)); + return -1; + } + } + else + { + if (ospfh->checksum != 0) + return -1; + if (ospf_check_md5_digest (oi, ibuf, ntohs (ospfh->length)) == 0) + { + zlog_warn ("interface %s: ospf_read md5 authentication failed.", + IF_NAME (oi)); + return -1; + } + } + + return 0; +} + +/* Starting point of packet process function. */ +int +ospf_read (struct thread *thread) +{ + int ret; + struct stream *ibuf; + struct ospf *ospf; + struct ospf_interface *oi; + struct ip *iph; + struct ospf_header *ospfh; + u_int16_t length; + struct interface *ifp; + + /* first of all get interface pointer. */ + ospf = THREAD_ARG (thread); + ospf->t_read = NULL; + + /* prepare for next packet. */ + ospf->t_read = thread_add_read (master, ospf_read, ospf, ospf->fd); + + /* read OSPF packet. */ + ibuf = ospf_recv_packet (ospf->fd, &ifp); + if (ibuf == NULL) + return -1; + + iph = (struct ip *) STREAM_DATA (ibuf); + + /* Self-originated packet should be discarded silently. */ + if (ospf_if_lookup_by_local_addr (ospf, NULL, iph->ip_src)) + { + stream_free (ibuf); + return 0; + } + + /* Adjust size to message length. */ + stream_forward (ibuf, iph->ip_hl * 4); + + /* Get ospf packet header. */ + ospfh = (struct ospf_header *) STREAM_PNT (ibuf); + + /* associate packet with ospf interface */ + oi = ospf_if_lookup_recv_if (ospf, iph->ip_src); + if (ifp && oi && oi->ifp != ifp) + { + zlog_warn ("Packet from [%s] received on wrong link %s", + inet_ntoa (iph->ip_src), ifp->name); + stream_free (ibuf); + return 0; + } + + if ((oi = ospf_associate_packet_vl (ospf, ifp, oi, iph, ospfh)) == NULL) + { + stream_free (ibuf); + return 0; + } + + /* + * If the received packet is destined for AllDRouters, the packet + * should be accepted only if the received ospf interface state is + * either DR or Backup -- endo. + */ + if (iph->ip_dst.s_addr == htonl (OSPF_ALLDROUTERS) + && (oi->state != ISM_DR && oi->state != ISM_Backup)) + { + zlog_info ("Packet for AllDRouters from [%s] via [%s] (ISM: %s)", + inet_ntoa (iph->ip_src), IF_NAME (oi), + LOOKUP (ospf_ism_state_msg, oi->state)); + stream_free (ibuf); + return 0; + } + + /* Show debug receiving packet. */ + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) + { + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL)) + { + zlog_info ("-----------------------------------------------------"); + ospf_packet_dump (ibuf); + } + + zlog_info ("%s received from [%s] via [%s]", + ospf_packet_type_str[ospfh->type], + inet_ntoa (ospfh->router_id), IF_NAME (oi)); + zlog_info (" src [%s],", inet_ntoa (iph->ip_src)); + zlog_info (" dst [%s]", inet_ntoa (iph->ip_dst)); + + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL)) + zlog_info ("-----------------------------------------------------"); + } + + /* Some header verification. */ + ret = ospf_verify_header (ibuf, oi, iph, ospfh); + if (ret < 0) + { + stream_free (ibuf); + return ret; + } + + stream_forward (ibuf, OSPF_HEADER_SIZE); + + /* Adjust size to message length. */ + length = ntohs (ospfh->length) - OSPF_HEADER_SIZE; + + /* Read rest of the packet and call each sort of packet routine. */ + switch (ospfh->type) + { + case OSPF_MSG_HELLO: + ospf_hello (iph, ospfh, ibuf, oi, length); + break; + case OSPF_MSG_DB_DESC: + ospf_db_desc (iph, ospfh, ibuf, oi, length); + break; + case OSPF_MSG_LS_REQ: + ospf_ls_req (iph, ospfh, ibuf, oi, length); + break; + case OSPF_MSG_LS_UPD: + ospf_ls_upd (iph, ospfh, ibuf, oi, length); + break; + case OSPF_MSG_LS_ACK: + ospf_ls_ack (iph, ospfh, ibuf, oi, length); + break; + default: + zlog (NULL, LOG_WARNING, + "interface %s: OSPF packet header type %d is illegal", + IF_NAME (oi), ospfh->type); + break; + } + + stream_free (ibuf); + return 0; +} + +/* Make OSPF header. */ +void +ospf_make_header (int type, struct ospf_interface *oi, struct stream *s) +{ + struct ospf_header *ospfh; + + ospfh = (struct ospf_header *) STREAM_DATA (s); + + ospfh->version = (u_char) OSPF_VERSION; + ospfh->type = (u_char) type; + + ospfh->router_id = oi->ospf->router_id; + + ospfh->checksum = 0; + ospfh->area_id = oi->area->area_id; + ospfh->auth_type = htons (ospf_auth_type (oi)); + + memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE); + + ospf_output_forward (s, OSPF_HEADER_SIZE); +} + +/* Make Authentication Data. */ +int +ospf_make_auth (struct ospf_interface *oi, struct ospf_header *ospfh) +{ + struct crypt_key *ck; + + switch (ospf_auth_type (oi)) + { + case OSPF_AUTH_NULL: + break; + case OSPF_AUTH_SIMPLE: + memcpy (ospfh->u.auth_data, OSPF_IF_PARAM (oi, auth_simple), + OSPF_AUTH_SIMPLE_SIZE); + break; + case OSPF_AUTH_CRYPTOGRAPHIC: + /* If key is not set, then set 0. */ + if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt))) + { + ospfh->u.crypt.zero = 0; + ospfh->u.crypt.key_id = 0; + ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE; + } + else + { + ck = getdata (OSPF_IF_PARAM (oi, auth_crypt)->tail); + ospfh->u.crypt.zero = 0; + ospfh->u.crypt.key_id = ck->key_id; + ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE; + } + /* note: the seq is done in ospf_make_md5_digest() */ + break; + default: + break; + } + + return 0; +} + +/* Fill rest of OSPF header. */ +void +ospf_fill_header (struct ospf_interface *oi, + struct stream *s, u_int16_t length) +{ + struct ospf_header *ospfh; + + ospfh = (struct ospf_header *) STREAM_DATA (s); + + /* Fill length. */ + ospfh->length = htons (length); + + /* Calculate checksum. */ + if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) + ospfh->checksum = in_cksum (ospfh, length); + else + ospfh->checksum = 0; + + /* Add Authentication Data. */ + ospf_make_auth (oi, ospfh); +} + +int +ospf_make_hello (struct ospf_interface *oi, struct stream *s) +{ + struct ospf_neighbor *nbr; + struct route_node *rn; + u_int16_t length = OSPF_HELLO_MIN_SIZE; + struct in_addr mask; + unsigned long p; + int flag = 0; + + /* Set netmask of interface. */ + if (oi->type != OSPF_IFTYPE_POINTOPOINT && + oi->type != OSPF_IFTYPE_VIRTUALLINK) + masklen2ip (oi->address->prefixlen, &mask); + else + memset ((char *) &mask, 0, sizeof (struct in_addr)); + stream_put_ipv4 (s, mask.s_addr); + + /* Set Hello Interval. */ + stream_putw (s, OSPF_IF_PARAM (oi, v_hello)); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("make_hello: options: %x, int: %s", + OPTIONS(oi), IF_NAME (oi)); + + /* Set Options. */ + stream_putc (s, OPTIONS (oi)); + + /* Set Router Priority. */ + stream_putc (s, PRIORITY (oi)); + + /* Set Router Dead Interval. */ + stream_putl (s, OSPF_IF_PARAM (oi, v_wait)); + + /* Set Designated Router. */ + stream_put_ipv4 (s, DR (oi).s_addr); + + p = s->putp; + + /* Set Backup Designated Router. */ + stream_put_ipv4 (s, BDR (oi).s_addr); + + /* Add neighbor seen. */ + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + if (nbr->router_id.s_addr != 0) /* Ignore 0.0.0.0 node. */ + if (nbr->state != NSM_Attempt) /* Ignore Down neighbor. */ + if (nbr->state != NSM_Down) /* This is myself for DR election. */ + if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id)) + { + /* Check neighbor is sane? */ + if (nbr->d_router.s_addr != 0 + && IPV4_ADDR_SAME (&nbr->d_router, &oi->address->u.prefix4) + && IPV4_ADDR_SAME (&nbr->bd_router, &oi->address->u.prefix4)) + flag = 1; + + stream_put_ipv4 (s, nbr->router_id.s_addr); + length += 4; + } + + /* Let neighbor generate BackupSeen. */ + if (flag == 1) + { + stream_set_putp (s, p); + stream_put_ipv4 (s, 0); + } + + return length; +} + +int +ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr, + struct stream *s) +{ + struct ospf_lsa *lsa; + u_int16_t length = OSPF_DB_DESC_MIN_SIZE; + u_char options; + unsigned long pp; + int i; + struct ospf_lsdb *lsdb; + + /* Set Interface MTU. */ + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + stream_putw (s, 0); + else + stream_putw (s, oi->ifp->mtu); + + /* Set Options. */ + options = OPTIONS (oi); +#ifdef HAVE_OPAQUE_LSA + if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) + { + if (IS_SET_DD_I (nbr->dd_flags) + || CHECK_FLAG (nbr->options, OSPF_OPTION_O)) + /* + * Set O-bit in the outgoing DD packet for capablity negotiation, + * if one of following case is applicable. + * + * 1) WaitTimer expiration event triggered the neighbor state to + * change to Exstart, but no (valid) DD packet has received + * from the neighbor yet. + * + * 2) At least one DD packet with O-bit on has received from the + * neighbor. + */ + SET_FLAG (options, OSPF_OPTION_O); + } +#endif /* HAVE_OPAQUE_LSA */ + stream_putc (s, options); + + /* Keep pointer to flags. */ + pp = stream_get_putp (s); + stream_putc (s, nbr->dd_flags); + + /* Set DD Sequence Number. */ + stream_putl (s, nbr->dd_seqnum); + + if (ospf_db_summary_isempty (nbr)) + { + if (nbr->state >= NSM_Exchange) + { + nbr->dd_flags &= ~OSPF_DD_FLAG_M; + /* Set DD flags again */ + stream_set_putp (s, pp); + stream_putc (s, nbr->dd_flags); + } + return length; + } + + /* Describe LSA Header from Database Summary List. */ + lsdb = &nbr->db_sum; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + { + struct route_table *table = lsdb->type[i].db; + struct route_node *rn; + + for (rn = route_top (table); rn; rn = route_next (rn)) + if ((lsa = rn->info) != NULL) + { +#ifdef HAVE_OPAQUE_LSA + if (IS_OPAQUE_LSA (lsa->data->type) + && (! CHECK_FLAG (options, OSPF_OPTION_O))) + { + /* Suppress advertising opaque-informations. */ + /* Remove LSA from DB summary list. */ + ospf_lsdb_delete (lsdb, lsa); + continue; + } +#endif /* HAVE_OPAQUE_LSA */ + + if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)) + { + struct lsa_header *lsah; + u_int16_t ls_age; + + /* DD packet overflows interface MTU. */ + if (length + OSPF_LSA_HEADER_SIZE > OSPF_PACKET_MAX (oi)) + break; + + /* Keep pointer to LS age. */ + lsah = (struct lsa_header *) (STREAM_DATA (s) + + stream_get_putp (s)); + + /* Proceed stream pointer. */ + stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE); + length += OSPF_LSA_HEADER_SIZE; + + /* Set LS age. */ + ls_age = LS_AGE (lsa); + lsah->ls_age = htons (ls_age); + + } + + /* Remove LSA from DB summary list. */ + ospf_lsdb_delete (lsdb, lsa); + } + } + + return length; +} + +int +ospf_make_ls_req_func (struct stream *s, u_int16_t *length, + unsigned long delta, struct ospf_neighbor *nbr, + struct ospf_lsa *lsa) +{ + struct ospf_interface *oi; + + oi = nbr->oi; + + /* LS Request packet overflows interface MTU. */ + if (*length + delta > OSPF_PACKET_MAX(oi)) + return 0; + + stream_putl (s, lsa->data->type); + stream_put_ipv4 (s, lsa->data->id.s_addr); + stream_put_ipv4 (s, lsa->data->adv_router.s_addr); + + ospf_lsa_unlock (nbr->ls_req_last); + nbr->ls_req_last = ospf_lsa_lock (lsa); + + *length += 12; + return 1; +} + +int +ospf_make_ls_req (struct ospf_neighbor *nbr, struct stream *s) +{ + struct ospf_lsa *lsa; + u_int16_t length = OSPF_LS_REQ_MIN_SIZE; + unsigned long delta = stream_get_putp(s)+12; + struct route_table *table; + struct route_node *rn; + int i; + struct ospf_lsdb *lsdb; + + lsdb = &nbr->ls_req; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + { + table = lsdb->type[i].db; + for (rn = route_top (table); rn; rn = route_next (rn)) + if ((lsa = (rn->info)) != NULL) + if (ospf_make_ls_req_func (s, &length, delta, nbr, lsa) == 0) + { + route_unlock_node (rn); + break; + } + } + return length; +} + +int +ls_age_increment (struct ospf_lsa *lsa, int delay) +{ + int age; + + age = IS_LSA_MAXAGE (lsa) ? OSPF_LSA_MAXAGE : LS_AGE (lsa) + delay; + + return (age > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : age); +} + +int +ospf_make_ls_upd (struct ospf_interface *oi, list update, struct stream *s) +{ + struct ospf_lsa *lsa; + listnode node; + u_int16_t length = OSPF_LS_UPD_MIN_SIZE; + unsigned long delta = stream_get_putp (s); + unsigned long pp; + int count = 0; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_make_ls_upd: Start"); + + pp = stream_get_putp (s); + ospf_output_forward (s, 4); + + while ((node = listhead (update)) != NULL) + { + struct lsa_header *lsah; + u_int16_t ls_age; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_make_ls_upd: List Iteration"); + + lsa = getdata (node); + assert (lsa); + assert (lsa->data); + + /* Check packet size. */ + if (length + delta + ntohs (lsa->data->length) > OSPF_PACKET_MAX (oi)) + break; + + /* Keep pointer to LS age. */ + lsah = (struct lsa_header *) (STREAM_DATA (s) + stream_get_putp (s)); + + /* Put LSA to Link State Request. */ + stream_put (s, lsa->data, ntohs (lsa->data->length)); + + /* Set LS age. */ + /* each hop must increment an lsa_age by transmit_delay + of OSPF interface */ + ls_age = ls_age_increment (lsa, OSPF_IF_PARAM (oi, transmit_delay)); + lsah->ls_age = htons (ls_age); + + length += ntohs (lsa->data->length); + count++; + + list_delete_node (update, node); + ospf_lsa_unlock (lsa); + } + + /* Now set #LSAs. */ + stream_set_putp (s, pp); + stream_putl (s, count); + + stream_set_putp (s, s->endp); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_make_ls_upd: Stop"); + return length; +} + +int +ospf_make_ls_ack (struct ospf_interface *oi, list ack, struct stream *s) +{ + list rm_list; + listnode node; + u_int16_t length = OSPF_LS_ACK_MIN_SIZE; + unsigned long delta = stream_get_putp(s) + 24; + struct ospf_lsa *lsa; + + rm_list = list_new (); + + for (node = listhead (ack); node; nextnode (node)) + { + lsa = getdata (node); + assert (lsa); + + if (length + delta > OSPF_PACKET_MAX (oi)) + break; + + stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE); + length += OSPF_LSA_HEADER_SIZE; + + listnode_add (rm_list, lsa); + } + + /* Remove LSA from LS-Ack list. */ + for (node = listhead (rm_list); node; nextnode (node)) + { + lsa = (struct ospf_lsa *) getdata (node); + + listnode_delete (ack, lsa); + ospf_lsa_unlock (lsa); + } + + list_delete (rm_list); + + return length; +} + +void +ospf_hello_send_sub (struct ospf_interface *oi, struct in_addr *addr) +{ + struct ospf_packet *op; + u_int16_t length = OSPF_HEADER_SIZE; + + op = ospf_packet_new (oi->ifp->mtu); + + /* Prepare OSPF common header. */ + ospf_make_header (OSPF_MSG_HELLO, oi, op->s); + + /* Prepare OSPF Hello body. */ + length += ospf_make_hello (oi, op->s); + + /* Fill OSPF header. */ + ospf_fill_header (oi, op->s, length); + + /* Set packet length. */ + op->length = length; + + op->dst.s_addr = addr->s_addr; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (oi->ospf); +} + +void +ospf_poll_send (struct ospf_nbr_nbma *nbr_nbma) +{ + struct ospf_interface *oi; + + oi = nbr_nbma->oi; + assert(oi); + + /* If this is passive interface, do not send OSPF Hello. */ + if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE) + return; + + if (oi->type != OSPF_IFTYPE_NBMA) + return; + + if (nbr_nbma->nbr != NULL && nbr_nbma->nbr->state != NSM_Down) + return; + + if (PRIORITY(oi) == 0) + return; + + if (nbr_nbma->priority == 0 + && oi->state != ISM_DR && oi->state != ISM_Backup) + return; + + ospf_hello_send_sub (oi, &nbr_nbma->addr); +} + +int +ospf_poll_timer (struct thread *thread) +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = THREAD_ARG (thread); + nbr_nbma->t_poll = NULL; + + if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) + zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (Poll timer expire)", + IF_NAME (nbr_nbma->oi), inet_ntoa (nbr_nbma->addr)); + + ospf_poll_send (nbr_nbma); + + if (nbr_nbma->v_poll > 0) + OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer, + nbr_nbma->v_poll); + + return 0; +} + + +int +ospf_hello_reply_timer (struct thread *thread) +{ + struct ospf_neighbor *nbr; + + nbr = THREAD_ARG (thread); + nbr->t_hello_reply = NULL; + + assert (nbr->oi); + + if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) + zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (hello-reply timer expire)", + IF_NAME (nbr->oi), inet_ntoa (nbr->router_id)); + + ospf_hello_send_sub (nbr->oi, &nbr->address.u.prefix4); + + return 0; +} + +/* Send OSPF Hello. */ +void +ospf_hello_send (struct ospf_interface *oi) +{ + struct ospf_packet *op; + u_int16_t length = OSPF_HEADER_SIZE; + + /* If this is passive interface, do not send OSPF Hello. */ + if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE) + return; + + op = ospf_packet_new (oi->ifp->mtu); + + /* Prepare OSPF common header. */ + ospf_make_header (OSPF_MSG_HELLO, oi, op->s); + + /* Prepare OSPF Hello body. */ + length += ospf_make_hello (oi, op->s); + + /* Fill OSPF header. */ + ospf_fill_header (oi, op->s, length); + + /* Set packet length. */ + op->length = length; + + if (oi->type == OSPF_IFTYPE_NBMA) + { + struct ospf_neighbor *nbr; + struct route_node *rn; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + if (nbr != oi->nbr_self) + if (nbr->state != NSM_Down) + { + /* RFC 2328 Section 9.5.1 + If the router is not eligible to become Designated Router, + it must periodically send Hello Packets to both the + Designated Router and the Backup Designated Router (if they + exist). */ + if (PRIORITY(oi) == 0 && + IPV4_ADDR_CMP(&DR(oi), &nbr->address.u.prefix4) && + IPV4_ADDR_CMP(&BDR(oi), &nbr->address.u.prefix4)) + continue; + + /* If the router is eligible to become Designated Router, it + must periodically send Hello Packets to all neighbors that + are also eligible. In addition, if the router is itself the + Designated Router or Backup Designated Router, it must also + send periodic Hello Packets to all other neighbors. */ + + if (nbr->priority == 0 && oi->state == ISM_DROther) + continue; + /* if oi->state == Waiting, send hello to all neighbors */ + { + struct ospf_packet *op_dup; + + op_dup = ospf_packet_dup(op); + op_dup->dst = nbr->address.u.prefix4; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op_dup); + + OSPF_ISM_WRITE_ON (oi->ospf); + } + + } + ospf_packet_free (op); + } + else + { + /* Decide destination address. */ + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + op->dst.s_addr = oi->vl_data->peer_addr.s_addr; + else + op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS); + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (oi->ospf); + } +} + +/* Send OSPF Database Description. */ +void +ospf_db_desc_send (struct ospf_neighbor *nbr) +{ + struct ospf_interface *oi; + struct ospf_packet *op; + u_int16_t length = OSPF_HEADER_SIZE; + + oi = nbr->oi; + op = ospf_packet_new (oi->ifp->mtu); + + /* Prepare OSPF common header. */ + ospf_make_header (OSPF_MSG_DB_DESC, oi, op->s); + + /* Prepare OSPF Database Description body. */ + length += ospf_make_db_desc (oi, nbr, op->s); + + /* Fill OSPF header. */ + ospf_fill_header (oi, op->s, length); + + /* Set packet length. */ + op->length = length; + + /* Decide destination address. */ + op->dst = nbr->address.u.prefix4; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (oi->ospf); + + /* Remove old DD packet, then copy new one and keep in neighbor structure. */ + if (nbr->last_send) + ospf_packet_free (nbr->last_send); + nbr->last_send = ospf_packet_dup (op); + gettimeofday (&nbr->last_send_ts, NULL); +} + +/* Re-send Database Description. */ +void +ospf_db_desc_resend (struct ospf_neighbor *nbr) +{ + struct ospf_interface *oi; + + oi = nbr->oi; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, ospf_packet_dup (nbr->last_send)); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (oi->ospf); +} + +/* Send Link State Request. */ +void +ospf_ls_req_send (struct ospf_neighbor *nbr) +{ + struct ospf_interface *oi; + struct ospf_packet *op; + u_int16_t length = OSPF_HEADER_SIZE; + + oi = nbr->oi; + op = ospf_packet_new (oi->ifp->mtu); + + /* Prepare OSPF common header. */ + ospf_make_header (OSPF_MSG_LS_REQ, oi, op->s); + + /* Prepare OSPF Link State Request body. */ + length += ospf_make_ls_req (nbr, op->s); + if (length == OSPF_HEADER_SIZE) + { + ospf_packet_free (op); + return; + } + + /* Fill OSPF header. */ + ospf_fill_header (oi, op->s, length); + + /* Set packet length. */ + op->length = length; + + /* Decide destination address. */ + op->dst = nbr->address.u.prefix4; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (oi->ospf); + + /* Add Link State Request Retransmission Timer. */ + OSPF_NSM_TIMER_ON (nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req); +} + +/* Send Link State Update with an LSA. */ +void +ospf_ls_upd_send_lsa (struct ospf_neighbor *nbr, struct ospf_lsa *lsa, + int flag) +{ + list update; + + update = list_new (); + + listnode_add (update, lsa); + ospf_ls_upd_send (nbr, update, flag); + + list_delete (update); +} + +static void +ospf_ls_upd_queue_send (struct ospf_interface *oi, list update, + struct in_addr addr) +{ + struct ospf_packet *op; + u_int16_t length = OSPF_HEADER_SIZE; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("listcount = %d, dst %s", listcount (update), inet_ntoa(addr)); + + op = ospf_packet_new (oi->ifp->mtu); + + /* Prepare OSPF common header. */ + ospf_make_header (OSPF_MSG_LS_UPD, oi, op->s); + + /* Prepare OSPF Link State Update body. */ + /* Includes Type-7 translation. */ + length += ospf_make_ls_upd (oi, update, op->s); + + /* Fill OSPF header. */ + ospf_fill_header (oi, op->s, length); + + /* Set packet length. */ + op->length = length; + + /* Decide destination address. */ + op->dst.s_addr = addr.s_addr; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (oi->ospf); +} + +static int +ospf_ls_upd_send_queue_event (struct thread *thread) +{ + struct ospf_interface *oi = THREAD_ARG(thread); + struct route_node *rn; + + oi->t_ls_upd_event = NULL; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ls_upd_send_queue start"); + + for (rn = route_top (oi->ls_upd_queue); rn; rn = route_next (rn)) + { + if (rn->info == NULL) + continue; + + while (!list_isempty ((list)rn->info)) + ospf_ls_upd_queue_send (oi, rn->info, rn->p.u.prefix4); + + list_delete (rn->info); + rn->info = NULL; + + route_unlock_node (rn); + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_ls_upd_send_queue stop"); + return 0; +} + +void +ospf_ls_upd_send (struct ospf_neighbor *nbr, list update, int flag) +{ + struct ospf_interface *oi; + struct prefix_ipv4 p; + struct route_node *rn; + listnode n; + + oi = nbr->oi; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + + /* Decide destination address. */ + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + p.prefix = oi->vl_data->peer_addr; + else if (flag == OSPF_SEND_PACKET_DIRECT) + p.prefix = nbr->address.u.prefix4; + else if (oi->state == ISM_DR || oi->state == ISM_Backup) + p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS); + else if ((oi->type == OSPF_IFTYPE_POINTOPOINT) + && (flag == OSPF_SEND_PACKET_INDIRECT)) + p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS); + else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) + p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS); + else + p.prefix.s_addr = htonl (OSPF_ALLDROUTERS); + + if (oi->type == OSPF_IFTYPE_NBMA) + { + if (flag == OSPF_SEND_PACKET_INDIRECT) + zlog_warn ("* LS-Update is directly sent on NBMA network."); + if (IPV4_ADDR_SAME(&oi->address->u.prefix4, &p.prefix.s_addr)) + zlog_warn ("* LS-Update is sent to myself."); + } + + rn = route_node_get (oi->ls_upd_queue, (struct prefix *) &p); + + if (rn->info == NULL) + rn->info = list_new (); + + for (n = listhead (update); n; nextnode (n)) + listnode_add (rn->info, ospf_lsa_lock (getdata (n))); + + if (oi->t_ls_upd_event == NULL) + oi->t_ls_upd_event = + thread_add_event (master, ospf_ls_upd_send_queue_event, oi, 0); +} + +static void +ospf_ls_ack_send_list (struct ospf_interface *oi, list ack, struct in_addr dst) +{ + struct ospf_packet *op; + u_int16_t length = OSPF_HEADER_SIZE; + + op = ospf_packet_new (oi->ifp->mtu); + + /* Prepare OSPF common header. */ + ospf_make_header (OSPF_MSG_LS_ACK, oi, op->s); + + /* Prepare OSPF Link State Acknowledgment body. */ + length += ospf_make_ls_ack (oi, ack, op->s); + + /* Fill OSPF header. */ + ospf_fill_header (oi, op->s, length); + + /* Set packet length. */ + op->length = length; + + /* Set destination IP address. */ + op->dst = dst; + + /* Add packet to the interface output queue. */ + ospf_packet_add (oi, op); + + /* Hook thread to write packet. */ + OSPF_ISM_WRITE_ON (oi->ospf); +} + +static int +ospf_ls_ack_send_event (struct thread *thread) +{ + struct ospf_interface *oi = THREAD_ARG (thread); + + oi->t_ls_ack_direct = NULL; + + while (listcount (oi->ls_ack_direct.ls_ack)) + ospf_ls_ack_send_list (oi, oi->ls_ack_direct.ls_ack, + oi->ls_ack_direct.dst); + + return 0; +} + +void +ospf_ls_ack_send (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +{ + struct ospf_interface *oi = nbr->oi; + + if (listcount (oi->ls_ack_direct.ls_ack) == 0) + oi->ls_ack_direct.dst = nbr->address.u.prefix4; + + listnode_add (oi->ls_ack_direct.ls_ack, ospf_lsa_lock (lsa)); + + if (oi->t_ls_ack_direct == NULL) + oi->t_ls_ack_direct = + thread_add_event (master, ospf_ls_ack_send_event, oi, 0); +} + +/* Send Link State Acknowledgment delayed. */ +void +ospf_ls_ack_send_delayed (struct ospf_interface *oi) +{ + struct in_addr dst; + + /* Decide destination address. */ + /* RFC2328 Section 13.5 On non-broadcast + networks, delayed Link State Acknowledgment packets must be + unicast separately over each adjacency (i.e., neighbor whose + state is >= Exchange). */ + if (oi->type == OSPF_IFTYPE_NBMA) + { + struct ospf_neighbor *nbr; + struct route_node *rn; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL) + if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) + while (listcount (oi->ls_ack)) + ospf_ls_ack_send_list (oi, oi->ls_ack, nbr->address.u.prefix4); + return; + } + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + dst.s_addr = oi->vl_data->peer_addr.s_addr; + else if (oi->state == ISM_DR || oi->state == ISM_Backup) + dst.s_addr = htonl (OSPF_ALLSPFROUTERS); + else if (oi->type == OSPF_IFTYPE_POINTOPOINT) + dst.s_addr = htonl (OSPF_ALLSPFROUTERS); + else + dst.s_addr = htonl (OSPF_ALLDROUTERS); + + while (listcount (oi->ls_ack)) + ospf_ls_ack_send_list (oi, oi->ls_ack, dst); +} diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h new file mode 100644 index 0000000..81a104c --- /dev/null +++ b/ospfd/ospf_packet.h @@ -0,0 +1,171 @@ +/* + * OSPF Sending and Receiving OSPF Packets. + * Copyright (C) 1999 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_PACKET_H +#define _ZEBRA_OSPF_PACKET_H + +#define OSPF_HEADER_SIZE 24 +#define OSPF_AUTH_SIMPLE_SIZE 8 +#define OSPF_AUTH_MD5_SIZE 16 + +#define OSPF_MAX_PACKET_SIZE 65535 /* includes IP Header size. */ +#define OSPF_HELLO_MIN_SIZE 20 /* not including neighbors */ +#define OSPF_DB_DESC_MIN_SIZE 8 +#define OSPF_LS_REQ_MIN_SIZE 0 +#define OSPF_LS_UPD_MIN_SIZE 4 +#define OSPF_LS_ACK_MIN_SIZE 0 + +#define OSPF_MSG_HELLO 1 /* OSPF Hello Message. */ +#define OSPF_MSG_DB_DESC 2 /* OSPF Database Descriptoin Message. */ +#define OSPF_MSG_LS_REQ 3 /* OSPF Link State Request Message. */ +#define OSPF_MSG_LS_UPD 4 /* OSPF Link State Update Message. */ +#define OSPF_MSG_LS_ACK 5 /* OSPF Link State Acknoledgement Message. */ + +#define OSPF_SEND_PACKET_DIRECT 1 +#define OSPF_SEND_PACKET_INDIRECT 2 + +#ifdef HAVE_NSSA +#define OSPF_SEND_PACKET_LOOP 3 +#endif /* HAVE_NSSA */ + +#define OSPF_HELLO_REPLY_DELAY 1 + +struct ospf_packet +{ + struct ospf_packet *next; + + /* Pointer to data stream. */ + struct stream *s; + + /* IP destination address. */ + struct in_addr dst; + + /* OSPF packet length. */ + u_int16_t length; +}; + +/* OSPF packet queue structure. */ +struct ospf_fifo +{ + unsigned long count; + + struct ospf_packet *head; + struct ospf_packet *tail; +}; + +/* OSPF packet header structure. */ +struct ospf_header +{ + u_char version; /* OSPF Version. */ + u_char type; /* Packet Type. */ + u_int16_t length; /* Packet Length. */ + struct in_addr router_id; /* Router ID. */ + struct in_addr area_id; /* Area ID. */ + u_int16_t checksum; /* Check Sum. */ + u_int16_t auth_type; /* Authentication Type. */ + /* Authentication Data. */ + union + { + /* Simple Authentication. */ + u_char auth_data [OSPF_AUTH_SIMPLE_SIZE]; + /* Cryptographic Authentication. */ + struct + { + u_int16_t zero; /* Should be 0. */ + u_char key_id; /* Key ID. */ + u_char auth_data_len; /* Auth Data Length. */ + u_int32_t crypt_seqnum; /* Cryptographic Sequence Number. */ + } crypt; + } u; +}; + +/* OSPF Hello body format. */ +struct ospf_hello +{ + struct in_addr network_mask; + u_int16_t hello_interval; + u_char options; + u_char priority; + u_int32_t dead_interval; + struct in_addr d_router; + struct in_addr bd_router; + struct in_addr neighbors[1]; +}; + +/* OSPF Database Description body format. */ +struct ospf_db_desc +{ + u_int16_t mtu; + u_char options; + u_char flags; + u_int32_t dd_seqnum; +}; + + +/* Macros. */ +#define OSPF_PACKET_MAX(oi) ospf_packet_max (oi) +/* +#define OSPF_PACKET_MAX(oi) (((oi)->ifp->mtu - ((oi)->auth_md5 ? OSPF_AUTH_MD5_SIZE : 0)) - 88) +*/ + +#define OSPF_OUTPUT_PNT(S) ((S)->data + (S)->putp) +#define OSPF_OUTPUT_LENGTH(S) ((S)->endp) + +#define IS_SET_DD_MS(X) ((X) & OSPF_DD_FLAG_MS) +#define IS_SET_DD_M(X) ((X) & OSPF_DD_FLAG_M) +#define IS_SET_DD_I(X) ((X) & OSPF_DD_FLAG_I) +#define IS_SET_DD_ALL(X) ((X) & OSPF_DD_FLAG_ALL) + +/* Prototypes. */ +void ospf_output_forward (struct stream *, int); +struct ospf_packet *ospf_packet_new (size_t); +void ospf_packet_free (struct ospf_packet *); +struct ospf_fifo *ospf_fifo_new (); +void ospf_fifo_push (struct ospf_fifo *, struct ospf_packet *); +struct ospf_packet *ospf_fifo_pop (struct ospf_fifo *); +struct ospf_packet *ospf_fifo_head (struct ospf_fifo *); +void ospf_fifo_flush (struct ospf_fifo *); +void ospf_fifo_free (struct ospf_fifo *); +void ospf_packet_add (struct ospf_interface *, struct ospf_packet *); +void ospf_packet_delete (struct ospf_interface *); +struct stream *ospf_stream_dup (struct stream *); +struct ospf_packet *ospf_packet_dup (struct ospf_packet *); + +int ospf_read (struct thread *); +void ospf_hello_send (struct ospf_interface *); +void ospf_db_desc_send (struct ospf_neighbor *); +void ospf_db_desc_resend (struct ospf_neighbor *); +void ospf_ls_req_send (struct ospf_neighbor *); +void ospf_ls_upd_send_lsa (struct ospf_neighbor *, struct ospf_lsa *, int); +void ospf_ls_upd_send (struct ospf_neighbor *, list, int); +void ospf_ls_ack_send (struct ospf_neighbor *, struct ospf_lsa *); +void ospf_ls_ack_send_delayed (struct ospf_interface *); +void ospf_ls_retransmit (struct ospf_interface *, struct ospf_lsa *); +void ospf_ls_req_event (struct ospf_neighbor *); + +int ospf_ls_upd_timer (struct thread *); +int ospf_ls_ack_timer (struct thread *); +int ospf_poll_timer (struct thread *); +int ospf_hello_reply_timer (struct thread *); +void ospf_hello_send_sub (struct ospf_interface *, struct in_addr *); + +#endif /* _ZEBRA_OSPF_PACKET_H */ diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c new file mode 100644 index 0000000..ded3f0c --- /dev/null +++ b/ospfd/ospf_route.c @@ -0,0 +1,1026 @@ +/* + * OSPF routing table. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "linklist.h" +#include "log.h" +#include "if.h" +#include "command.h" +#include "sockunion.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" + +struct ospf_route * +ospf_route_new () +{ + struct ospf_route *new; + + new = XCALLOC (MTYPE_OSPF_ROUTE, sizeof (struct ospf_route)); + + new->ctime = time (NULL); + new->mtime = new->ctime; + + return new; +} + +void +ospf_route_free (struct ospf_route *or) +{ + listnode node; + + if (or->path) + { + for (node = listhead (or->path); node; nextnode (node)) + ospf_path_free (node->data); + + list_delete (or->path); + } + + XFREE (MTYPE_OSPF_ROUTE, or); +} + +struct ospf_path * +ospf_path_new () +{ + struct ospf_path *new; + + new = XCALLOC (MTYPE_OSPF_PATH, sizeof (struct ospf_path)); + + return new; +} + +struct ospf_path * +ospf_path_dup (struct ospf_path *path) +{ + struct ospf_path *new; + + new = ospf_path_new (); + memcpy (new, path, sizeof (struct ospf_path)); + + return new; +} + +void +ospf_path_free (struct ospf_path *op) +{ + XFREE (MTYPE_OSPF_PATH, op); +} + +void +ospf_route_delete (struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + { + if (or->type == OSPF_DESTINATION_NETWORK) + ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, + or); + else if (or->type == OSPF_DESTINATION_DISCARD) + ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p); + } +} + +void +ospf_route_table_free (struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + { + ospf_route_free (or); + + rn->info = NULL; + route_unlock_node (rn); + } + + route_table_finish (rt); +} + +/* If a prefix and a nexthop match any route in the routing table, + then return 1, otherwise return 0. */ +int +ospf_route_match_same (struct route_table *rt, struct prefix_ipv4 *prefix, + struct ospf_route *newor) +{ + struct route_node *rn; + struct ospf_route *or; + struct ospf_path *op; + struct ospf_path *newop; + listnode n1; + listnode n2; + + if (! rt || ! prefix) + return 0; + + rn = route_node_lookup (rt, (struct prefix *) prefix); + if (! rn || ! rn->info) + return 0; + + route_unlock_node (rn); + + or = rn->info; + if (or->type == newor->type && or->cost == newor->cost) + { + if (or->type == OSPF_DESTINATION_NETWORK) + { + if (or->path->count != newor->path->count) + return 0; + + /* Check each path. */ + for (n1 = listhead (or->path), n2 = listhead (newor->path); + n1 && n2; nextnode (n1), nextnode (n2)) + { + op = getdata (n1); + newop = getdata (n2); + + if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop)) + return 0; + } + return 1; + } + else if (prefix_same (&rn->p, (struct prefix *) prefix)) + return 1; + } + return 0; +} + +/* rt: Old, cmprt: New */ +void +ospf_route_delete_uniq (struct route_table *rt, struct route_table *cmprt) +{ + struct route_node *rn; + struct ospf_route *or; + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + if (or->path_type == OSPF_PATH_INTRA_AREA || + or->path_type == OSPF_PATH_INTER_AREA) + { + if (or->type == OSPF_DESTINATION_NETWORK) + { + if (! ospf_route_match_same (cmprt, + (struct prefix_ipv4 *) &rn->p, or)) + ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); + } + else if (or->type == OSPF_DESTINATION_DISCARD) + if (! ospf_route_match_same (cmprt, + (struct prefix_ipv4 *) &rn->p, or)) + ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p); + } +} + +/* Install routes to table. */ +void +ospf_route_install (struct ospf *ospf, struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + + /* rt contains new routing table, new_table contains an old one. + updating pointers */ + if (ospf->old_table) + ospf_route_table_free (ospf->old_table); + + ospf->old_table = ospf->new_table; + ospf->new_table = rt; + + /* Delete old routes. */ + if (ospf->old_table) + ospf_route_delete_uniq (ospf->old_table, rt); + + /* Install new routes. */ + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + { + if (or->type == OSPF_DESTINATION_NETWORK) + { + if (! ospf_route_match_same (ospf->old_table, + (struct prefix_ipv4 *)&rn->p, or)) + ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or); + } + else if (or->type == OSPF_DESTINATION_DISCARD) + if (! ospf_route_match_same (ospf->old_table, + (struct prefix_ipv4 *) &rn->p, or)) + ospf_zebra_add_discard ((struct prefix_ipv4 *) &rn->p); + } +} + +void +ospf_intra_route_add (struct route_table *rt, struct vertex *v, + struct ospf_area *area) +{ + struct route_node *rn; + struct ospf_route *or; + struct prefix_ipv4 p; + struct ospf_path *path; + struct vertex_nexthop *nexthop; + listnode nnode; + + p.family = AF_INET; + p.prefix = v->id; + if (v->type == OSPF_VERTEX_ROUTER) + p.prefixlen = IPV4_MAX_BITLEN; + else + { + struct network_lsa *lsa = (struct network_lsa *) v->lsa; + p.prefixlen = ip_masklen (lsa->mask); + } + apply_mask_ipv4 (&p); + + rn = route_node_get (rt, (struct prefix *) &p); + if (rn->info) + { + zlog_warn ("Same routing information exists for %s", inet_ntoa (v->id)); + route_unlock_node (rn); + return; + } + + or = ospf_route_new (); + + if (v->type == OSPF_VERTEX_NETWORK) + { + or->type = OSPF_DESTINATION_NETWORK; + or->path = list_new (); + + for (nnode = listhead (v->nexthop); nnode; nextnode (nnode)) + { + nexthop = getdata (nnode); + path = ospf_path_new (); + path->nexthop = nexthop->router; + listnode_add (or->path, path); + } + } + else + or->type = OSPF_DESTINATION_ROUTER; + + or->id = v->id; + or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + or->u.std.external_routing= area->external_routing; +#endif /* HAVE_NSSA */ + or->path_type = OSPF_PATH_INTRA_AREA; + or->cost = v->distance; + + rn->info = or; +} + +/* RFC2328 16.1. (4). For "router". */ +void +ospf_intra_add_router (struct route_table *rt, struct vertex *v, + struct ospf_area *area) +{ + struct route_node *rn; + struct ospf_route *or; + struct prefix_ipv4 p; + struct router_lsa *lsa; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_router: Start"); + + lsa = (struct router_lsa *) v->lsa; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_router: LS ID: %s", + inet_ntoa (lsa->header.id)); + + ospf_vl_up_check (area, lsa->header.id, v); + + if (!CHECK_FLAG (lsa->flags, ROUTER_LSA_SHORTCUT)) + area->shortcut_capability = 0; + + /* If the newly added vertex is an area border router or AS boundary + router, a routing table entry is added whose destination type is + "router". */ + if (! IS_ROUTER_LSA_BORDER (lsa) && ! IS_ROUTER_LSA_EXTERNAL (lsa)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_router: " + "this router is neither ASBR nor ABR, skipping it"); + return; + } + + /* Update ABR and ASBR count in this area. */ + if (IS_ROUTER_LSA_BORDER (lsa)) + area->abr_count++; + if (IS_ROUTER_LSA_EXTERNAL (lsa)) + area->asbr_count++; + + /* The Options field found in the associated router-LSA is copied + into the routing table entry's Optional capabilities field. Call + the newly added vertex Router X. */ + or = ospf_route_new (); + + or->id = v->id; + or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + or->path_type = OSPF_PATH_INTRA_AREA; + or->cost = v->distance; + or->type = OSPF_DESTINATION_ROUTER; + or->u.std.origin = (struct lsa_header *) lsa; + or->u.std.options = lsa->header.options; + or->u.std.flags = lsa->flags; + + /* If Router X is the endpoint of one of the calculating router's + virtual links, and the virtual link uses Area A as Transit area: + the virtual link is declared up, the IP address of the virtual + interface is set to the IP address of the outgoing interface + calculated above for Router X, and the virtual neighbor's IP + address is set to Router X's interface address (contained in + Router X's router-LSA) that points back to the root of the + shortest- path tree; equivalently, this is the interface that + points back to Router X's parent vertex on the shortest-path tree + (similar to the calculation in Section 16.1.1). */ + + p.family = AF_INET; + p.prefix = v->id; + p.prefixlen = IPV4_MAX_BITLEN; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_router: talking about %s/%d", + inet_ntoa (p.prefix), p.prefixlen); + + rn = route_node_get (rt, (struct prefix *) &p); + + /* Note that we keep all routes to ABRs and ASBRs, not only the best */ + if (rn->info == NULL) + rn->info = list_new (); + else + route_unlock_node (rn); + + ospf_route_copy_nexthops_from_vertex (or, v); + + listnode_add (rn->info, or); + + zlog_info ("ospf_intra_add_router: Start"); +} + +/* RFC2328 16.1. (4). For transit network. */ +void +ospf_intra_add_transit (struct route_table *rt, struct vertex *v, + struct ospf_area *area) +{ + struct route_node *rn; + struct ospf_route *or; + struct prefix_ipv4 p; + struct network_lsa *lsa; + + lsa = (struct network_lsa*) v->lsa; + + /* If the newly added vertex is a transit network, the routing table + entry for the network is located. The entry's Destination ID is + the IP network number, which can be obtained by masking the + Vertex ID (Link State ID) with its associated subnet mask (found + in the body of the associated network-LSA). */ + p.family = AF_INET; + p.prefix = v->id; + p.prefixlen = ip_masklen (lsa->mask); + apply_mask_ipv4 (&p); + + rn = route_node_get (rt, (struct prefix *) &p); + + /* If the routing table entry already exists (i.e., there is already + an intra-area route to the destination installed in the routing + table), multiple vertices have mapped to the same IP network. + For example, this can occur when a new Designated Router is being + established. In this case, the current routing table entry + should be overwritten if and only if the newly found path is just + as short and the current routing table entry's Link State Origin + has a smaller Link State ID than the newly added vertex' LSA. */ + if (rn->info) + { + struct ospf_route *cur_or; + + route_unlock_node (rn); + cur_or = rn->info; + + if (v->distance > cur_or->cost || + IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) > 0) + return; + + ospf_route_free (rn->info); + } + + or = ospf_route_new (); + + or->id = v->id; + or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + or->path_type = OSPF_PATH_INTRA_AREA; + or->cost = v->distance; + or->type = OSPF_DESTINATION_NETWORK; + or->u.std.origin = (struct lsa_header *) lsa; + + ospf_route_copy_nexthops_from_vertex (or, v); + + rn->info = or; +} + +/* RFC2328 16.1. second stage. */ +void +ospf_intra_add_stub (struct route_table *rt, struct router_lsa_link *link, + struct vertex *v, struct ospf_area *area) +{ + u_int32_t cost; + struct route_node *rn; + struct ospf_route *or; + struct prefix_ipv4 p; + struct router_lsa *lsa; + struct ospf_interface *oi; + struct ospf_path *path; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): Start"); + + lsa = (struct router_lsa *) v->lsa; + + p.family = AF_INET; + p.prefix = link->link_id; + p.prefixlen = ip_masklen (link->link_data); + apply_mask_ipv4 (&p); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): processing route to %s/%d", + inet_ntoa (p.prefix), p.prefixlen); + + /* (1) Calculate the distance D of stub network from the root. D is + equal to the distance from the root to the router vertex + (calculated in stage 1), plus the stub network link's advertised + cost. */ + cost = v->distance + ntohs (link->m[0].metric); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): calculated cost is %d + %d = %d", + v->distance, ntohs(link->m[0].metric), cost); + + rn = route_node_get (rt, (struct prefix *) &p); + + /* Lookup current routing table. */ + if (rn->info) + { + struct ospf_route *cur_or; + + route_unlock_node (rn); + + cur_or = rn->info; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): " + "another route to the same prefix found"); + + /* Compare this distance to the current best cost to the stub + network. This is done by looking up the stub network's + current routing table entry. If the calculated distance D is + larger, go on to examine the next stub network link in the + LSA. */ + if (cost > cur_or->cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): old route is better, exit"); + return; + } + + /* (2) If this step is reached, the stub network's routing table + entry must be updated. Calculate the set of next hops that + would result from using the stub network link. This + calculation is shown in Section 16.1.1; input to this + calculation is the destination (the stub network) and the + parent vertex (the router vertex). If the distance D is the + same as the current routing table cost, simply add this set + of next hops to the routing table entry's list of next hops. + In this case, the routing table already has a Link State + Origin. If this Link State Origin is a router-LSA whose Link + State ID is smaller than V's Router ID, reset the Link State + Origin to V's router-LSA. */ + + if (cost == cur_or->cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): routes are equal, merge"); + + ospf_route_copy_nexthops_from_vertex (cur_or, v); + + if (IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) < 0) + cur_or->u.std.origin = (struct lsa_header *) lsa; + return; + } + + /* Otherwise D is smaller than the routing table cost. + Overwrite the current routing table entry by setting the + routing table entry's cost to D, and by setting the entry's + list of next hops to the newly calculated set. Set the + routing table entry's Link State Origin to V's router-LSA. + Then go on to examine the next stub network link. */ + + if (cost < cur_or->cost) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): new route is better, set it"); + + cur_or->cost = cost; + + list_delete (cur_or->path); + cur_or->path = NULL; + + ospf_route_copy_nexthops_from_vertex (cur_or, v); + + cur_or->u.std.origin = (struct lsa_header *) lsa; + return; + } + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): installing new route"); + + or = ospf_route_new (); + + or->id = v->id; + or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + or->path_type = OSPF_PATH_INTRA_AREA; + or->cost = cost; + or->type = OSPF_DESTINATION_NETWORK; + or->u.std.origin = (struct lsa_header *) lsa; + or->path = list_new (); + + /* Nexthop is depend on connection type. */ + if (v != area->spf) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): this network is on remote router"); + ospf_route_copy_nexthops_from_vertex (or, v); + } + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): this network is on this router"); + + if ((oi = ospf_if_lookup_by_prefix (area->ospf, &p))) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): the interface is %s", + IF_NAME (oi)); + + path = ospf_path_new (); + path->nexthop.s_addr = 0; + path->oi = oi; + listnode_add (or->path, path); + } + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_intra_add_stub(): where's the interface ?"); + } + } + + rn->info = or; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info("ospf_intra_add_stub(): Stop"); +} + +char *ospf_path_type_str[] = +{ + "unknown-type", + "intra-area", + "inter-area", + "type1-external", + "type2-external" +}; + +void +ospf_route_table_dump (struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; + listnode pnode; + struct ospf_path *path; + + zlog_info ("========== OSPF routing table =========="); + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + { + if (or->type == OSPF_DESTINATION_NETWORK) + { + zlog_info ("N %s/%d\t%s\t%s\t%d", + inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ), + rn->p.prefixlen, + inet_ntop (AF_INET, &or->u.std.area_id, buf2, + BUFSIZ), + ospf_path_type_str[or->path_type], + or->cost); + for (pnode = listhead (or->path); pnode; nextnode (pnode)) + { + path = getdata (pnode); + zlog_info (" -> %s", inet_ntoa (path->nexthop)); + } + } + else + zlog_info ("R %s\t%s\t%s\t%d", + inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ), + inet_ntop (AF_INET, &or->u.std.area_id, buf2, + BUFSIZ), + ospf_path_type_str[or->path_type], + or->cost); + } + zlog_info ("========================================"); +} + +void +ospf_terminate () +{ + struct ospf *ospf; + listnode node; + + LIST_LOOP (om->ospf, ospf, node) + { + if (ospf->new_table) + ospf_route_delete (ospf->new_table); + if (ospf->old_external_route) + ospf_route_delete (ospf->old_external_route); + } +} + +/* This is 16.4.1 implementation. + o Intra-area paths using non-backbone areas are always the most preferred. + o The other paths, intra-area backbone paths and inter-area paths, + are of equal preference. */ +int +ospf_asbr_route_cmp (struct ospf *ospf, struct ospf_route *r1, + struct ospf_route *r2) +{ + u_char r1_type, r2_type; + + r1_type = r1->path_type; + r2_type = r2->path_type; + + /* If RFC1583Compat flag is on -- all paths are equal. */ + if (CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) + return 0; + + /* r1/r2 itself is backbone, and it's Inter-area path. */ + if (OSPF_IS_AREA_ID_BACKBONE (r1->u.std.area_id)) + r1_type = OSPF_PATH_INTER_AREA; + if (OSPF_IS_AREA_ID_BACKBONE (r2->u.std.area_id)) + r2_type = OSPF_PATH_INTER_AREA; + + return (r1_type - r2_type); +} + +/* Compare two routes. + ret < 0 -- r1 is better. + ret == 0 -- r1 and r2 are the same. + ret > 0 -- r2 is better. */ +int +ospf_route_cmp (struct ospf *ospf, struct ospf_route *r1, + struct ospf_route *r2) +{ + int ret = 0; + + /* Path types of r1 and r2 are not the same. */ + if ((ret = (r1->path_type - r2->path_type))) + return ret; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Route[Compare]: Path types are the same."); + /* Path types are the same, compare any cost. */ + switch (r1->path_type) + { + case OSPF_PATH_INTRA_AREA: + case OSPF_PATH_INTER_AREA: + break; + case OSPF_PATH_TYPE1_EXTERNAL: + if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) + { + ret = ospf_asbr_route_cmp (ospf, r1->u.ext.asbr, r2->u.ext.asbr); + if (ret != 0) + return ret; + } + break; + case OSPF_PATH_TYPE2_EXTERNAL: + if ((ret = (r1->u.ext.type2_cost - r2->u.ext.type2_cost))) + return ret; + + if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) + { + ret = ospf_asbr_route_cmp (ospf, r1->u.ext.asbr, r2->u.ext.asbr); + if (ret != 0) + return ret; + } + break; + } + + /* Anyway, compare the costs. */ + return (r1->cost - r2->cost); +} + +int +ospf_path_exist (struct list *plist, struct in_addr nexthop, + struct ospf_interface *oi) +{ + listnode node; + struct ospf_path *path; + + for (node = listhead (plist); node; nextnode (node)) + { + path = node->data; + + if (IPV4_ADDR_SAME (&path->nexthop, &nexthop) && path->oi == oi) + return 1; + } + return 0; +} + +void +ospf_route_copy_nexthops_from_vertex (struct ospf_route *to, + struct vertex *v) +{ + listnode nnode; + struct ospf_path *path; + struct vertex_nexthop *nexthop; + + if (to->path == NULL) + to->path = list_new (); + + for (nnode = listhead (v->nexthop); nnode; nextnode (nnode)) + { + nexthop = getdata (nnode); + + if (nexthop->oi != NULL) + { + if (! ospf_path_exist (to->path, nexthop->router, nexthop->oi)) + { + path = ospf_path_new (); + path->nexthop = nexthop->router; + path->oi = nexthop->oi; + listnode_add (to->path, path); + } + } + } +} + +struct ospf_path * +ospf_path_lookup (list plist, struct ospf_path *path) +{ + listnode node; + + for (node = listhead (plist); node; nextnode (node)) + { + struct ospf_path *op = node->data; + + if (IPV4_ADDR_SAME (&op->nexthop, &path->nexthop) && + IPV4_ADDR_SAME (&op->adv_router, &path->adv_router)) + return op; + } + + return NULL; +} + +void +ospf_route_copy_nexthops (struct ospf_route *to, list from) +{ + listnode node; + + if (to->path == NULL) + to->path = list_new (); + + for (node = listhead (from); node; nextnode (node)) + /* The same routes are just discarded. */ + if (!ospf_path_lookup (to->path, node->data)) + listnode_add (to->path, ospf_path_dup (node->data)); +} + +void +ospf_route_subst_nexthops (struct ospf_route *to, list from) +{ + listnode node; + struct ospf_path *op; + + for (node = listhead (to->path); node; nextnode (node)) + if ((op = getdata (node)) != NULL) + { + ospf_path_free (op); + node->data = NULL; + } + + list_delete_all_node (to->path); + ospf_route_copy_nexthops (to, from); +} + +void +ospf_route_subst (struct route_node *rn, struct ospf_route *new_or, + struct ospf_route *over) +{ + route_lock_node (rn); + ospf_route_free (rn->info); + + ospf_route_copy_nexthops (new_or, over->path); + rn->info = new_or; + route_unlock_node (rn); +} + +void +ospf_route_add (struct route_table *rt, struct prefix_ipv4 *p, + struct ospf_route *new_or, struct ospf_route *over) +{ + struct route_node *rn; + + rn = route_node_get (rt, (struct prefix *) p); + + ospf_route_copy_nexthops (new_or, over->path); + + if (rn->info) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_route_add(): something's wrong !"); + route_unlock_node (rn); + return; + } + + rn->info = new_or; +} + +void +ospf_prune_unreachable_networks (struct route_table *rt) +{ + struct route_node *rn, *next; + struct ospf_route *or; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Pruning unreachable networks"); + + for (rn = route_top (rt); rn; rn = next) + { + next = route_next (rn); + if (rn->info != NULL) + { + or = rn->info; + if (listcount (or->path) == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Pruning route to %s/%d", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); + + ospf_route_free (or); + rn->info = NULL; + route_unlock_node (rn); + } + } + } +} + +void +ospf_prune_unreachable_routers (struct route_table *rtrs) +{ + struct route_node *rn, *next; + struct ospf_route *or; + listnode node, nnext; + list paths; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Pruning unreachable routers"); + + for (rn = route_top (rtrs); rn; rn = next) + { + next = route_next (rn); + if ((paths = rn->info) == NULL) + continue; + + for (node = listhead (paths); node; node = nnext) + { + nnext = node->next; + + or = getdata (node); + + if (listcount (or->path) == 0) + { + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("Pruning route to rtr %s", + inet_ntoa (rn->p.u.prefix4)); + zlog_info (" via area %s", + inet_ntoa (or->u.std.area_id)); + } + + listnode_delete (paths, or); + ospf_route_free (or); + } + } + + if (listcount (paths) == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Pruning router node %s", inet_ntoa (rn->p.u.prefix4)); + + list_delete (paths); + rn->info = NULL; + route_unlock_node (rn); + } + } +} + +int +ospf_add_discard_route (struct route_table *rt, struct ospf_area *area, + struct prefix_ipv4 *p) +{ + struct route_node *rn; + struct ospf_route *or, *new_or; + + rn = route_node_get (rt, (struct prefix *) p); + + if (rn == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_add_discard_route(): router installation error"); + return 0; + } + + if (rn->info) /* If the route to the same destination is found */ + { + route_unlock_node (rn); + + or = rn->info; + + if (or->path_type == OSPF_PATH_INTRA_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_add_discard_route(): " + "an intra-area route exists"); + return 0; + } + + if (or->type == OSPF_DESTINATION_DISCARD) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_add_discard_route(): " + "discard entry already installed"); + return 0; + } + + ospf_route_free (rn->info); + } + + new_or = ospf_route_new (); + new_or->type = OSPF_DESTINATION_DISCARD; + new_or->id.s_addr = 0; + new_or->cost = 0; + new_or->u.std.area_id = area->area_id; +#ifdef HAVE_NSSA + new_or->u.std.external_routing = area->external_routing; +#endif /* HAVE_NSSA */ + new_or->path_type = OSPF_PATH_INTER_AREA; + rn->info = new_or; + + ospf_zebra_add_discard (p); + + return 1; +} + +void +ospf_delete_discard_route (struct prefix_ipv4 *p) +{ + ospf_zebra_delete_discard(p); +} + diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h new file mode 100644 index 0000000..4222f52 --- /dev/null +++ b/ospfd/ospf_route.h @@ -0,0 +1,165 @@ +/* + * OSPF routing table. + * Copyright (C) 1999, 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ROUTE_H +#define _ZEBRA_OSPF_ROUTE_H + +#define OSPF_DESTINATION_ROUTER 1 +#define OSPF_DESTINATION_NETWORK 2 +#define OSPF_DESTINATION_DISCARD 3 + +#define OSPF_PATH_MIN 0 +#define OSPF_PATH_INTRA_AREA 1 +#define OSPF_PATH_INTER_AREA 2 +#define OSPF_PATH_TYPE1_EXTERNAL 3 +#define OSPF_PATH_TYPE2_EXTERNAL 4 +#define OSPF_PATH_MAX 5 + +/* OSPF Path. */ +struct ospf_path +{ + struct in_addr nexthop; + struct in_addr adv_router; + struct ospf_interface *oi; +}; + +/* Below is the structure linked to every + route node. Note that for Network routing + entries a single ospf_route is kept, while + for ABRs and ASBRs (Router routing entries), + we link an instance of ospf_router_route + where a list of paths is maintained, so + + nr->info is a (struct ospf_route *) for OSPF_DESTINATION_NETWORK + but + nr->info is a (struct ospf_router_route *) for OSPF_DESTINATION_ROUTER +*/ + +struct route_standard +{ + /* Link Sate Origin. */ + struct lsa_header *origin; + + /* Associated Area. */ + struct in_addr area_id; /* The area the route belongs to */ + +#ifdef HAVE_NSSA + /* Area Type */ + int external_routing; +#endif /* HAVE_NSSA */ + + /* Optional Capability. */ + u_char options; /* Get from LSA header. */ + + /* */ + u_char flags; /* From router-LSA */ +}; + +struct route_external +{ + /* Link State Origin. */ + struct ospf_lsa *origin; + + /* Link State Cost Type2. */ + u_int32_t type2_cost; + + /* Tag value. */ + u_int32_t tag; + + /* ASBR route. */ + struct ospf_route *asbr; +}; + +struct ospf_route +{ + /* Create time. */ + time_t ctime; + + /* Modified time. */ + time_t mtime; + + /* Destination Type. */ + u_char type; + + /* Destination ID. */ /* i.e. Link State ID. */ + struct in_addr id; + + /* Address Mask. */ + struct in_addr mask; /* Only valid for networks. */ + + /* Path Type. */ + u_char path_type; + + /* List of Paths. */ + list path; + + /* Link State Cost. */ + u_int32_t cost; /* i.e. metric. */ + + /* Route specific info. */ + union + { + struct route_standard std; + struct route_external ext; + } u; +}; + +struct ospf_path *ospf_path_new (); +void ospf_path_free (struct ospf_path *); +struct ospf_path *ospf_path_lookup (list, struct ospf_path *); +struct ospf_route *ospf_route_new (); +void ospf_route_free (struct ospf_route *); +void ospf_route_delete (struct route_table *); +void ospf_route_table_free (struct route_table *); + +void ospf_route_install (struct ospf *, struct route_table *); +void ospf_route_table_dump (struct route_table *); + +void ospf_intra_add_router (struct route_table *, struct vertex *, + struct ospf_area *); + +void ospf_intra_add_transit (struct route_table *, struct vertex *, + struct ospf_area *); + +void ospf_intra_add_stub (struct route_table *, struct router_lsa_link *, + struct vertex *, struct ospf_area *); + +int ospf_route_cmp (struct ospf *, struct ospf_route *, struct ospf_route *); +void ospf_route_copy_nexthops (struct ospf_route *, list); +void ospf_route_copy_nexthops_from_vertex (struct ospf_route *, + struct vertex * ); + +void ospf_route_subst (struct route_node *, struct ospf_route *, + struct ospf_route *); +void ospf_route_add (struct route_table *, struct prefix_ipv4 *, + struct ospf_route *, struct ospf_route *); + +void ospf_route_subst_nexthops (struct ospf_route *, list); +void ospf_prune_unreachable_networks (struct route_table *); +void ospf_prune_unreachable_routers (struct route_table *); +int ospf_add_discard_route (struct route_table *, struct ospf_area *, + struct prefix_ipv4 *); +void ospf_delete_discard_route (struct prefix_ipv4 *); +int ospf_route_match_same (struct route_table *, struct prefix_ipv4 *, + struct ospf_route *); + +#endif /* _ZEBRA_OSPF_ROUTE_H */ diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c new file mode 100644 index 0000000..b0617df --- /dev/null +++ b/ospfd/ospf_routemap.c @@ -0,0 +1,834 @@ +/* + * Route map function of ospfd. + * Copyright (C) 2000 IP Infusion Inc. + * + * Written by Toshiaki Takada. + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "prefix.h" +#include "table.h" +#include "routemap.h" +#include "command.h" +#include "log.h" +#include "plist.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" + +/* Hook function for updating route_map assignment. */ +void +ospf_route_map_update (char *name) +{ + struct ospf *ospf; + int type; + + /* If OSPF instatnce does not exist, return right now. */ + ospf = ospf_lookup (); + if (ospf == NULL) + return; + + /* Update route-map */ + for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) + { + if (ROUTEMAP_NAME (ospf, type) + && strcmp (ROUTEMAP_NAME (ospf, type), name) == 0) + { + /* Keep old route-map. */ + struct route_map *old = ROUTEMAP (ospf, type); + + /* Update route-map. */ + ROUTEMAP (ospf, type) = + route_map_lookup_by_name (ROUTEMAP_NAME (ospf, type)); + + /* No update for this distribute type. */ + if (old == NULL && ROUTEMAP (ospf, type) == NULL) + continue; + + ospf_distribute_list_update (ospf, type); + } + } +} + +void +ospf_route_map_event (route_map_event_t event, char *name) +{ + struct ospf *ospf; + int type; + + /* If OSPF instatnce does not exist, return right now. */ + ospf = ospf_lookup (); + if (ospf == NULL) + return; + + /* Update route-map. */ + for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) + { + if (ROUTEMAP_NAME (ospf, type) && ROUTEMAP (ospf, type) + && !strcmp (ROUTEMAP_NAME (ospf, type), name)) + { + ospf_distribute_list_update (ospf, type); + } + } +} + +/* Delete rip route map rule. */ +int +ospf_route_match_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + + return CMD_SUCCESS; +} + +int +ospf_route_match_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + + return CMD_SUCCESS; +} + +int +ospf_route_set_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + + return CMD_SUCCESS; +} + +/* Delete rip route map rule. */ +int +ospf_route_set_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + + return CMD_SUCCESS; +} + +/* `match ip netxthop ' */ +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_ip_nexthop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + struct external_info *ei = object; + struct prefix_ipv4 p; + + if (type == RMAP_OSPF) + { + p.family = AF_INET; + p.prefix = ei->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, &p) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip next-hop' match statement. `arg' should be + access-list name. */ +void * +route_match_ip_nexthop_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_nexthop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for metric matching. */ +struct route_map_rule_cmd route_match_ip_nexthop_cmd = +{ + "ip next-hop", + route_match_ip_nexthop, + route_match_ip_nexthop_compile, + route_match_ip_nexthop_free +}; + +/* `match ip next-hop prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + struct external_info *ei = object; + struct prefix_ipv4 p; + + if (type == RMAP_OSPF) + { + p.family = AF_INET; + p.prefix = ei->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, &p) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_next_hop_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_next_hop_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = +{ + "ip next-hop prefix-list", + route_match_ip_next_hop_prefix_list, + route_match_ip_next_hop_prefix_list_compile, + route_match_ip_next_hop_prefix_list_free +}; + +/* `match ip address IP_ACCESS_LIST' */ +/* Match function should return 1 if match is success else return + zero. */ +route_map_result_t +route_match_ip_address (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + /* struct prefix_ipv4 match; */ + + if (type == RMAP_OSPF) + { + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, prefix) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip address' match statement. `arg' should be + access-list name. */ +void * +route_match_ip_address_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_address_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_ip_address_cmd = +{ + "ip address", + route_match_ip_address, + route_match_ip_address_compile, + route_match_ip_address_free +}; + +/* `match ip address prefix-list PREFIX_LIST' */ +route_map_result_t +route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + + if (type == RMAP_OSPF) + { + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_address_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_address_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = +{ + "ip address prefix-list", + route_match_ip_address_prefix_list, + route_match_ip_address_prefix_list_compile, + route_match_ip_address_prefix_list_free +}; + +/* `match interface IFNAME' */ +/* Match function should return 1 if match is success else return + zero. */ +route_map_result_t +route_match_interface (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct interface *ifp; + struct external_info *ei; + + if (type == RMAP_OSPF) + { + ei = object; + ifp = if_lookup_by_name ((char *)rule); + + if (ifp == NULL || ifp->ifindex != ei->ifindex) + return RMAP_NOMATCH; + + return RMAP_MATCH; + } + return RMAP_NOMATCH; +} + +/* Route map `interface' match statement. `arg' should be + interface name. */ +void * +route_match_interface_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `interface' value. */ +void +route_match_interface_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_interface_cmd = +{ + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; + +/* `set metric METRIC' */ +/* Set metric to attribute. */ +route_map_result_t +route_set_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *metric; + struct external_info *ei; + + if (type == RMAP_OSPF) + { + /* Fetch routemap's rule information. */ + metric = rule; + ei = object; + + /* Set metric out value. */ + ei->route_map_set.metric = *metric; + } + return RMAP_OKAY; +} + +/* set metric compilation. */ +void * +route_set_metric_compile (char *arg) +{ + u_int32_t *metric; + + metric = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + *metric = atoi (arg); + + if (*metric >= 0) + return metric; + + XFREE (MTYPE_ROUTE_MAP_COMPILED, metric); + return NULL; +} + +/* Free route map's compiled `set metric' value. */ +void +route_set_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_metric_cmd = +{ + "metric", + route_set_metric, + route_set_metric_compile, + route_set_metric_free, +}; + +/* `set metric-type TYPE' */ +/* Set metric-type to attribute. */ +route_map_result_t +route_set_metric_type (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *metric_type; + struct external_info *ei; + + if (type == RMAP_OSPF) + { + /* Fetch routemap's rule information. */ + metric_type = rule; + ei = object; + + /* Set metric out value. */ + ei->route_map_set.metric_type = *metric_type; + } + return RMAP_OKAY; +} + +/* set metric-type compilation. */ +void * +route_set_metric_type_compile (char *arg) +{ + u_int32_t *metric_type; + + metric_type = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + if (strcmp (arg, "type-1") == 0) + *metric_type = EXTERNAL_METRIC_TYPE_1; + else if (strcmp (arg, "type-2") == 0) + *metric_type = EXTERNAL_METRIC_TYPE_2; + + if (*metric_type == EXTERNAL_METRIC_TYPE_1 || + *metric_type == EXTERNAL_METRIC_TYPE_2) + return metric_type; + + XFREE (MTYPE_ROUTE_MAP_COMPILED, metric_type); + return NULL; +} + +/* Free route map's compiled `set metric-type' value. */ +void +route_set_metric_type_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_metric_type_cmd = +{ + "metric-type", + route_set_metric_type, + route_set_metric_type_compile, + route_set_metric_type_free, +}; + +DEFUN (match_ip_nexthop, + match_ip_nexthop_cmd, + "match ip next-hop (<1-199>|<1300-2699>|WORD)", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP access-list name\n") +{ + return ospf_route_match_add (vty, vty->index, "ip next-hop", argv[0]); +} + +DEFUN (no_match_ip_nexthop, + no_match_ip_nexthop_cmd, + "no match ip next-hop", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n") +{ + if (argc == 0) + return ospf_route_match_delete (vty, vty->index, "ip next-hop", NULL); + + return ospf_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); +} + +ALIAS (no_match_ip_nexthop, + no_match_ip_nexthop_val_cmd, + "no match ip next-hop (<1-199>|<1300-2699>|WORD)", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP access-list name\n"); + +DEFUN (match_ip_next_hop_prefix_list, + match_ip_next_hop_prefix_list_cmd, + "match ip next-hop prefix-list WORD", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return ospf_route_match_add (vty, vty->index, "ip next-hop prefix-list", + argv[0]); +} + +DEFUN (no_match_ip_next_hop_prefix_list, + no_match_ip_next_hop_prefix_list_cmd, + "no match ip next-hop prefix-list", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n") +{ + if (argc == 0) + return ospf_route_match_delete (vty, vty->index, "ip next-hop prefix-list", + NULL); + return ospf_route_match_delete (vty, vty->index, "ip next-hop prefix-list", + argv[0]); +} + +ALIAS (no_match_ip_next_hop_prefix_list, + no_match_ip_next_hop_prefix_list_val_cmd, + "no match ip next-hop prefix-list WORD", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n"); + +DEFUN (match_ip_address, + match_ip_address_cmd, + "match ip address (<1-199>|<1300-2699>|WORD)", + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP access-list name\n") +{ + return ospf_route_match_add (vty, vty->index, "ip address", argv[0]); +} + +DEFUN (no_match_ip_address, + no_match_ip_address_cmd, + "no match ip address", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n") +{ + if (argc == 0) + return ospf_route_match_delete (vty, vty->index, "ip address", NULL); + + return ospf_route_match_delete (vty, vty->index, "ip address", argv[0]); +} + +ALIAS (no_match_ip_address, + no_match_ip_address_val_cmd, + "no match ip address (<1-199>|<1300-2699>|WORD)", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP access-list name\n"); + +DEFUN (match_ip_address_prefix_list, + match_ip_address_prefix_list_cmd, + "match ip address prefix-list WORD", + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return ospf_route_match_add (vty, vty->index, "ip address prefix-list", + argv[0]); +} + +DEFUN (no_match_ip_address_prefix_list, + no_match_ip_address_prefix_list_cmd, + "no match ip address prefix-list", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n") +{ + if (argc == 0) + return ospf_route_match_delete (vty, vty->index, "ip address prefix-list", + NULL); + return ospf_route_match_delete (vty, vty->index, "ip address prefix-list", + argv[0]); +} + +ALIAS (no_match_ip_address_prefix_list, + no_match_ip_address_prefix_list_val_cmd, + "no match ip address prefix-list WORD", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n"); + +DEFUN (match_interface, + match_interface_cmd, + "match interface WORD", + MATCH_STR + "Match first hop interface of route\n" + "Interface name\n") +{ + return ospf_route_match_add (vty, vty->index, "interface", argv[0]); +} + +DEFUN (no_match_interface, + no_match_interface_cmd, + "no match interface", + NO_STR + MATCH_STR + "Match first hop interface of route\n") +{ + if (argc == 0) + return ospf_route_match_delete (vty, vty->index, "interface", NULL); + + return ospf_route_match_delete (vty, vty->index, "interface", argv[0]); +} + +ALIAS (no_match_interface, + no_match_interface_val_cmd, + "no match interface WORD", + NO_STR + MATCH_STR + "Match first hop interface of route\n" + "Interface name\n"); + +DEFUN (set_metric, + set_metric_cmd, + "set metric <0-4294967295>", + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n") +{ + return ospf_route_set_add (vty, vty->index, "metric", argv[0]); +} + +DEFUN (no_set_metric, + no_set_metric_cmd, + "no set metric", + NO_STR + SET_STR + "Metric value for destination routing protocol\n") +{ + if (argc == 0) + return ospf_route_set_delete (vty, vty->index, "metric", NULL); + + return ospf_route_set_delete (vty, vty->index, "metric", argv[0]); +} + +ALIAS (no_set_metric, + no_set_metric_val_cmd, + "no set metric <0-4294967295>", + NO_STR + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n"); + +DEFUN (set_metric_type, + set_metric_type_cmd, + "set metric-type (type-1|type-2)", + SET_STR + "Type of metric for destination routing protocol\n" + "OSPF external type 1 metric\n" + "OSPF external type 2 metric\n") +{ + if (strcmp (argv[0], "1") == 0) + return ospf_route_set_add (vty, vty->index, "metric-type", "type-1"); + if (strcmp (argv[0], "2") == 0) + return ospf_route_set_add (vty, vty->index, "metric-type", "type-2"); + + return ospf_route_set_add (vty, vty->index, "metric-type", argv[0]); +} + +DEFUN (no_set_metric_type, + no_set_metric_type_cmd, + "no set metric-type", + NO_STR + SET_STR + "Type of metric for destination routing protocol\n") +{ + if (argc == 0) + return ospf_route_set_delete (vty, vty->index, "metric-type", NULL); + + return ospf_route_set_delete (vty, vty->index, "metric-type", argv[0]); +} + +ALIAS (no_set_metric_type, + no_set_metric_type_val_cmd, + "no set metric-type (type-1|type-2)", + NO_STR + SET_STR + "Type of metric for destination routing protocol\n" + "OSPF external type 1 metric\n" + "OSPF external type 2 metric\n"); + +/* Route-map init */ +void +ospf_route_map_init (void) +{ + route_map_init (); + route_map_init_vty (); + + route_map_add_hook (ospf_route_map_update); + route_map_delete_hook (ospf_route_map_update); + route_map_event_hook (ospf_route_map_event); + + route_map_install_match (&route_match_ip_nexthop_cmd); + route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); + route_map_install_match (&route_match_ip_address_cmd); + route_map_install_match (&route_match_ip_address_prefix_list_cmd); + route_map_install_match (&route_match_interface_cmd); + + route_map_install_set (&route_set_metric_cmd); + route_map_install_set (&route_set_metric_type_cmd); + + install_element (RMAP_NODE, &match_ip_nexthop_cmd); + install_element (RMAP_NODE, &no_match_ip_nexthop_cmd); + install_element (RMAP_NODE, &no_match_ip_nexthop_val_cmd); + install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd); + install_element (RMAP_NODE, &match_ip_address_cmd); + install_element (RMAP_NODE, &no_match_ip_address_cmd); + install_element (RMAP_NODE, &no_match_ip_address_val_cmd); + install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); + install_element (RMAP_NODE, &match_interface_cmd); + install_element (RMAP_NODE, &no_match_interface_cmd); + install_element (RMAP_NODE, &no_match_interface_val_cmd); + + install_element (RMAP_NODE, &set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_val_cmd); + install_element (RMAP_NODE, &set_metric_type_cmd); + install_element (RMAP_NODE, &no_set_metric_type_cmd); + install_element (RMAP_NODE, &no_set_metric_type_val_cmd); +} diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c new file mode 100644 index 0000000..e82bdef --- /dev/null +++ b/ospfd/ospf_snmp.c @@ -0,0 +1,2527 @@ +/* OSPFv2 SNMP support + * Copyright (C) 2000 IP Infusion Inc. + * + * Written by Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#ifdef HAVE_SNMP + +#ifdef HAVE_NETSNMP +#include +#endif /* HAVE_NETSNMP */ + +#include +#include +#include + +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "table.h" +#include "command.h" +#include "memory.h" +#include "smux.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_flood.h" + +/* OSPF2-MIB. */ +#define OSPF2MIB 1,3,6,1,2,1,14 + +/* Zebra enterprise OSPF MIB. This variable is used for register + OSPF MIB to SNMP agent under SMUX protocol. */ +#define OSPFDOID 1,3,6,1,4,1,3317,1,2,5 + +/* OSPF MIB General Group values. */ +#define OSPFROUTERID 1 +#define OSPFADMINSTAT 2 +#define OSPFVERSIONNUMBER 3 +#define OSPFAREABDRRTRSTATUS 4 +#define OSPFASBDRRTRSTATUS 5 +#define OSPFEXTERNLSACOUNT 6 +#define OSPFEXTERNLSACKSUMSUM 7 +#define OSPFTOSSUPPORT 8 +#define OSPFORIGINATENEWLSAS 9 +#define OSPFRXNEWLSAS 10 +#define OSPFEXTLSDBLIMIT 11 +#define OSPFMULTICASTEXTENSIONS 12 +#define OSPFEXITOVERFLOWINTERVAL 13 +#define OSPFDEMANDEXTENSIONS 14 + +/* OSPF MIB ospfAreaTable. */ +#define OSPFAREAID 1 +#define OSPFAUTHTYPE 2 +#define OSPFIMPORTASEXTERN 3 +#define OSPFSPFRUNS 4 +#define OSPFAREABDRRTRCOUNT 5 +#define OSPFASBDRRTRCOUNT 6 +#define OSPFAREALSACOUNT 7 +#define OSPFAREALSACKSUMSUM 8 +#define OSPFAREASUMMARY 9 +#define OSPFAREASTATUS 10 + +/* OSPF MIB ospfStubAreaTable. */ +#define OSPFSTUBAREAID 1 +#define OSPFSTUBTOS 2 +#define OSPFSTUBMETRIC 3 +#define OSPFSTUBSTATUS 4 +#define OSPFSTUBMETRICTYPE 5 + +/* OSPF MIB ospfLsdbTable. */ +#define OSPFLSDBAREAID 1 +#define OSPFLSDBTYPE 2 +#define OSPFLSDBLSID 3 +#define OSPFLSDBROUTERID 4 +#define OSPFLSDBSEQUENCE 5 +#define OSPFLSDBAGE 6 +#define OSPFLSDBCHECKSUM 7 +#define OSPFLSDBADVERTISEMENT 8 + +/* OSPF MIB ospfAreaRangeTable. */ +#define OSPFAREARANGEAREAID 1 +#define OSPFAREARANGENET 2 +#define OSPFAREARANGEMASK 3 +#define OSPFAREARANGESTATUS 4 +#define OSPFAREARANGEEFFECT 5 + +/* OSPF MIB ospfHostTable. */ +#define OSPFHOSTIPADDRESS 1 +#define OSPFHOSTTOS 2 +#define OSPFHOSTMETRIC 3 +#define OSPFHOSTSTATUS 4 +#define OSPFHOSTAREAID 5 + +/* OSPF MIB ospfIfTable. */ +#define OSPFIFIPADDRESS 1 +#define OSPFADDRESSLESSIF 2 +#define OSPFIFAREAID 3 +#define OSPFIFTYPE 4 +#define OSPFIFADMINSTAT 5 +#define OSPFIFRTRPRIORITY 6 +#define OSPFIFTRANSITDELAY 7 +#define OSPFIFRETRANSINTERVAL 8 +#define OSPFIFHELLOINTERVAL 9 +#define OSPFIFRTRDEADINTERVAL 10 +#define OSPFIFPOLLINTERVAL 11 +#define OSPFIFSTATE 12 +#define OSPFIFDESIGNATEDROUTER 13 +#define OSPFIFBACKUPDESIGNATEDROUTER 14 +#define OSPFIFEVENTS 15 +#define OSPFIFAUTHKEY 16 +#define OSPFIFSTATUS 17 +#define OSPFIFMULTICASTFORWARDING 18 +#define OSPFIFDEMAND 19 +#define OSPFIFAUTHTYPE 20 + +/* OSPF MIB ospfIfMetricTable. */ +#define OSPFIFMETRICIPADDRESS 1 +#define OSPFIFMETRICADDRESSLESSIF 2 +#define OSPFIFMETRICTOS 3 +#define OSPFIFMETRICVALUE 4 +#define OSPFIFMETRICSTATUS 5 + +/* OSPF MIB ospfVirtIfTable. */ +#define OSPFVIRTIFAREAID 1 +#define OSPFVIRTIFNEIGHBOR 2 +#define OSPFVIRTIFTRANSITDELAY 3 +#define OSPFVIRTIFRETRANSINTERVAL 4 +#define OSPFVIRTIFHELLOINTERVAL 5 +#define OSPFVIRTIFRTRDEADINTERVAL 6 +#define OSPFVIRTIFSTATE 7 +#define OSPFVIRTIFEVENTS 8 +#define OSPFVIRTIFAUTHKEY 9 +#define OSPFVIRTIFSTATUS 10 +#define OSPFVIRTIFAUTHTYPE 11 + +/* OSPF MIB ospfNbrTable. */ +#define OSPFNBRIPADDR 1 +#define OSPFNBRADDRESSLESSINDEX 2 +#define OSPFNBRRTRID 3 +#define OSPFNBROPTIONS 4 +#define OSPFNBRPRIORITY 5 +#define OSPFNBRSTATE 6 +#define OSPFNBREVENTS 7 +#define OSPFNBRLSRETRANSQLEN 8 +#define OSPFNBMANBRSTATUS 9 +#define OSPFNBMANBRPERMANENCE 10 +#define OSPFNBRHELLOSUPPRESSED 11 + +/* OSPF MIB ospfVirtNbrTable. */ +#define OSPFVIRTNBRAREA 1 +#define OSPFVIRTNBRRTRID 2 +#define OSPFVIRTNBRIPADDR 3 +#define OSPFVIRTNBROPTIONS 4 +#define OSPFVIRTNBRSTATE 5 +#define OSPFVIRTNBREVENTS 6 +#define OSPFVIRTNBRLSRETRANSQLEN 7 +#define OSPFVIRTNBRHELLOSUPPRESSED 8 + +/* OSPF MIB ospfExtLsdbTable. */ +#define OSPFEXTLSDBTYPE 1 +#define OSPFEXTLSDBLSID 2 +#define OSPFEXTLSDBROUTERID 3 +#define OSPFEXTLSDBSEQUENCE 4 +#define OSPFEXTLSDBAGE 5 +#define OSPFEXTLSDBCHECKSUM 6 +#define OSPFEXTLSDBADVERTISEMENT 7 + +/* OSPF MIB ospfAreaAggregateTable. */ +#define OSPFAREAAGGREGATEAREAID 1 +#define OSPFAREAAGGREGATELSDBTYPE 2 +#define OSPFAREAAGGREGATENET 3 +#define OSPFAREAAGGREGATEMASK 4 +#define OSPFAREAAGGREGATESTATUS 5 +#define OSPFAREAAGGREGATEEFFECT 6 + +/* SYNTAX Status from OSPF-MIB. */ +#define OSPF_STATUS_ENABLED 1 +#define OSPF_STATUS_DISABLED 2 + +/* SNMP value hack. */ +#define COUNTER ASN_COUNTER +#define INTEGER ASN_INTEGER +#define GAUGE ASN_GAUGE +#define TIMETICKS ASN_TIMETICKS +#define IPADDRESS ASN_IPADDRESS +#define STRING ASN_OCTET_STR + +/* Declare static local variables for convenience. */ +SNMP_LOCAL_VARIABLES + +/* OSPF-MIB instances. */ +oid ospf_oid [] = { OSPF2MIB }; +oid ospfd_oid [] = { OSPFDOID }; + +/* IP address 0.0.0.0. */ +static struct in_addr ospf_empty_addr = {0}; + +/* Hook functions. */ +static u_char *ospfGeneralGroup (); +static u_char *ospfAreaEntry (); +static u_char *ospfStubAreaEntry (); +static u_char *ospfLsdbEntry (); +static u_char *ospfAreaRangeEntry (); +static u_char *ospfHostEntry (); +static u_char *ospfIfEntry (); +static u_char *ospfIfMetricEntry (); +static u_char *ospfVirtIfEntry (); +static u_char *ospfNbrEntry (); +static u_char *ospfVirtNbrEntry (); +static u_char *ospfExtLsdbEntry (); +static u_char *ospfAreaAggregateEntry (); + +struct variable ospf_variables[] = +{ + /* OSPF general variables */ + {OSPFROUTERID, IPADDRESS, RWRITE, ospfGeneralGroup, + 2, {1, 1}}, + {OSPFADMINSTAT, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 2}}, + {OSPFVERSIONNUMBER, INTEGER, RONLY, ospfGeneralGroup, + 2, {1, 3}}, + {OSPFAREABDRRTRSTATUS, INTEGER, RONLY, ospfGeneralGroup, + 2, {1, 4}}, + {OSPFASBDRRTRSTATUS, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 5}}, + {OSPFEXTERNLSACOUNT, GAUGE, RONLY, ospfGeneralGroup, + 2, {1, 6}}, + {OSPFEXTERNLSACKSUMSUM, INTEGER, RONLY, ospfGeneralGroup, + 2, {1, 7}}, + {OSPFTOSSUPPORT, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 8}}, + {OSPFORIGINATENEWLSAS, COUNTER, RONLY, ospfGeneralGroup, + 2, {1, 9}}, + {OSPFRXNEWLSAS, COUNTER, RONLY, ospfGeneralGroup, + 2, {1, 10}}, + {OSPFEXTLSDBLIMIT, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 11}}, + {OSPFMULTICASTEXTENSIONS, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 12}}, + {OSPFEXITOVERFLOWINTERVAL, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 13}}, + {OSPFDEMANDEXTENSIONS, INTEGER, RWRITE, ospfGeneralGroup, + 2, {1, 14}}, + + /* OSPF area data structure. */ + {OSPFAREAID, IPADDRESS, RONLY, ospfAreaEntry, + 3, {2, 1, 1}}, + {OSPFAUTHTYPE, INTEGER, RWRITE, ospfAreaEntry, + 3, {2, 1, 2}}, + {OSPFIMPORTASEXTERN, INTEGER, RWRITE, ospfAreaEntry, + 3, {2, 1, 3}}, + {OSPFSPFRUNS, COUNTER, RONLY, ospfAreaEntry, + 3, {2, 1, 4}}, + {OSPFAREABDRRTRCOUNT, GAUGE, RONLY, ospfAreaEntry, + 3, {2, 1, 5}}, + {OSPFASBDRRTRCOUNT, GAUGE, RONLY, ospfAreaEntry, + 3, {2, 1, 6}}, + {OSPFAREALSACOUNT, GAUGE, RONLY, ospfAreaEntry, + 3, {2, 1, 7}}, + {OSPFAREALSACKSUMSUM, INTEGER, RONLY, ospfAreaEntry, + 3, {2, 1, 8}}, + {OSPFAREASUMMARY, INTEGER, RWRITE, ospfAreaEntry, + 3, {2, 1, 9}}, + {OSPFAREASTATUS, INTEGER, RWRITE, ospfAreaEntry, + 3, {2, 1, 10}}, + + /* OSPF stub area information. */ + {OSPFSTUBAREAID, IPADDRESS, RONLY, ospfStubAreaEntry, + 3, {3, 1, 1}}, + {OSPFSTUBTOS, INTEGER, RONLY, ospfStubAreaEntry, + 3, {3, 1, 2}}, + {OSPFSTUBMETRIC, INTEGER, RWRITE, ospfStubAreaEntry, + 3, {3, 1, 3}}, + {OSPFSTUBSTATUS, INTEGER, RWRITE, ospfStubAreaEntry, + 3, {3, 1, 4}}, + {OSPFSTUBMETRICTYPE, INTEGER, RWRITE, ospfStubAreaEntry, + 3, {3, 1, 5}}, + + /* OSPF link state database. */ + {OSPFLSDBAREAID, IPADDRESS, RONLY, ospfLsdbEntry, + 3, {4, 1, 1}}, + {OSPFLSDBTYPE, INTEGER, RONLY, ospfLsdbEntry, + 3, {4, 1, 2}}, + {OSPFLSDBLSID, IPADDRESS, RONLY, ospfLsdbEntry, + 3, {4, 1, 3}}, + {OSPFLSDBROUTERID, IPADDRESS, RONLY, ospfLsdbEntry, + 3, {4, 1, 4}}, + {OSPFLSDBSEQUENCE, INTEGER, RONLY, ospfLsdbEntry, + 3, {4, 1, 5}}, + {OSPFLSDBAGE, INTEGER, RONLY, ospfLsdbEntry, + 3, {4, 1, 6}}, + {OSPFLSDBCHECKSUM, INTEGER, RONLY, ospfLsdbEntry, + 3, {4, 1, 7}}, + {OSPFLSDBADVERTISEMENT, STRING, RONLY, ospfLsdbEntry, + 3, {4, 1, 8}}, + + /* Area range table. */ + {OSPFAREARANGEAREAID, IPADDRESS, RONLY, ospfAreaRangeEntry, + 3, {5, 1, 1}}, + {OSPFAREARANGENET, IPADDRESS, RONLY, ospfAreaRangeEntry, + 3, {5, 1, 2}}, + {OSPFAREARANGEMASK, IPADDRESS, RWRITE, ospfAreaRangeEntry, + 3, {5, 1, 3}}, + {OSPFAREARANGESTATUS, INTEGER, RWRITE, ospfAreaRangeEntry, + 3, {5, 1, 4}}, + {OSPFAREARANGEEFFECT, INTEGER, RWRITE, ospfAreaRangeEntry, + 3, {5, 1, 5}}, + + /* OSPF host table. */ + {OSPFHOSTIPADDRESS, IPADDRESS, RONLY, ospfHostEntry, + 3, {6, 1, 1}}, + {OSPFHOSTTOS, INTEGER, RONLY, ospfHostEntry, + 3, {6, 1, 2}}, + {OSPFHOSTMETRIC, INTEGER, RWRITE, ospfHostEntry, + 3, {6, 1, 3}}, + {OSPFHOSTSTATUS, INTEGER, RWRITE, ospfHostEntry, + 3, {6, 1, 4}}, + {OSPFHOSTAREAID, IPADDRESS, RONLY, ospfHostEntry, + 3, {6, 1, 5}}, + + /* OSPF interface table. */ + {OSPFIFIPADDRESS, IPADDRESS, RONLY, ospfIfEntry, + 3, {7, 1, 1}}, + {OSPFADDRESSLESSIF, INTEGER, RONLY, ospfIfEntry, + 3, {7, 1, 2}}, + {OSPFIFAREAID, IPADDRESS, RWRITE, ospfIfEntry, + 3, {7, 1, 3}}, + {OSPFIFTYPE, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 4}}, + {OSPFIFADMINSTAT, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 5}}, + {OSPFIFRTRPRIORITY, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 6}}, + {OSPFIFTRANSITDELAY, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 7}}, + {OSPFIFRETRANSINTERVAL, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 8}}, + {OSPFIFHELLOINTERVAL, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 9}}, + {OSPFIFRTRDEADINTERVAL, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 10}}, + {OSPFIFPOLLINTERVAL, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 11}}, + {OSPFIFSTATE, INTEGER, RONLY, ospfIfEntry, + 3, {7, 1, 12}}, + {OSPFIFDESIGNATEDROUTER, IPADDRESS, RONLY, ospfIfEntry, + 3, {7, 1, 13}}, + {OSPFIFBACKUPDESIGNATEDROUTER, IPADDRESS, RONLY, ospfIfEntry, + 3, {7, 1, 14}}, + {OSPFIFEVENTS, COUNTER, RONLY, ospfIfEntry, + 3, {7, 1, 15}}, + {OSPFIFAUTHKEY, STRING, RWRITE, ospfIfEntry, + 3, {7, 1, 16}}, + {OSPFIFSTATUS, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 17}}, + {OSPFIFMULTICASTFORWARDING, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 18}}, + {OSPFIFDEMAND, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 19}}, + {OSPFIFAUTHTYPE, INTEGER, RWRITE, ospfIfEntry, + 3, {7, 1, 20}}, + + /* OSPF interface metric table. */ + {OSPFIFMETRICIPADDRESS, IPADDRESS, RONLY, ospfIfMetricEntry, + 3, {8, 1, 1}}, + {OSPFIFMETRICADDRESSLESSIF, INTEGER, RONLY, ospfIfMetricEntry, + 3, {8, 1, 2}}, + {OSPFIFMETRICTOS, INTEGER, RONLY, ospfIfMetricEntry, + 3, {8, 1, 3}}, + {OSPFIFMETRICVALUE, INTEGER, RWRITE, ospfIfMetricEntry, + 3, {8, 1, 4}}, + {OSPFIFMETRICSTATUS, INTEGER, RWRITE, ospfIfMetricEntry, + 3, {8, 1, 5}}, + + /* OSPF virtual interface table. */ + {OSPFVIRTIFAREAID, IPADDRESS, RONLY, ospfVirtIfEntry, + 3, {9, 1, 1}}, + {OSPFVIRTIFNEIGHBOR, IPADDRESS, RONLY, ospfVirtIfEntry, + 3, {9, 1, 2}}, + {OSPFVIRTIFTRANSITDELAY, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 3}}, + {OSPFVIRTIFRETRANSINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 4}}, + {OSPFVIRTIFHELLOINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 5}}, + {OSPFVIRTIFRTRDEADINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 6}}, + {OSPFVIRTIFSTATE, INTEGER, RONLY, ospfVirtIfEntry, + 3, {9, 1, 7}}, + {OSPFVIRTIFEVENTS, COUNTER, RONLY, ospfVirtIfEntry, + 3, {9, 1, 8}}, + {OSPFVIRTIFAUTHKEY, STRING, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 9}}, + {OSPFVIRTIFSTATUS, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 10}}, + {OSPFVIRTIFAUTHTYPE, INTEGER, RWRITE, ospfVirtIfEntry, + 3, {9, 1, 11}}, + + /* OSPF neighbor table. */ + {OSPFNBRIPADDR, IPADDRESS, RONLY, ospfNbrEntry, + 3, {10, 1, 1}}, + {OSPFNBRADDRESSLESSINDEX, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 2}}, + {OSPFNBRRTRID, IPADDRESS, RONLY, ospfNbrEntry, + 3, {10, 1, 3}}, + {OSPFNBROPTIONS, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 4}}, + {OSPFNBRPRIORITY, INTEGER, RWRITE, ospfNbrEntry, + 3, {10, 1, 5}}, + {OSPFNBRSTATE, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 6}}, + {OSPFNBREVENTS, COUNTER, RONLY, ospfNbrEntry, + 3, {10, 1, 7}}, + {OSPFNBRLSRETRANSQLEN, GAUGE, RONLY, ospfNbrEntry, + 3, {10, 1, 8}}, + {OSPFNBMANBRSTATUS, INTEGER, RWRITE, ospfNbrEntry, + 3, {10, 1, 9}}, + {OSPFNBMANBRPERMANENCE, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 10}}, + {OSPFNBRHELLOSUPPRESSED, INTEGER, RONLY, ospfNbrEntry, + 3, {10, 1, 11}}, + + /* OSPF virtual neighbor table. */ + {OSPFVIRTNBRAREA, IPADDRESS, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 1}}, + {OSPFVIRTNBRRTRID, IPADDRESS, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 2}}, + {OSPFVIRTNBRIPADDR, IPADDRESS, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 3}}, + {OSPFVIRTNBROPTIONS, INTEGER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 4}}, + {OSPFVIRTNBRSTATE, INTEGER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 5}}, + {OSPFVIRTNBREVENTS, COUNTER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 6}}, + {OSPFVIRTNBRLSRETRANSQLEN, INTEGER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 7}}, + {OSPFVIRTNBRHELLOSUPPRESSED, INTEGER, RONLY, ospfVirtNbrEntry, + 3, {11, 1, 8}}, + + /* OSPF link state database, external. */ + {OSPFEXTLSDBTYPE, INTEGER, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 1}}, + {OSPFEXTLSDBLSID, IPADDRESS, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 2}}, + {OSPFEXTLSDBROUTERID, IPADDRESS, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 3}}, + {OSPFEXTLSDBSEQUENCE, INTEGER, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 4}}, + {OSPFEXTLSDBAGE, INTEGER, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 5}}, + {OSPFEXTLSDBCHECKSUM, INTEGER, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 6}}, + {OSPFEXTLSDBADVERTISEMENT, STRING, RONLY, ospfExtLsdbEntry, + 3, {12, 1, 7}}, + + /* OSPF area aggregate table. */ + {OSPFAREAAGGREGATEAREAID, IPADDRESS, RONLY, ospfAreaAggregateEntry, + 3, {14, 1, 1}}, + {OSPFAREAAGGREGATELSDBTYPE, INTEGER, RONLY, ospfAreaAggregateEntry, + 3, {14, 1, 2}}, + {OSPFAREAAGGREGATENET, IPADDRESS, RONLY, ospfAreaAggregateEntry, + 3, {14, 1, 3}}, + {OSPFAREAAGGREGATEMASK, IPADDRESS, RONLY, ospfAreaAggregateEntry, + 3, {14, 1, 4}}, + {OSPFAREAAGGREGATESTATUS, INTEGER, RWRITE, ospfAreaAggregateEntry, + 3, {14, 1, 5}}, + {OSPFAREAAGGREGATEEFFECT, INTEGER, RWRITE, ospfAreaAggregateEntry, + 3, {14, 1, 6}} +}; + +/* The administrative status of OSPF. When OSPF is enbled on at least + one interface return 1. */ +int +ospf_admin_stat (struct ospf *ospf) +{ + listnode node; + struct ospf_interface *oi; + + if (ospf == NULL) + return 0; + + for (node = listhead (ospf->oiflist); node; nextnode (node)) + { + oi = getdata (node); + + if (oi && oi->address) + return 1; + } + return 0; +} + +static u_char * +ospfGeneralGroup (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + struct ospf *ospf; + + ospf = ospf_lookup (); + + /* Check whether the instance identifier is valid */ + if (smux_header_generic (v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFROUTERID: /* 1 */ + /* Router-ID of this OSPF instance. */ + if (ospf) + return SNMP_IPADDRESS (ospf->router_id); + else + return SNMP_IPADDRESS (ospf_empty_addr); + break; + case OSPFADMINSTAT: /* 2 */ + /* The administrative status of OSPF in the router. */ + if (ospf_admin_stat (ospf)) + return SNMP_INTEGER (OSPF_STATUS_ENABLED); + else + return SNMP_INTEGER (OSPF_STATUS_DISABLED); + break; + case OSPFVERSIONNUMBER: /* 3 */ + /* OSPF version 2. */ + return SNMP_INTEGER (OSPF_VERSION); + break; + case OSPFAREABDRRTRSTATUS: /* 4 */ + /* Area Border router status. */ + if (ospf && CHECK_FLAG (ospf->flags, OSPF_FLAG_ABR)) + return SNMP_INTEGER (SNMP_TRUE); + else + return SNMP_INTEGER (SNMP_FALSE); + break; + case OSPFASBDRRTRSTATUS: /* 5 */ + /* AS Border router status. */ + if (ospf && CHECK_FLAG (ospf->flags, OSPF_FLAG_ASBR)) + return SNMP_INTEGER (SNMP_TRUE); + else + return SNMP_INTEGER (SNMP_FALSE); + break; + case OSPFEXTERNLSACOUNT: /* 6 */ + /* External LSA counts. */ + if (ospf) + return SNMP_INTEGER (ospf_lsdb_count_all (ospf->lsdb)); + else + return SNMP_INTEGER (0); + break; + case OSPFEXTERNLSACKSUMSUM: /* 7 */ + /* External LSA checksum. */ + return SNMP_INTEGER (0); + break; + case OSPFTOSSUPPORT: /* 8 */ + /* TOS is not supported. */ + return SNMP_INTEGER (SNMP_FALSE); + break; + case OSPFORIGINATENEWLSAS: /* 9 */ + /* The number of new link-state advertisements. */ + if (ospf) + return SNMP_INTEGER (ospf->lsa_originate_count); + else + return SNMP_INTEGER (0); + break; + case OSPFRXNEWLSAS: /* 10 */ + /* The number of link-state advertisements received determined + to be new instantiations. */ + if (ospf) + return SNMP_INTEGER (ospf->rx_lsa_count); + else + return SNMP_INTEGER (0); + break; + case OSPFEXTLSDBLIMIT: /* 11 */ + /* There is no limit for the number of non-default + AS-external-LSAs. */ + return SNMP_INTEGER (-1); + break; + case OSPFMULTICASTEXTENSIONS: /* 12 */ + /* Multicast Extensions to OSPF is not supported. */ + return SNMP_INTEGER (0); + break; + case OSPFEXITOVERFLOWINTERVAL: /* 13 */ + /* Overflow is not supported. */ + return SNMP_INTEGER (0); + break; + case OSPFDEMANDEXTENSIONS: /* 14 */ + /* Demand routing is not supported. */ + return SNMP_INTEGER (SNMP_FALSE); + break; + default: + return NULL; + } + return NULL; +} + +struct ospf_area * +ospf_area_lookup_next (struct ospf *ospf, struct in_addr *area_id, int first) +{ + struct ospf_area *area; + listnode node; + + if (ospf == NULL) + return NULL; + + if (first) + { + node = listhead (ospf->areas); + if (node) + { + area = getdata (node); + *area_id = area->area_id; + return area; + } + return NULL; + } + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + + if (ntohl (area->area_id.s_addr) > ntohl (area_id->s_addr)) + { + *area_id = area->area_id; + return area; + } + } + return NULL; +} + +struct ospf_area * +ospfAreaLookup (struct variable *v, oid name[], size_t *length, + struct in_addr *addr, int exact) +{ + struct ospf *ospf; + struct ospf_area *area; + int len; + + ospf = ospf_lookup (); + if (ospf == NULL) + return NULL; + + if (exact) + { + /* Length is insufficient to lookup OSPF area. */ + if (*length - v->namelen != sizeof (struct in_addr)) + return NULL; + + oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); + + area = ospf_area_lookup_by_area_id (ospf, *addr); + + return area; + } + else + { + len = *length - v->namelen; + if (len > 4) + len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + area = ospf_area_lookup_next (ospf, addr, len == 0 ? 1 : 0); + + if (area == NULL) + return NULL; + + oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); + *length = sizeof (struct in_addr) + v->namelen; + + return area; + } + return NULL; +} + +static u_char * +ospfAreaEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_area *area; + struct in_addr addr; + + memset (&addr, 0, sizeof (struct in_addr)); + + area = ospfAreaLookup (v, name, length, &addr, exact); + if (! area) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFAREAID: /* 1 */ + return SNMP_IPADDRESS (area->area_id); + break; + case OSPFAUTHTYPE: /* 2 */ + return SNMP_INTEGER (area->auth_type); + break; + case OSPFIMPORTASEXTERN: /* 3 */ + return SNMP_INTEGER (area->external_routing + 1); + break; + case OSPFSPFRUNS: /* 4 */ + return SNMP_INTEGER (area->spf_calculation); + break; + case OSPFAREABDRRTRCOUNT: /* 5 */ + return SNMP_INTEGER (area->abr_count); + break; + case OSPFASBDRRTRCOUNT: /* 6 */ + return SNMP_INTEGER (area->asbr_count); + break; + case OSPFAREALSACOUNT: /* 7 */ + return SNMP_INTEGER (area->lsdb->total); + break; + case OSPFAREALSACKSUMSUM: /* 8 */ + return SNMP_INTEGER (0); + break; + case OSPFAREASUMMARY: /* 9 */ +#define OSPF_noAreaSummary 1 +#define OSPF_sendAreaSummary 2 + if (area->no_summary) + return SNMP_INTEGER (OSPF_noAreaSummary); + else + return SNMP_INTEGER (OSPF_sendAreaSummary); + break; + case OSPFAREASTATUS: /* 10 */ + return SNMP_INTEGER (SNMP_VALID); + break; + default: + return NULL; + break; + } + return NULL; +} + +struct ospf_area * +ospf_stub_area_lookup_next (struct in_addr *area_id, int first) +{ + struct ospf_area *area; + listnode node; + struct ospf *ospf; + + ospf = ospf_lookup (); + if (ospf == NULL) + return NULL; + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + + if (area->external_routing == OSPF_AREA_STUB) + { + if (first) + { + *area_id = area->area_id; + return area; + } + else if (ntohl (area->area_id.s_addr) > ntohl (area_id->s_addr)) + { + *area_id = area->area_id; + return area; + } + } + } + return NULL; +} + +struct ospf_area * +ospfStubAreaLookup (struct variable *v, oid name[], size_t *length, + struct in_addr *addr, int exact) +{ + struct ospf *ospf; + struct ospf_area *area; + int len; + + ospf = ospf_lookup (); + if (ospf == NULL) + return NULL; + + /* Exact lookup. */ + if (exact) + { + /* ospfStubAreaID + ospfStubTOS. */ + if (*length != v->namelen + sizeof (struct in_addr) + 1) + return NULL; + + /* Check ospfStubTOS is zero. */ + if (name[*length - 1] != 0) + return NULL; + + oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); + + area = ospf_area_lookup_by_area_id (ospf, *addr); + + if (area->external_routing == OSPF_AREA_STUB) + return area; + else + return NULL; + } + else + { + len = *length - v->namelen; + if (len > 4) + len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + area = ospf_stub_area_lookup_next (addr, len == 0 ? 1 : 0); + + if (area == NULL) + return NULL; + + oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); + /* Set TOS 0. */ + name[v->namelen + sizeof (struct in_addr)] = 0; + *length = v->namelen + sizeof (struct in_addr) + 1; + + return area; + } + return NULL; +} + +static u_char * +ospfStubAreaEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + struct ospf_area *area; + struct in_addr addr; + + memset (&addr, 0, sizeof (struct in_addr)); + + area = ospfStubAreaLookup (v, name, length, &addr, exact); + if (! area) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFSTUBAREAID: /* 1 */ + /* OSPF stub area id. */ + return SNMP_IPADDRESS (area->area_id); + break; + case OSPFSTUBTOS: /* 2 */ + /* TOS value is not supported. */ + return SNMP_INTEGER (0); + break; + case OSPFSTUBMETRIC: /* 3 */ + /* Default cost to stub area. */ + return SNMP_INTEGER (area->default_cost); + break; + case OSPFSTUBSTATUS: /* 4 */ + /* Status of the stub area. */ + return SNMP_INTEGER (SNMP_VALID); + break; + case OSPFSTUBMETRICTYPE: /* 5 */ + /* OSPF Metric type. */ +#define OSPF_ospfMetric 1 +#define OSPF_comparableCost 2 +#define OSPF_nonComparable 3 + return SNMP_INTEGER (OSPF_ospfMetric); + break; + default: + return NULL; + break; + } + return NULL; +} + +struct ospf_lsa * +lsdb_lookup_next (struct ospf_area *area, u_char *type, int type_next, + struct in_addr *ls_id, int ls_id_next, + struct in_addr *router_id, int router_id_next) +{ + struct ospf_lsa *lsa; + int i; + + if (type_next) + i = OSPF_MIN_LSA; + else + i = *type; + + for (; i < OSPF_MAX_LSA; i++) + { + *type = i; + + lsa = ospf_lsdb_lookup_by_id_next (area->lsdb, *type, *ls_id, *router_id, + ls_id_next); + if (lsa) + return lsa; + + ls_id_next = 1; + } + return NULL; +} + +struct ospf_lsa * +ospfLsdbLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *area_id, u_char *type, + struct in_addr *ls_id, struct in_addr *router_id, int exact) +{ + struct ospf *ospf; + struct ospf_area *area; + struct ospf_lsa *lsa; + int len; + int type_next; + int ls_id_next; + int router_id_next; + oid *offset; + int offsetlen; + + ospf = ospf_lookup (); + +#define OSPF_LSDB_ENTRY_OFFSET \ + (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE) + + if (exact) + { + /* Area ID + Type + LS ID + Router ID. */ + if (*length - v->namelen != OSPF_LSDB_ENTRY_OFFSET) + return NULL; + + /* Set OID offset for Area ID. */ + offset = name + v->namelen; + + /* Lookup area first. */ + oid2in_addr (offset, IN_ADDR_SIZE, area_id); + area = ospf_area_lookup_by_area_id (ospf, *area_id); + if (! area) + return NULL; + offset += IN_ADDR_SIZE; + + /* Type. */ + *type = *offset; + offset++; + + /* LS ID. */ + oid2in_addr (offset, IN_ADDR_SIZE, ls_id); + offset += IN_ADDR_SIZE; + + /* Router ID. */ + oid2in_addr (offset, IN_ADDR_SIZE, router_id); + + /* Lookup LSDB. */ + return ospf_lsdb_lookup_by_id (area->lsdb, *type, *ls_id, *router_id); + } + else + { + /* Get variable length. */ + offset = name + v->namelen; + offsetlen = *length - v->namelen; + len = offsetlen; + + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, area_id); + + /* First we search area. */ + if (len == IN_ADDR_SIZE) + area = ospf_area_lookup_by_area_id (ospf, *area_id); + else + area = ospf_area_lookup_next (ospf, area_id, len == 0 ? 1 : 0); + + if (area == NULL) + return NULL; + + do + { + /* Next we lookup type. */ + offset += IN_ADDR_SIZE; + offsetlen -= IN_ADDR_SIZE; + len = offsetlen; + + if (len <= 0) + type_next = 1; + else + { + len = 1; + type_next = 0; + *type = *offset; + } + + /* LS ID. */ + offset++; + offsetlen--; + len = offsetlen; + + if (len <= 0) + ls_id_next = 1; + else + { + ls_id_next = 0; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, ls_id); + } + + /* Router ID. */ + offset += IN_ADDR_SIZE; + offsetlen -= IN_ADDR_SIZE; + len = offsetlen; + + if (len <= 0) + router_id_next = 1; + else + { + router_id_next = 0; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, router_id); + } + + lsa = lsdb_lookup_next (area, type, type_next, ls_id, ls_id_next, + router_id, router_id_next); + + if (lsa) + { + /* Fill in length. */ + *length = v->namelen + OSPF_LSDB_ENTRY_OFFSET; + + /* Fill in value. */ + offset = name + v->namelen; + oid_copy_addr (offset, area_id, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + *offset = lsa->data->type; + offset++; + oid_copy_addr (offset, &lsa->data->id, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + oid_copy_addr (offset, &lsa->data->adv_router, IN_ADDR_SIZE); + + return lsa; + } + } + while ((area = ospf_area_lookup_next (ospf, area_id, 0)) != NULL); + } + return NULL; +} + +static u_char * +ospfLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_lsa *lsa; + struct lsa_header *lsah; + struct in_addr area_id; + u_char type; + struct in_addr ls_id; + struct in_addr router_id; + struct ospf *ospf; + + /* INDEX { ospfLsdbAreaId, ospfLsdbType, + ospfLsdbLsid, ospfLsdbRouterId } */ + + memset (&area_id, 0, sizeof (struct in_addr)); + type = 0; + memset (&ls_id, 0, sizeof (struct in_addr)); + memset (&router_id, 0, sizeof (struct in_addr)); + + /* Check OSPF instance. */ + ospf = ospf_lookup (); + if (ospf == NULL) + return NULL; + + lsa = ospfLsdbLookup (v, name, length, &area_id, &type, &ls_id, &router_id, + exact); + if (! lsa) + return NULL; + + lsah = lsa->data; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFLSDBAREAID: /* 1 */ + return SNMP_IPADDRESS (lsa->area->area_id); + break; + case OSPFLSDBTYPE: /* 2 */ + return SNMP_INTEGER (lsah->type); + break; + case OSPFLSDBLSID: /* 3 */ + return SNMP_IPADDRESS (lsah->id); + break; + case OSPFLSDBROUTERID: /* 4 */ + return SNMP_IPADDRESS (lsah->adv_router); + break; + case OSPFLSDBSEQUENCE: /* 5 */ + return SNMP_INTEGER (lsah->ls_seqnum); + break; + case OSPFLSDBAGE: /* 6 */ + return SNMP_INTEGER (lsah->ls_age); + break; + case OSPFLSDBCHECKSUM: /* 7 */ + return SNMP_INTEGER (lsah->checksum); + break; + case OSPFLSDBADVERTISEMENT: /* 8 */ + *var_len = ntohs (lsah->length); + return (u_char *) lsah; + break; + default: + return NULL; + break; + } + return NULL; +} + +struct ospf_area_range * +ospfAreaRangeLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *area_id, struct in_addr *range_net, + int exact) +{ + oid *offset; + int offsetlen; + int len; + struct ospf *ospf; + struct ospf_area *area; + struct ospf_area_range *range; + struct prefix_ipv4 p; + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + + ospf = ospf_lookup (); + + if (exact) + { + /* Area ID + Range Network. */ + if (v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE != *length) + return NULL; + + /* Set OID offset for Area ID. */ + offset = name + v->namelen; + + /* Lookup area first. */ + oid2in_addr (offset, IN_ADDR_SIZE, area_id); + + area = ospf_area_lookup_by_area_id (ospf, *area_id); + if (! area) + return NULL; + + offset += IN_ADDR_SIZE; + + /* Lookup area range. */ + oid2in_addr (offset, IN_ADDR_SIZE, range_net); + p.prefix = *range_net; + + return ospf_area_range_lookup (area, &p); + } + else + { + /* Set OID offset for Area ID. */ + offset = name + v->namelen; + offsetlen = *length - v->namelen; + + len = offsetlen; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, area_id); + + /* First we search area. */ + if (len == IN_ADDR_SIZE) + area = ospf_area_lookup_by_area_id (ospf,*area_id); + else + area = ospf_area_lookup_next (ospf, area_id, len == 0 ? 1 : 0); + + if (area == NULL) + return NULL; + + do + { + offset += IN_ADDR_SIZE; + offsetlen -= IN_ADDR_SIZE; + len = offsetlen; + + if (len < 0) + len = 0; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, range_net); + + range = ospf_area_range_lookup_next (area, range_net, + len == 0 ? 1 : 0); + + if (range) + { + /* Fill in length. */ + *length = v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE; + + /* Fill in value. */ + offset = name + v->namelen; + oid_copy_addr (offset, area_id, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + oid_copy_addr (offset, range_net, IN_ADDR_SIZE); + + return range; + } + } + while ((area = ospf_area_lookup_next (ospf, area_id, 0)) != NULL); + } + return NULL; +} + +static u_char * +ospfAreaRangeEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_area_range *range; + struct in_addr area_id; + struct in_addr range_net; + struct in_addr mask; + struct ospf *ospf; + + /* Check OSPF instance. */ + ospf = ospf_lookup (); + if (ospf == NULL) + return NULL; + + memset (&area_id, 0, IN_ADDR_SIZE); + memset (&range_net, 0, IN_ADDR_SIZE); + + range = ospfAreaRangeLookup (v, name, length, &area_id, &range_net, exact); + if (! range) + return NULL; + + /* Convert prefixlen to network mask format. */ + masklen2ip (range->subst_masklen, &mask); + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFAREARANGEAREAID: /* 1 */ + return SNMP_IPADDRESS (area_id); + break; + case OSPFAREARANGENET: /* 2 */ + return SNMP_IPADDRESS (range_net); + break; + case OSPFAREARANGEMASK: /* 3 */ + return SNMP_IPADDRESS (mask); + break; + case OSPFAREARANGESTATUS: /* 4 */ + return SNMP_INTEGER (SNMP_VALID); + break; + case OSPFAREARANGEEFFECT: /* 5 */ +#define OSPF_advertiseMatching 1 +#define OSPF_doNotAdvertiseMatching 2 + return SNMP_INTEGER (OSPF_advertiseMatching); + break; + default: + return NULL; + break; + } + return NULL; +} + +struct ospf_nbr_nbma * +ospf_nbr_nbma_lookup_next (struct ospf *ospf, struct in_addr *nbr_addr, + int first) +{ + struct route_node *rn; + struct ospf_nbr_nbma *nbr_nbma; + struct ospf_nbr_nbma *min = NULL; + + for (rn = route_top (ospf->nbr_nbma); rn; rn = route_next (rn)) + if ((nbr_nbma = rn->info) != NULL + && nbr_nbma->nbr != nbr_nbma->oi->nbr_self /* just make sure */ + && nbr_nbma->nbr->state != NSM_Down /* xxx */ + && nbr_nbma->addr.s_addr != 0) + { + if (first) + { + if (! min) + min = nbr_nbma; + else if (ntohl (nbr_nbma->addr.s_addr) < ntohl (min->addr.s_addr)) + min = nbr_nbma; + } + else if (ntohl (nbr_nbma->addr.s_addr) > ntohl (nbr_addr->s_addr)) + { + if (! min) + min = nbr_nbma; + else if (ntohl (nbr_nbma->addr.s_addr) < ntohl (min->addr.s_addr)) + min = nbr_nbma; + } + } + + if (min) + { + *nbr_addr = min->addr; + return min; + } + + return NULL; +} + +struct ospf_nbr_nbma * +ospfHostLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *addr, int exact) +{ + int len; + struct ospf_nbr_nbma *nbr_nbma; + struct ospf *ospf; + + ospf = ospf_lookup (); + if (ospf == NULL) + return NULL; + + if (exact) + { + /* INDEX { ospfHostIpAddress, ospfHostTOS } */ + if (*length != v->namelen + IN_ADDR_SIZE + 1) + return NULL; + + /* Check ospfHostTOS. */ + if (name[*length - 1] != 0) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, addr); + + nbr_nbma = ospf_nbr_nbma_lookup (ospf, *addr); + + return nbr_nbma; + } + else + { + len = *length - v->namelen; + if (len > 4) + len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + nbr_nbma = ospf_nbr_nbma_lookup_next (ospf, addr, len == 0 ? 1 : 0); + + if (nbr_nbma == NULL) + return NULL; + + oid_copy_addr (name + v->namelen, addr, IN_ADDR_SIZE); + + /* Set TOS 0. */ + name[v->namelen + IN_ADDR_SIZE] = 0; + + *length = v->namelen + IN_ADDR_SIZE + 1; + + return nbr_nbma; + } + return NULL; +} + +static u_char * +ospfHostEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_nbr_nbma *nbr_nbma; + struct ospf_interface *oi; + struct in_addr addr; + struct ospf *ospf; + + /* Check OSPF instance. */ + ospf = ospf_lookup (); + if (ospf == NULL) + return NULL; + + memset (&addr, 0, sizeof (struct in_addr)); + + nbr_nbma = ospfHostLookup (v, name, length, &addr, exact); + if (nbr_nbma == NULL) + return NULL; + + oi = nbr_nbma->oi; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFHOSTIPADDRESS: /* 1 */ + return SNMP_IPADDRESS (nbr_nbma->addr); + break; + case OSPFHOSTTOS: /* 2 */ + return SNMP_INTEGER (0); + break; + case OSPFHOSTMETRIC: /* 3 */ + if (oi) + return SNMP_INTEGER (oi->output_cost); + else + return SNMP_INTEGER (1); + break; + case OSPFHOSTSTATUS: /* 4 */ + return SNMP_INTEGER (SNMP_VALID); + break; + case OSPFHOSTAREAID: /* 5 */ + if (oi && oi->area) + return SNMP_IPADDRESS (oi->area->area_id); + else + return SNMP_IPADDRESS (ospf_empty_addr); + break; + default: + return NULL; + break; + } + return NULL; +} + +struct list *ospf_snmp_iflist; + +struct ospf_snmp_if +{ + struct in_addr addr; + unsigned int ifindex; + struct interface *ifp; +}; + +struct ospf_snmp_if * +ospf_snmp_if_new () +{ + struct ospf_snmp_if *osif; + + osif = XMALLOC (0, sizeof (struct ospf_snmp_if)); + memset (osif, 0, sizeof (struct ospf_snmp_if)); + return osif; +} + +void +ospf_snmp_if_free (struct ospf_snmp_if *osif) +{ + XFREE (0, osif); +} + +void +ospf_snmp_if_delete (struct interface *ifp) +{ + struct listnode *nn; + struct ospf_snmp_if *osif; + + LIST_LOOP (ospf_snmp_iflist, osif, nn) + { + if (osif->ifp == ifp) + { + list_delete_node (ospf_snmp_iflist, nn); + ospf_snmp_if_free (osif); + return; + } + } +} + +void +ospf_snmp_if_update (struct interface *ifp) +{ + struct listnode *nn; + struct listnode *pn; + struct connected *ifc; + struct prefix *p; + struct ospf_snmp_if *osif; + struct in_addr *addr; + unsigned int ifindex; + + ospf_snmp_if_delete (ifp); + + p = NULL; + addr = NULL; + ifindex = 0; + + /* Lookup first IPv4 address entry. */ + LIST_LOOP (ifp->connected, ifc, nn) + { + if (if_is_pointopoint (ifp)) + p = ifc->destination; + else + p = ifc->address; + + if (p->family == AF_INET) + { + addr = &p->u.prefix4; + break; + } + } + if (! addr) + ifindex = ifp->ifindex; + + /* Add interface to the list. */ + pn = NULL; + LIST_LOOP (ospf_snmp_iflist, osif, nn) + { + if (addr) + { + if (ntohl (osif->addr.s_addr) > ntohl (addr->s_addr)) + break; + } + else + { + /* Unnumbered interface. */ + if (osif->addr.s_addr != 0 || osif->ifindex > ifindex) + break; + } + pn = nn; + } + + osif = ospf_snmp_if_new (); + if (addr) + osif->addr = *addr; + else + osif->ifindex = ifindex; + osif->ifp = ifp; + + listnode_add_after (ospf_snmp_iflist, pn, osif); +} + +struct interface * +ospf_snmp_if_lookup (struct in_addr *ifaddr, unsigned int *ifindex) +{ + struct listnode *nn; + struct ospf_snmp_if *osif; + + LIST_LOOP (ospf_snmp_iflist, osif, nn) + { + if (ifaddr->s_addr) + { + if (IPV4_ADDR_SAME (&osif->addr, ifaddr)) + return osif->ifp; + } + else + { + if (osif->ifindex == *ifindex) + return osif->ifp; + } + } + return NULL; +} + +struct interface * +ospf_snmp_if_lookup_next (struct in_addr *ifaddr, unsigned int *ifindex, + int ifaddr_next, int ifindex_next) +{ + struct ospf_snmp_if *osif; + struct listnode *nn; + + if (ifaddr_next) + { + nn = listhead (ospf_snmp_iflist); + if (nn) + { + osif = getdata (nn); + *ifaddr = osif->addr; + *ifindex = osif->ifindex; + return osif->ifp; + } + return NULL; + } + + LIST_LOOP (ospf_snmp_iflist, osif, nn) + { + if (ifaddr->s_addr) + { + if (ntohl (osif->addr.s_addr) > ntohl (ifaddr->s_addr)) + { + *ifaddr = osif->addr; + *ifindex = osif->ifindex; + return osif->ifp; + } + } + else + { + if (osif->ifindex > *ifindex || osif->addr.s_addr) + { + *ifaddr = osif->addr; + *ifindex = osif->ifindex; + return osif->ifp; + } + } + } + return NULL; +} + +int +ospf_snmp_iftype (struct interface *ifp) +{ +#define ospf_snmp_iftype_broadcast 1 +#define ospf_snmp_iftype_nbma 2 +#define ospf_snmp_iftype_pointToPoint 3 +#define ospf_snmp_iftype_pointToMultipoint 5 + if (if_is_broadcast (ifp)) + return ospf_snmp_iftype_broadcast; + if (if_is_pointopoint (ifp)) + return ospf_snmp_iftype_pointToPoint; + return ospf_snmp_iftype_broadcast; +} + +struct interface * +ospfIfLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *ifaddr, unsigned int *ifindex, int exact) +{ + int len; + int ifaddr_next = 0; + int ifindex_next = 0; + struct interface *ifp; + oid *offset; + + if (exact) + { + if (*length != v->namelen + IN_ADDR_SIZE + 1) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, ifaddr); + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + + return ospf_snmp_if_lookup (ifaddr, ifindex); + } + else + { + len = *length - v->namelen; + if (len >= IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + if (len <= 0) + ifaddr_next = 1; + + oid2in_addr (name + v->namelen, len, ifaddr); + + len = *length - v->namelen - IN_ADDR_SIZE; + if (len >= 1) + len = 1; + else + ifindex_next = 1; + + if (len == 1) + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + + ifp = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next, + ifindex_next); + if (ifp) + { + *length = v->namelen + IN_ADDR_SIZE + 1; + offset = name + v->namelen; + oid_copy_addr (offset, ifaddr, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + *offset = *ifindex; + return ifp; + } + } + return NULL; +} + +static u_char * +ospfIfEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct interface *ifp; + unsigned int ifindex; + struct in_addr ifaddr; + struct ospf_interface *oi; + struct ospf *ospf; + + ifindex = 0; + memset (&ifaddr, 0, sizeof (struct in_addr)); + + /* Check OSPF instance. */ + ospf = ospf_lookup (); + if (ospf == NULL) + return NULL; + + ifp = ospfIfLookup (v, name, length, &ifaddr, &ifindex, exact); + if (ifp == NULL) + return NULL; + + oi = ospf_if_lookup_by_local_addr (ospf, ifp, ifaddr); + if (oi == NULL) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFIFIPADDRESS: /* 1 */ + return SNMP_IPADDRESS (ifaddr); + break; + case OSPFADDRESSLESSIF: /* 2 */ + return SNMP_INTEGER (ifindex); + break; + case OSPFIFAREAID: /* 3 */ + if (oi->area) + return SNMP_IPADDRESS (oi->area->area_id); + else + return SNMP_IPADDRESS (ospf_empty_addr); + break; + case OSPFIFTYPE: /* 4 */ + return SNMP_INTEGER (ospf_snmp_iftype (ifp)); + break; + case OSPFIFADMINSTAT: /* 5 */ + if (oi) + return SNMP_INTEGER (OSPF_STATUS_ENABLED); + else + return SNMP_INTEGER (OSPF_STATUS_DISABLED); + break; + case OSPFIFRTRPRIORITY: /* 6 */ + return SNMP_INTEGER (PRIORITY (oi)); + break; + case OSPFIFTRANSITDELAY: /* 7 */ + return SNMP_INTEGER (OSPF_IF_PARAM (oi, transmit_delay)); + break; + case OSPFIFRETRANSINTERVAL: /* 8 */ + return SNMP_INTEGER (OSPF_IF_PARAM (oi, retransmit_interval)); + break; + case OSPFIFHELLOINTERVAL: /* 9 */ + return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_hello)); + break; + case OSPFIFRTRDEADINTERVAL: /* 10 */ + return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_wait)); + break; + case OSPFIFPOLLINTERVAL: /* 11 */ + return SNMP_INTEGER (OSPF_POLL_INTERVAL_DEFAULT); + break; + case OSPFIFSTATE: /* 12 */ + return SNMP_INTEGER (oi->state); + break; + case OSPFIFDESIGNATEDROUTER: /* 13 */ + return SNMP_IPADDRESS (DR (oi)); + break; + case OSPFIFBACKUPDESIGNATEDROUTER: /* 14 */ + return SNMP_IPADDRESS (BDR (oi)); + break; + case OSPFIFEVENTS: /* 15 */ + return SNMP_INTEGER (oi->state_change); + break; + case OSPFIFAUTHKEY: /* 16 */ + *var_len = 0; + return (u_char *) OSPF_IF_PARAM (oi, auth_simple); + break; + case OSPFIFSTATUS: /* 17 */ + return SNMP_INTEGER (SNMP_VALID); + break; + case OSPFIFMULTICASTFORWARDING: /* 18 */ +#define ospf_snmp_multiforward_blocked 1 +#define ospf_snmp_multiforward_multicast 2 +#define ospf_snmp_multiforward_unicast 3 + return SNMP_INTEGER (ospf_snmp_multiforward_blocked); + break; + case OSPFIFDEMAND: /* 19 */ + return SNMP_INTEGER (SNMP_FALSE); + break; + case OSPFIFAUTHTYPE: /* 20 */ + if (oi->area) + return SNMP_INTEGER (oi->area->auth_type); + else + return SNMP_INTEGER (0); + break; + default: + return NULL; + break; + } + return NULL; +} + +#define OSPF_SNMP_METRIC_VALUE 1 + +struct interface * +ospfIfMetricLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *ifaddr, unsigned int *ifindex, int exact) +{ + int len; + int ifaddr_next = 0; + int ifindex_next = 0; + struct interface *ifp; + oid *offset; + int metric; + + if (exact) + { + if (*length != v->namelen + IN_ADDR_SIZE + 1 + 1) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, ifaddr); + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + metric = name[v->namelen + IN_ADDR_SIZE + 1]; + + if (metric != OSPF_SNMP_METRIC_VALUE) + return NULL; + + return ospf_snmp_if_lookup (ifaddr, ifindex); + } + else + { + len = *length - v->namelen; + if (len >= IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + else + ifaddr_next = 1; + + oid2in_addr (name + v->namelen, len, ifaddr); + + len = *length - v->namelen - IN_ADDR_SIZE; + if (len >= 1) + len = 1; + else + ifindex_next = 1; + + if (len == 1) + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + + ifp = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next, + ifindex_next); + if (ifp) + { + *length = v->namelen + IN_ADDR_SIZE + 1 + 1; + offset = name + v->namelen; + oid_copy_addr (offset, ifaddr, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + *offset = *ifindex; + offset++; + *offset = OSPF_SNMP_METRIC_VALUE; + return ifp; + } + } + return NULL; +} + +static u_char * +ospfIfMetricEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + /* Currently we support metric 1 only. */ + struct interface *ifp; + unsigned int ifindex; + struct in_addr ifaddr; + struct ospf_interface *oi; + struct ospf *ospf; + + ifindex = 0; + memset (&ifaddr, 0, sizeof (struct in_addr)); + + /* Check OSPF instance. */ + ospf = ospf_lookup (); + if (ospf == NULL) + return NULL; + + ifp = ospfIfMetricLookup (v, name, length, &ifaddr, &ifindex, exact); + if (ifp == NULL) + return NULL; + + oi = ospf_if_lookup_by_local_addr (ospf, ifp, ifaddr); + if (oi == NULL) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFIFMETRICIPADDRESS: + return SNMP_IPADDRESS (ifaddr); + break; + case OSPFIFMETRICADDRESSLESSIF: + return SNMP_INTEGER (ifindex); + break; + case OSPFIFMETRICTOS: + return SNMP_INTEGER (0); + break; + case OSPFIFMETRICVALUE: + return SNMP_INTEGER (OSPF_SNMP_METRIC_VALUE); + break; + case OSPFIFMETRICSTATUS: + return SNMP_INTEGER (1); + break; + default: + return NULL; + break; + } + return NULL; +} + +struct route_table *ospf_snmp_vl_table; + +void +ospf_snmp_vl_add (struct ospf_vl_data *vl_data) +{ + struct prefix_ls lp; + struct route_node *rn; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = vl_data->vl_area_id; + lp.adv_router = vl_data->vl_peer; + + rn = route_node_get (ospf_snmp_vl_table, (struct prefix *) &lp); + rn->info = vl_data; +} + +void +ospf_snmp_vl_delete (struct ospf_vl_data *vl_data) +{ + struct prefix_ls lp; + struct route_node *rn; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = vl_data->vl_area_id; + lp.adv_router = vl_data->vl_peer; + + rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp); + if (! rn) + return; + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); +} + +struct ospf_vl_data * +ospf_snmp_vl_lookup (struct in_addr *area_id, struct in_addr *neighbor) +{ + struct prefix_ls lp; + struct route_node *rn; + struct ospf_vl_data *vl_data; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = *area_id; + lp.adv_router = *neighbor; + + rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp); + if (rn) + { + vl_data = rn->info; + route_unlock_node (rn); + return vl_data; + } + return NULL; +} + +struct ospf_vl_data * +ospf_snmp_vl_lookup_next (struct in_addr *area_id, struct in_addr *neighbor, + int first) +{ + struct prefix_ls lp; + struct route_node *rn; + struct ospf_vl_data *vl_data; + + memset (&lp, 0, sizeof (struct prefix_ls)); + lp.family = 0; + lp.prefixlen = 64; + lp.id = *area_id; + lp.adv_router = *neighbor; + + if (first) + rn = route_top (ospf_snmp_vl_table); + else + { + rn = route_node_get (ospf_snmp_vl_table, (struct prefix *) &lp); + rn = route_next (rn); + } + + for (; rn; rn = route_next (rn)) + if (rn->info) + break; + + if (rn && rn->info) + { + vl_data = rn->info; + *area_id = vl_data->vl_area_id; + *neighbor = vl_data->vl_peer; + route_unlock_node (rn); + return vl_data; + } + return NULL; +} + +struct ospf_vl_data * +ospfVirtIfLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *area_id, struct in_addr *neighbor, int exact) +{ + int first; + int len; + struct ospf_vl_data *vl_data; + + if (exact) + { + if (*length != v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, area_id); + oid2in_addr (name + v->namelen + IN_ADDR_SIZE, IN_ADDR_SIZE, neighbor); + + return ospf_snmp_vl_lookup (area_id, neighbor); + } + else + { + first = 0; + + len = *length - v->namelen; + if (len <= 0) + first = 1; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + oid2in_addr (name + v->namelen, len, area_id); + + len = *length - v->namelen - IN_ADDR_SIZE; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + oid2in_addr (name + v->namelen + IN_ADDR_SIZE, len, neighbor); + + vl_data = ospf_snmp_vl_lookup_next (area_id, neighbor, first); + + if (vl_data) + { + *length = v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE; + oid_copy_addr (name + v->namelen, area_id, IN_ADDR_SIZE); + oid_copy_addr (name + v->namelen + IN_ADDR_SIZE, neighbor, + IN_ADDR_SIZE); + return vl_data; + } + } + return NULL; +} + +static u_char * +ospfVirtIfEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_vl_data *vl_data; + struct ospf_interface *oi; + struct in_addr area_id; + struct in_addr neighbor; + + memset (&area_id, 0, sizeof (struct in_addr)); + memset (&neighbor, 0, sizeof (struct in_addr)); + + vl_data = ospfVirtIfLookup (v, name, length, &area_id, &neighbor, exact); + if (! vl_data) + return NULL; + oi = vl_data->vl_oi; + if (! oi) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFVIRTIFAREAID: + return SNMP_IPADDRESS (area_id); + break; + case OSPFVIRTIFNEIGHBOR: + return SNMP_IPADDRESS (neighbor); + break; + case OSPFVIRTIFTRANSITDELAY: + return SNMP_INTEGER (OSPF_IF_PARAM (oi, transmit_delay)); + break; + case OSPFVIRTIFRETRANSINTERVAL: + return SNMP_INTEGER (OSPF_IF_PARAM (oi, retransmit_interval)); + break; + case OSPFVIRTIFHELLOINTERVAL: + return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_hello)); + break; + case OSPFVIRTIFRTRDEADINTERVAL: + return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_wait)); + break; + case OSPFVIRTIFSTATE: + return SNMP_INTEGER (oi->state); + break; + case OSPFVIRTIFEVENTS: + return SNMP_INTEGER (oi->state_change); + break; + case OSPFVIRTIFAUTHKEY: + *var_len = 0; + return (u_char *) OSPF_IF_PARAM (oi, auth_simple); + break; + case OSPFVIRTIFSTATUS: + return SNMP_INTEGER (SNMP_VALID); + break; + case OSPFVIRTIFAUTHTYPE: + if (oi->area) + return SNMP_INTEGER (oi->area->auth_type); + else + return SNMP_INTEGER (0); + break; + default: + return NULL; + break; + } + return NULL; +} + +struct ospf_neighbor * +ospf_snmp_nbr_lookup (struct ospf *ospf, struct in_addr *nbr_addr, + unsigned int *ifindex) +{ + struct listnode *nn; + struct ospf_interface *oi; + struct ospf_neighbor *nbr; + struct route_node *rn; + + LIST_LOOP (ospf->oiflist, oi, nn) + { + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL + && nbr != oi->nbr_self + && nbr->state != NSM_Down + && nbr->src.s_addr != 0) + { + if (IPV4_ADDR_SAME (&nbr->src, nbr_addr)) + { + route_unlock_node (rn); + return nbr; + } + } + } + return NULL; +} + +struct ospf_neighbor * +ospf_snmp_nbr_lookup_next (struct in_addr *nbr_addr, unsigned int *ifindex, + int first) +{ + struct listnode *nn; + struct ospf_interface *oi; + struct ospf_neighbor *nbr; + struct route_node *rn; + struct ospf_neighbor *min = NULL; + struct ospf *ospf = ospf; + + ospf = ospf_lookup (); + LIST_LOOP (ospf->oiflist, oi, nn) + { + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info) != NULL + && nbr != oi->nbr_self + && nbr->state != NSM_Down + && nbr->src.s_addr != 0) + { + if (first) + { + if (! min) + min = nbr; + else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr)) + min = nbr; + } + else if (ntohl (nbr->src.s_addr) > ntohl (nbr_addr->s_addr)) + { + if (! min) + min = nbr; + else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr)) + min = nbr; + } + } + } + if (min) + { + *nbr_addr = min->src; + *ifindex = 0; + return min; + } + return NULL; +} + +struct ospf_neighbor * +ospfNbrLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *nbr_addr, unsigned int *ifindex, int exact) +{ + int len; + int first; + struct ospf_neighbor *nbr; + struct ospf *ospf; + + ospf = ospf_lookup (); + + if (exact) + { + if (*length != v->namelen + IN_ADDR_SIZE + 1) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, nbr_addr); + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + + return ospf_snmp_nbr_lookup (ospf, nbr_addr, ifindex); + } + else + { + first = 0; + len = *length - v->namelen; + + if (len <= 0) + first = 1; + + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (name + v->namelen, len, nbr_addr); + + len = *length - v->namelen - IN_ADDR_SIZE; + if (len >= 1) + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + + nbr = ospf_snmp_nbr_lookup_next (nbr_addr, ifindex, first); + + if (nbr) + { + *length = v->namelen + IN_ADDR_SIZE + 1; + oid_copy_addr (name + v->namelen, nbr_addr, IN_ADDR_SIZE); + name[v->namelen + IN_ADDR_SIZE] = *ifindex; + return nbr; + } + } + return NULL; +} + +static u_char * +ospfNbrEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct in_addr nbr_addr; + unsigned int ifindex; + struct ospf_neighbor *nbr; + struct ospf_interface *oi; + + memset (&nbr_addr, 0, sizeof (struct in_addr)); + ifindex = 0; + + nbr = ospfNbrLookup (v, name, length, &nbr_addr, &ifindex, exact); + if (! nbr) + return NULL; + oi = nbr->oi; + if (! oi) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFNBRIPADDR: + return SNMP_IPADDRESS (nbr_addr); + break; + case OSPFNBRADDRESSLESSINDEX: + return SNMP_INTEGER (ifindex); + break; + case OSPFNBRRTRID: + return SNMP_IPADDRESS (nbr->router_id); + break; + case OSPFNBROPTIONS: + return SNMP_INTEGER (oi->nbr_self->options); + break; + case OSPFNBRPRIORITY: + return SNMP_INTEGER (nbr->priority); + break; + case OSPFNBRSTATE: + return SNMP_INTEGER (nbr->state); + break; + case OSPFNBREVENTS: + return SNMP_INTEGER (nbr->state_change); + break; + case OSPFNBRLSRETRANSQLEN: + return SNMP_INTEGER (ospf_ls_retransmit_count (nbr)); + break; + case OSPFNBMANBRSTATUS: + return SNMP_INTEGER (SNMP_VALID); + break; + case OSPFNBMANBRPERMANENCE: + return SNMP_INTEGER (2); + break; + case OSPFNBRHELLOSUPPRESSED: + return SNMP_INTEGER (SNMP_FALSE); + break; + default: + return NULL; + break; + } + return NULL; +} + +static u_char * +ospfVirtNbrEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_vl_data *vl_data; + struct in_addr area_id; + struct in_addr neighbor; + struct ospf *ospf; + + memset (&area_id, 0, sizeof (struct in_addr)); + memset (&neighbor, 0, sizeof (struct in_addr)); + + /* Check OSPF instance. */ + ospf = ospf_lookup (); + if (ospf == NULL) + return NULL; + + vl_data = ospfVirtIfLookup (v, name, length, &area_id, &neighbor, exact); + if (! vl_data) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFVIRTNBRAREA: + return (u_char *) NULL; + break; + case OSPFVIRTNBRRTRID: + return (u_char *) NULL; + break; + case OSPFVIRTNBRIPADDR: + return (u_char *) NULL; + break; + case OSPFVIRTNBROPTIONS: + return (u_char *) NULL; + break; + case OSPFVIRTNBRSTATE: + return (u_char *) NULL; + break; + case OSPFVIRTNBREVENTS: + return (u_char *) NULL; + break; + case OSPFVIRTNBRLSRETRANSQLEN: + return (u_char *) NULL; + break; + case OSPFVIRTNBRHELLOSUPPRESSED: + return (u_char *) NULL; + break; + default: + return NULL; + break; + } + return NULL; +} + +struct ospf_lsa * +ospfExtLsdbLookup (struct variable *v, oid *name, size_t *length, u_char *type, + struct in_addr *ls_id, struct in_addr *router_id, int exact) +{ + int first; + oid *offset; + int offsetlen; + u_char lsa_type; + int len; + struct ospf_lsa *lsa; + struct ospf *ospf; + + ospf = ospf_lookup (); + if (exact) + { + if (*length != v->namelen + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE) + return NULL; + + offset = name + v->namelen; + + /* Make it sure given value match to type. */ + lsa_type = *offset; + offset++; + + if (lsa_type != *type) + return NULL; + + /* LS ID. */ + oid2in_addr (offset, IN_ADDR_SIZE, ls_id); + offset += IN_ADDR_SIZE; + + /* Router ID. */ + oid2in_addr (offset, IN_ADDR_SIZE, router_id); + + return ospf_lsdb_lookup_by_id (ospf->lsdb, *type, *ls_id, *router_id); + } + else + { + /* Get variable length. */ + first = 0; + offset = name + v->namelen; + offsetlen = *length - v->namelen; + + /* LSA type value. */ + lsa_type = *offset; + offset++; + offsetlen--; + + if (offsetlen <= 0 || lsa_type < OSPF_AS_EXTERNAL_LSA) + first = 1; + + /* LS ID. */ + len = offsetlen; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, ls_id); + + offset += IN_ADDR_SIZE; + offsetlen -= IN_ADDR_SIZE; + + /* Router ID. */ + len = offsetlen; + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (offset, len, router_id); + + lsa = ospf_lsdb_lookup_by_id_next (ospf->lsdb, *type, *ls_id, + *router_id, first); + + if (lsa) + { + /* Fill in length. */ + *length = v->namelen + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE; + + /* Fill in value. */ + offset = name + v->namelen; + + *offset = OSPF_AS_EXTERNAL_LSA; + offset++; + oid_copy_addr (offset, &lsa->data->id, IN_ADDR_SIZE); + offset += IN_ADDR_SIZE; + oid_copy_addr (offset, &lsa->data->adv_router, IN_ADDR_SIZE); + + return lsa; + } + } + return NULL; +} + +static u_char * +ospfExtLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, + size_t *var_len, WriteMethod **write_method) +{ + struct ospf_lsa *lsa; + struct lsa_header *lsah; + u_char type; + struct in_addr ls_id; + struct in_addr router_id; + struct ospf *ospf; + + type = OSPF_AS_EXTERNAL_LSA; + memset (&ls_id, 0, sizeof (struct in_addr)); + memset (&router_id, 0, sizeof (struct in_addr)); + + /* Check OSPF instance. */ + ospf = ospf_lookup (); + if (ospf == NULL) + return NULL; + + lsa = ospfExtLsdbLookup (v, name, length, &type, &ls_id, &router_id, exact); + if (! lsa) + return NULL; + + lsah = lsa->data; + + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFEXTLSDBTYPE: + return SNMP_INTEGER (OSPF_AS_EXTERNAL_LSA); + break; + case OSPFEXTLSDBLSID: + return SNMP_IPADDRESS (lsah->id); + break; + case OSPFEXTLSDBROUTERID: + return SNMP_IPADDRESS (lsah->adv_router); + break; + case OSPFEXTLSDBSEQUENCE: + return SNMP_INTEGER (lsah->ls_seqnum); + break; + case OSPFEXTLSDBAGE: + return SNMP_INTEGER (lsah->ls_age); + break; + case OSPFEXTLSDBCHECKSUM: + return SNMP_INTEGER (lsah->checksum); + break; + case OSPFEXTLSDBADVERTISEMENT: + *var_len = ntohs (lsah->length); + return (u_char *) lsah; + break; + default: + return NULL; + break; + } + return NULL; +} + +static u_char * +ospfAreaAggregateEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + /* Return the current value of the variable */ + switch (v->magic) + { + case OSPFAREAAGGREGATEAREAID: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATELSDBTYPE: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATENET: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATEMASK: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATESTATUS: + return (u_char *) NULL; + break; + case OSPFAREAAGGREGATEEFFECT: + return (u_char *) NULL; + break; + default: + return NULL; + break; + } + return NULL; +} + +/* Register OSPF2-MIB. */ +void +ospf_snmp_init () +{ + ospf_snmp_iflist = list_new (); + ospf_snmp_vl_table = route_table_init (); + smux_init (ospfd_oid, sizeof (ospfd_oid) / sizeof (oid)); + REGISTER_MIB("mibII/ospf", ospf_variables, variable, ospf_oid); + smux_start (); +} +#endif /* HAVE_SNMP */ diff --git a/ospfd/ospf_snmp.h b/ospfd/ospf_snmp.h new file mode 100644 index 0000000..d82f87b --- /dev/null +++ b/ospfd/ospf_snmp.h @@ -0,0 +1,33 @@ +/* OSPFv2 SNMP support + * Copyright (C) 2000 IP Infusion Inc. + * + * Written by Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_SNMP_H +#define _ZEBRA_OSPF_SNMP_H + +void ospf_snmp_if_update (struct interface *); +void ospf_snmp_if_delete (struct interface *); + +void ospf_snmp_vl_add (struct ospf_vl_data *); +void ospf_snmp_vl_delete (struct ospf_vl_data *); + +#endif /* _ZEBRA_OSPF_SNMP_H */ diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c new file mode 100644 index 0000000..412e44d --- /dev/null +++ b/ospfd/ospf_spf.c @@ -0,0 +1,1110 @@ +/* OSPF SPF calculation. + Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "thread.h" +#include "memory.h" +#include "hash.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "log.h" +#include "sockunion.h" /* for inet_ntop () */ + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ia.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_dump.h" + +#define DEBUG + +struct vertex_nexthop * +vertex_nexthop_new (struct vertex *parent) +{ + struct vertex_nexthop *new; + + new = XCALLOC (MTYPE_OSPF_NEXTHOP, sizeof (struct vertex_nexthop)); + new->parent = parent; + + return new; +} + +void +vertex_nexthop_free (struct vertex_nexthop *nh) +{ + XFREE (MTYPE_OSPF_NEXTHOP, nh); +} + +struct vertex_nexthop * +vertex_nexthop_dup (struct vertex_nexthop *nh) +{ + struct vertex_nexthop *new; + + new = vertex_nexthop_new (nh->parent); + + new->oi = nh->oi; + new->router = nh->router; + + return new; +} + + +struct vertex * +ospf_vertex_new (struct ospf_lsa *lsa) +{ + struct vertex *new; + + new = XMALLOC (MTYPE_OSPF_VERTEX, sizeof (struct vertex)); + memset (new, 0, sizeof (struct vertex)); + + new->flags = 0; + new->type = lsa->data->type; + new->id = lsa->data->id; + new->lsa = lsa->data; + new->distance = 0; + new->child = list_new (); + new->nexthop = list_new (); + + return new; +} + +void +ospf_vertex_free (struct vertex *v) +{ + listnode node; + + list_delete (v->child); + + if (listcount (v->nexthop) > 0) + for (node = listhead (v->nexthop); node; nextnode (node)) + vertex_nexthop_free (node->data); + + list_delete (v->nexthop); + + XFREE (MTYPE_OSPF_VERTEX, v); +} + +void +ospf_vertex_add_parent (struct vertex *v) +{ + struct vertex_nexthop *nh; + listnode node; + + for (node = listhead (v->nexthop); node; nextnode (node)) + { + nh = (struct vertex_nexthop *) getdata (node); + + /* No need to add two links from the same parent. */ + if (listnode_lookup (nh->parent->child, v) == NULL) + listnode_add (nh->parent->child, v); + } +} + +void +ospf_spf_init (struct ospf_area *area) +{ + struct vertex *v; + + /* Create root node. */ + v = ospf_vertex_new (area->router_lsa_self); + + area->spf = v; + + /* Reset ABR and ASBR router counts. */ + area->abr_count = 0; + area->asbr_count = 0; +} + +int +ospf_spf_has_vertex (struct route_table *rv, struct route_table *nv, + struct lsa_header *lsa) +{ + struct prefix p; + struct route_node *rn; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = lsa->id; + + if (lsa->type == OSPF_ROUTER_LSA) + rn = route_node_get (rv, &p); + else + rn = route_node_get (nv, &p); + + if (rn->info != NULL) + { + route_unlock_node (rn); + return 1; + } + return 0; +} + +listnode +ospf_vertex_lookup (list vlist, struct in_addr id, int type) +{ + listnode node; + struct vertex *v; + + for (node = listhead (vlist); node; nextnode (node)) + { + v = (struct vertex *) getdata (node); + if (IPV4_ADDR_SAME (&id, &v->id) && type == v->type) + return node; + } + + return NULL; +} + +int +ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v) +{ + int i; + int length; + struct router_lsa *rl; + struct network_lsa *nl; + + /* In case of W is Network LSA. */ + if (w->type == OSPF_NETWORK_LSA) + { + if (v->type == OSPF_NETWORK_LSA) + return 0; + + nl = (struct network_lsa *) w; + length = (ntohs (w->length) - OSPF_LSA_HEADER_SIZE - 4) / 4; + + for (i = 0; i < length; i++) + if (IPV4_ADDR_SAME (&nl->routers[i], &v->id)) + return 1; + return 0; + } + + /* In case of W is Router LSA. */ + if (w->type == OSPF_ROUTER_LSA) + { + rl = (struct router_lsa *) w; + + length = ntohs (w->length); + + for (i = 0; + i < ntohs (rl->links) && length >= sizeof (struct router_lsa); + i++, length -= 12) + { + switch (rl->link[i].type) + { + case LSA_LINK_TYPE_POINTOPOINT: + case LSA_LINK_TYPE_VIRTUALLINK: + /* Router LSA ID. */ + if (v->type == OSPF_ROUTER_LSA && + IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id)) + { + return 1; + } + break; + case LSA_LINK_TYPE_TRANSIT: + /* Network LSA ID. */ + if (v->type == OSPF_NETWORK_LSA && + IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id)) + { + return 1; + } + break; + case LSA_LINK_TYPE_STUB: + /* Not take into count? */ + continue; + default: + break; + } + } + } + return 0; +} + +/* Add the nexthop to the list, only if it is unique. + * If it's not unique, free the nexthop entry. + */ +void +ospf_nexthop_add_unique (struct vertex_nexthop *new, list nexthop) +{ + struct vertex_nexthop *nh; + listnode node; + int match; + + match = 0; + for (node = listhead (nexthop); node; nextnode (node)) + { + nh = node->data; + + /* Compare the two entries. */ + /* XXX + * Comparing the parent preserves the shortest path tree + * structure even when the nexthops are identical. + */ + if (nh->oi == new->oi && + IPV4_ADDR_SAME (&nh->router, &new->router) && + nh->parent == new->parent) + { + match = 1; + break; + } + } + + if (!match) + listnode_add (nexthop, new); + else + vertex_nexthop_free (new); +} + +/* Merge entries in list b into list a. */ +void +ospf_nexthop_merge (list a, list b) +{ + struct listnode *n; + + for (n = listhead (b); n; nextnode (n)) + { + ospf_nexthop_add_unique (n->data, a); + } +} + +#define ROUTER_LSA_MIN_SIZE 12 +#define ROUTER_LSA_TOS_SIZE 4 + +struct router_lsa_link * +ospf_get_next_link (struct vertex *v, struct vertex *w, + struct router_lsa_link *prev_link) +{ + u_char *p; + u_char *lim; + struct router_lsa_link *l; + + if (prev_link == NULL) + p = ((u_char *) v->lsa) + 24; + else + { + p = (u_char *)prev_link; + p += (ROUTER_LSA_MIN_SIZE + + (prev_link->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + } + + lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); + + while (p < lim) + { + l = (struct router_lsa_link *) p; + + p += (ROUTER_LSA_MIN_SIZE + + (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + + if (l->m[0].type == LSA_LINK_TYPE_STUB) + continue; + + /* Defer NH calculation via VLs until summaries from + transit areas area confidered */ + + if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) + continue; + + if (IPV4_ADDR_SAME (&l->link_id, &w->id)) + return l; + } + + return NULL; +} + +/* Calculate nexthop from root to vertex W. */ +void +ospf_nexthop_calculation (struct ospf_area *area, + struct vertex *v, struct vertex *w) +{ + listnode node; + struct vertex_nexthop *nh, *x; + struct ospf_interface *oi = NULL; + struct router_lsa_link *l = NULL; + + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_nexthop_calculation(): Start"); + + /* W's parent is root. */ + if (v == area->spf) + { + if (w->type == OSPF_VERTEX_ROUTER) + { + while ((l = ospf_get_next_link (v, w, l))) + { + struct router_lsa_link *l2 = NULL; + + if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) + { + /* Check for PtMP, signified by PtP link V->W + with link_data our PtMP interface. */ + oi = ospf_if_is_configured (area->ospf, &l->link_data); + if (oi && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) + { + struct prefix_ipv4 la; + la.prefixlen = oi->address->prefixlen; + + /* We link to them on PtMP interface + - find the interface on w */ + while ((l2 = ospf_get_next_link (w, v, l2))) + { + la.prefix = l2->link_data; + + if (prefix_cmp ((struct prefix *)&la, + oi->address) == 0) + /* link_data is on our PtMP network */ + break; + } + } + else + { + while ((l2 = ospf_get_next_link (w, v, l2))) + { + oi = ospf_if_is_configured (area->ospf, + &(l2->link_data)); + + if (oi == NULL) + continue; + + if (!IPV4_ADDR_SAME (&oi->address->u.prefix4, + &l->link_data)) + continue; + + break; + } + } + + if (oi && l2) + { + nh = vertex_nexthop_new (v); + nh->oi = oi; + nh->router = l2->link_data; + listnode_add (w->nexthop, nh); + } + } + } + } + else + { + while ((l = ospf_get_next_link (v, w, l))) + { + oi = ospf_if_is_configured (area->ospf, &(l->link_data)); + if (oi) + { + nh = vertex_nexthop_new (v); + nh->oi = oi; + nh->router.s_addr = 0; + listnode_add (w->nexthop, nh); + } + } + } + return; + } + /* In case of W's parent is network connected to root. */ + else if (v->type == OSPF_VERTEX_NETWORK) + { + for (node = listhead (v->nexthop); node; nextnode (node)) + { + x = (struct vertex_nexthop *) getdata (node); + if (x->parent == area->spf) + { + while ((l = ospf_get_next_link (w, v, l))) + { + nh = vertex_nexthop_new (v); + nh->oi = x->oi; + nh->router = l->link_data; + listnode_add (w->nexthop, nh); + } + return; + } + } + } + + /* Inherit V's nexthop. */ + for (node = listhead (v->nexthop); node; nextnode (node)) + { + nh = vertex_nexthop_dup (node->data); + nh->parent = v; + ospf_nexthop_add_unique (nh, w->nexthop); + } +} + +void +ospf_install_candidate (list candidate, struct vertex *w) +{ + listnode node; + struct vertex *cw; + + if (list_isempty (candidate)) + { + listnode_add (candidate, w); + return; + } + + /* Install vertex with sorting by distance. */ + for (node = listhead (candidate); node; nextnode (node)) + { + cw = (struct vertex *) getdata (node); + if (cw->distance > w->distance) + { + list_add_node_prev (candidate, node, w); + break; + } + else if (node->next == NULL) + { + list_add_node_next (candidate, node, w); + break; + } + } +} + +/* RFC2328 Section 16.1 (2). */ +void +ospf_spf_next (struct vertex *v, struct ospf_area *area, + list candidate, struct route_table *rv, + struct route_table *nv) +{ + struct ospf_lsa *w_lsa = NULL; + struct vertex *w, *cw; + u_char *p; + u_char *lim; + struct router_lsa_link *l = NULL; + struct in_addr *r; + listnode node; + int type = 0; + + /* If this is a router-LSA, and bit V of the router-LSA (see Section + A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */ + if (v->type == OSPF_VERTEX_ROUTER) + { + if (IS_ROUTER_LSA_VIRTUAL ((struct router_lsa *) v->lsa)) + area->transit = OSPF_TRANSIT_TRUE; + } + + p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4; + lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); + + while (p < lim) + { + /* In case of V is Router-LSA. */ + if (v->lsa->type == OSPF_ROUTER_LSA) + { + l = (struct router_lsa_link *) p; + + p += (ROUTER_LSA_MIN_SIZE + + (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + + /* (a) If this is a link to a stub network, examine the next + link in V's LSA. Links to stub networks will be + considered in the second stage of the shortest path + calculation. */ + if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB) + continue; + + /* (b) Otherwise, W is a transit vertex (router or transit + network). Look up the vertex W's LSA (router-LSA or + network-LSA) in Area A's link state database. */ + switch (type) + { + case LSA_LINK_TYPE_POINTOPOINT: + case LSA_LINK_TYPE_VIRTUALLINK: + if (type == LSA_LINK_TYPE_VIRTUALLINK) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("looking up LSA through VL: %s", + inet_ntoa (l->link_id)); + } + + w_lsa = ospf_lsa_lookup (area, OSPF_ROUTER_LSA, l->link_id, + l->link_id); + if (w_lsa) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info("found the LSA"); + } + break; + case LSA_LINK_TYPE_TRANSIT: + if (IS_DEBUG_OSPF_EVENT) + + zlog_info ("Looking up Network LSA, ID: %s", + inet_ntoa(l->link_id)); + w_lsa = ospf_lsa_lookup_by_id (area, OSPF_NETWORK_LSA, + l->link_id); + if (w_lsa) + if (IS_DEBUG_OSPF_EVENT) + zlog_info("found the LSA"); + break; + default: + zlog_warn ("Invalid LSA link type %d", type); + continue; + } + } + else + { + /* In case of V is Network-LSA. */ + r = (struct in_addr *) p ; + p += sizeof (struct in_addr); + + /* Lookup the vertex W's LSA. */ + w_lsa = ospf_lsa_lookup_by_id (area, OSPF_ROUTER_LSA, *r); + } + + /* (b cont.) If the LSA does not exist, or its LS age is equal + to MaxAge, or it does not have a link back to vertex V, + examine the next link in V's LSA.[23] */ + if (w_lsa == NULL) + continue; + + if (IS_LSA_MAXAGE (w_lsa)) + continue; + + if (! ospf_lsa_has_link (w_lsa->data, v->lsa)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("The LSA doesn't have a link back"); + continue; + } + + /* (c) If vertex W is already on the shortest-path tree, examine + the next link in the LSA. */ + if (ospf_spf_has_vertex (rv, nv, w_lsa->data)) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("The LSA is already in SPF"); + continue; + } + + /* (d) Calculate the link state cost D of the resulting path + from the root to vertex W. D is equal to the sum of the link + state cost of the (already calculated) shortest path to + vertex V and the advertised cost of the link between vertices + V and W. If D is: */ + + /* prepare vertex W. */ + w = ospf_vertex_new (w_lsa); + + /* calculate link cost D. */ + if (v->lsa->type == OSPF_ROUTER_LSA) + w->distance = v->distance + ntohs (l->m[0].metric); + else + w->distance = v->distance; + + /* Is there already vertex W in candidate list? */ + node = ospf_vertex_lookup (candidate, w->id, w->type); + if (node == NULL) + { + /* Calculate nexthop to W. */ + ospf_nexthop_calculation (area, v, w); + + ospf_install_candidate (candidate, w); + } + else + { + cw = (struct vertex *) getdata (node); + + /* if D is greater than. */ + if (cw->distance < w->distance) + { + ospf_vertex_free (w); + continue; + } + /* equal to. */ + else if (cw->distance == w->distance) + { + /* Calculate nexthop to W. */ + ospf_nexthop_calculation (area, v, w); + ospf_nexthop_merge (cw->nexthop, w->nexthop); + list_delete_all_node (w->nexthop); + ospf_vertex_free (w); + } + /* less than. */ + else + { + /* Calculate nexthop. */ + ospf_nexthop_calculation (area, v, w); + + /* Remove old vertex from candidate list. */ + ospf_vertex_free (cw); + listnode_delete (candidate, cw); + + /* Install new to candidate. */ + ospf_install_candidate (candidate, w); + } + } + } +} + +/* Add vertex V to SPF tree. */ +void +ospf_spf_register (struct vertex *v, struct route_table *rv, + struct route_table *nv) +{ + struct prefix p; + struct route_node *rn; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = v->id; + + if (v->type == OSPF_VERTEX_ROUTER) + rn = route_node_get (rv, &p); + else + rn = route_node_get (nv, &p); + + rn->info = v; +} + +void +ospf_spf_route_free (struct route_table *table) +{ + struct route_node *rn; + struct vertex *v; + + for (rn = route_top (table); rn; rn = route_next (rn)) + { + if ((v = rn->info)) + { + ospf_vertex_free (v); + rn->info = NULL; + } + + route_unlock_node (rn); + } + + route_table_finish (table); +} + +void +ospf_spf_dump (struct vertex *v, int i) +{ + listnode cnode; + listnode nnode; + struct vertex_nexthop *nexthop; + + if (v->type == OSPF_VERTEX_ROUTER) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF Result: %d [R] %s", i, inet_ntoa (v->lsa->id)); + } + else + { + struct network_lsa *lsa = (struct network_lsa *) v->lsa; + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF Result: %d [N] %s/%d", i, inet_ntoa (v->lsa->id), + ip_masklen (lsa->mask)); + + for (nnode = listhead (v->nexthop); nnode; nextnode (nnode)) + { + nexthop = getdata (nnode); + if (IS_DEBUG_OSPF_EVENT) + zlog_info (" nexthop %s", inet_ntoa (nexthop->router)); + } + } + + i++; + + for (cnode = listhead (v->child); cnode; nextnode (cnode)) + { + v = getdata (cnode); + ospf_spf_dump (v, i); + } +} + +/* Second stage of SPF calculation. */ +void +ospf_spf_process_stubs (struct ospf_area *area, struct vertex * v, + struct route_table *rt) +{ + listnode cnode; + struct vertex *child; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_process_stub():processing stubs for area %s", + inet_ntoa (area->area_id)); + if (v->type == OSPF_VERTEX_ROUTER) + { + u_char *p; + u_char *lim; + struct router_lsa_link *l; + struct router_lsa *rlsa; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_process_stub():processing router LSA, id: %s", + inet_ntoa (v->lsa->id)); + rlsa = (struct router_lsa *) v->lsa; + + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_process_stub(): we have %d links to process", + ntohs (rlsa->links)); + p = ((u_char *) v->lsa) + 24; + lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); + + while (p < lim) + { + l = (struct router_lsa_link *) p; + + p += (ROUTER_LSA_MIN_SIZE + + (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + + if (l->m[0].type == LSA_LINK_TYPE_STUB) + ospf_intra_add_stub (rt, l, v, area); + } + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("children of V:"); + for (cnode = listhead (v->child); cnode; nextnode (cnode)) + { + child = getdata (cnode); + if (IS_DEBUG_OSPF_EVENT) + zlog_info (" child : %s", inet_ntoa (child->id)); + } + + for (cnode = listhead (v->child); cnode; nextnode (cnode)) + { + child = getdata (cnode); + + if (CHECK_FLAG (child->flags, OSPF_VERTEX_PROCESSED)) + continue; + + ospf_spf_process_stubs (area, child, rt); + + SET_FLAG (child->flags, OSPF_VERTEX_PROCESSED); + } +} + +void +ospf_rtrs_free (struct route_table *rtrs) +{ + struct route_node *rn; + list or_list; + listnode node; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Route: Router Routing Table free"); + + for (rn = route_top (rtrs); rn; rn = route_next (rn)) + if ((or_list = rn->info) != NULL) + { + for (node = listhead (or_list); node; nextnode (node)) + ospf_route_free (node->data); + + list_delete (or_list); + + /* Unlock the node. */ + rn->info = NULL; + route_unlock_node (rn); + } + route_table_finish (rtrs); +} + +void +ospf_rtrs_print (struct route_table *rtrs) +{ + struct route_node *rn; + list or_list; + listnode ln; + listnode pnode; + struct ospf_route *or; + struct ospf_path *path; + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_rtrs_print() start"); + + for (rn = route_top (rtrs); rn; rn = route_next (rn)) + if ((or_list = rn->info) != NULL) + for (ln = listhead (or_list); ln; nextnode (ln)) + { + or = getdata (ln); + + switch (or->path_type) + { + case OSPF_PATH_INTRA_AREA: + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("%s [%d] area: %s", + inet_ntop (AF_INET, &or->id, buf1, BUFSIZ), or->cost, + inet_ntop (AF_INET, &or->u.std.area_id, + buf2, BUFSIZ)); + break; + case OSPF_PATH_INTER_AREA: + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("%s IA [%d] area: %s", + inet_ntop (AF_INET, &or->id, buf1, BUFSIZ), or->cost, + inet_ntop (AF_INET, &or->u.std.area_id, + buf2, BUFSIZ)); + break; + default: + break; + } + + for (pnode = listhead (or->path); pnode; nextnode (pnode)) + { + path = getdata (pnode); + if (path->nexthop.s_addr == 0) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info (" directly attached to %s\r\n", + IF_NAME (path->oi)); + } + else + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info (" via %s, %s\r\n", + inet_ntoa (path->nexthop), IF_NAME (path->oi)); + } + } + } + + zlog_info ("ospf_rtrs_print() end"); +} + +/* Calculating the shortest-path tree for an area. */ +void +ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table, + struct route_table *new_rtrs) +{ + list candidate; + listnode node; + struct vertex *v; + struct route_table *rv; + struct route_table *nv; + + if (IS_DEBUG_OSPF_EVENT) + { + zlog_info ("ospf_spf_calculate: Start"); + zlog_info ("ospf_spf_calculate: running Dijkstra for area %s", + inet_ntoa (area->area_id)); + } + + /* Check router-lsa-self. If self-router-lsa is not yet allocated, + return this area's calculation. */ + if (! area->router_lsa_self) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_spf_calculate: " + "Skip area %s's calculation due to empty router_lsa_self", + inet_ntoa (area->area_id)); + return; + } + + /* RFC2328 16.1. (1). */ + /* Initialize the algorithm's data structures. */ + rv = route_table_init (); + nv = route_table_init (); + + /* Clear the list of candidate vertices. */ + candidate = list_new (); + + /* Initialize the shortest-path tree to only the root (which is the + router doing the calculation). */ + ospf_spf_init (area); + v = area->spf; + ospf_spf_register (v, rv, nv); + + /* Set Area A's TransitCapability to FALSE. */ + area->transit = OSPF_TRANSIT_FALSE; + area->shortcut_capability = 1; + + for (;;) + { + /* RFC2328 16.1. (2). */ + ospf_spf_next (v, area, candidate, rv, nv); + + /* RFC2328 16.1. (3). */ + /* If at this step the candidate list is empty, the shortest- + path tree (of transit vertices) has been completely built and + this stage of the procedure terminates. */ + if (listcount (candidate) == 0) + break; + + /* Otherwise, choose the vertex belonging to the candidate list + that is closest to the root, and add it to the shortest-path + tree (removing it from the candidate list in the + process). */ + node = listhead (candidate); + v = getdata (node); + ospf_vertex_add_parent (v); + + /* Reveve from the candidate list. */ + listnode_delete (candidate, v); + + /* Add to SPF tree. */ + ospf_spf_register (v, rv, nv); + + /* Note that when there is a choice of vertices closest to the + root, network vertices must be chosen before router vertices + in order to necessarily find all equal-cost paths. */ + /* We don't do this at this moment, we should add the treatment + above codes. -- kunihiro. */ + + /* RFC2328 16.1. (4). */ + if (v->type == OSPF_VERTEX_ROUTER) + ospf_intra_add_router (new_rtrs, v, area); + else + ospf_intra_add_transit (new_table, v, area); + + /* RFC2328 16.1. (5). */ + /* Iterate the algorithm by returning to Step 2. */ + } + + if (IS_DEBUG_OSPF_EVENT) + { + ospf_spf_dump (area->spf, 0); + ospf_route_table_dump (new_table); + } + + /* Second stage of SPF calculation procedure's */ + ospf_spf_process_stubs (area, area->spf, new_table); + + /* Free all vertices which allocated for SPF calculation */ + ospf_spf_route_free (rv); + ospf_spf_route_free (nv); + + /* Free candidate list */ + list_free (candidate); + + /* Increment SPF Calculation Counter. */ + area->spf_calculation++; + + area->ospf->ts_spf = time (NULL); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("ospf_spf_calculate: Stop"); +} + +/* Timer for SPF calculation. */ +int +ospf_spf_calculate_timer (struct thread *thread) +{ + struct ospf *ospf = THREAD_ARG (thread); + struct route_table *new_table, *new_rtrs; + listnode node; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF: Timer (SPF calculation expire)"); + + ospf->t_spf_calc = NULL; + + /* Allocate new table tree. */ + new_table = route_table_init (); + new_rtrs = route_table_init (); + + ospf_vl_unapprove (ospf); + + /* Calculate SPF for each area. */ + for (node = listhead (ospf->areas); node; node = nextnode (node)) + ospf_spf_calculate (node->data, new_table, new_rtrs); + + ospf_vl_shut_unapproved (ospf); + + ospf_ia_routing (ospf, new_table, new_rtrs); + + ospf_prune_unreachable_networks (new_table); + ospf_prune_unreachable_routers (new_rtrs); + + /* AS-external-LSA calculation should not be performed here. */ + + /* If new Router Route is installed, + then schedule re-calculate External routes. */ + if (1) + ospf_ase_calculate_schedule (ospf); + + ospf_ase_calculate_timer_add (ospf); + + /* Update routing table. */ + ospf_route_install (ospf, new_table); + + /* Update ABR/ASBR routing table */ + if (ospf->old_rtrs) + { + /* old_rtrs's node holds linked list of ospf_route. --kunihiro. */ + /* ospf_route_delete (ospf->old_rtrs); */ + ospf_rtrs_free (ospf->old_rtrs); + } + + ospf->old_rtrs = ospf->new_rtrs; + ospf->new_rtrs = new_rtrs; + + if (IS_OSPF_ABR (ospf)) + ospf_abr_task (ospf); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF: calculation complete"); + + return 0; +} + +/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we + set timer for SPF calc. */ +void +ospf_spf_calculate_schedule (struct ospf *ospf) +{ + time_t ht, delay; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF: calculation timer scheduled"); + + /* OSPF instance does not exist. */ + if (ospf == NULL) + return; + + /* SPF calculation timer is already scheduled. */ + if (ospf->t_spf_calc) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF: calculation timer is already scheduled: %p", + ospf->t_spf_calc); + return; + } + + ht = time (NULL) - ospf->ts_spf; + + /* Get SPF calculation delay time. */ + if (ht < ospf->spf_holdtime) + { + if (ospf->spf_holdtime - ht < ospf->spf_delay) + delay = ospf->spf_delay; + else + delay = ospf->spf_holdtime - ht; + } + else + delay = ospf->spf_delay; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("SPF: calculation timer delay = %ld", delay); + ospf->t_spf_calc = + thread_add_timer (master, ospf_spf_calculate_timer, ospf, delay); +} + diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h new file mode 100644 index 0000000..e71224b --- /dev/null +++ b/ospfd/ospf_spf.h @@ -0,0 +1,50 @@ +/* + * OSPF calculation. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#define OSPF_VERTEX_ROUTER 1 +#define OSPF_VERTEX_NETWORK 2 + +#define OSPF_VERTEX_PROCESSED 0x01 + + +struct vertex +{ + u_char flags; + u_char type; + struct in_addr id; + struct lsa_header *lsa; + u_int32_t distance; + list child; + list nexthop; +}; + +struct vertex_nexthop +{ + struct ospf_interface *oi; + struct in_addr router; + struct vertex *parent; +}; + +void ospf_spf_calculate_schedule (struct ospf *); +void ospf_rtrs_free (struct route_table *); + +/* void ospf_spf_calculate_timer_add (); */ diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c new file mode 100644 index 0000000..b3709cd --- /dev/null +++ b/ospfd/ospf_te.c @@ -0,0 +1,1921 @@ +/* + * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt + * Copyright (C) 2001 KDD R&D Laboratories, Inc. + * http://www.kddlabs.co.jp/ + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/***** MTYPE definition is not reflected to "memory.h" yet. *****/ +#define MTYPE_OSPF_MPLS_TE_LINKPARAMS 0 + +#include + +#ifdef HAVE_OSPF_TE +#ifndef HAVE_OPAQUE_LSA +#error "Wrong configure option" +#endif /* HAVE_OPAQUE_LSA */ + +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "memory.h" +#include "command.h" +#include "vty.h" +#include "stream.h" +#include "log.h" +#include "thread.h" +#include "hash.h" +#include "sockunion.h" /* for inet_aton() */ + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_te.h" + +/* Following structure are internal use only. */ +struct ospf_mpls_te +{ + enum { disabled, enabled } status; + + /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */ + list iflist; + + /* Store Router-TLV in network byte order. */ + struct te_tlv_router_addr router_addr; +}; + +struct mpls_te_link +{ + /* + * According to MPLS-TE (draft) specification, 24-bit Opaque-ID field + * is subdivided into 8-bit "unused" field and 16-bit "instance" field. + * In this implementation, each Link-TLV has its own instance. + */ + u_int32_t instance; + + /* Reference pointer to a Zebra-interface. */ + struct interface *ifp; + + /* Area info in which this MPLS-TE link belongs to. */ + struct ospf_area *area; + + /* Flags to manage this link parameters. */ + u_int32_t flags; +#define LPFLG_LOOKUP_DONE 0x1 +#define LPFLG_LSA_ENGAGED 0x2 +#define LPFLG_LSA_FORCED_REFRESH 0x4 + + /* Store Link-TLV in network byte order. */ + struct te_tlv_link link_header; + struct te_link_subtlv_link_type link_type; + struct te_link_subtlv_link_id link_id; + struct te_link_subtlv_lclif_ipaddr *lclif_ipaddr; + struct te_link_subtlv_rmtif_ipaddr *rmtif_ipaddr; + struct te_link_subtlv_te_metric te_metric; + struct te_link_subtlv_max_bw max_bw; + struct te_link_subtlv_max_rsv_bw max_rsv_bw; + struct te_link_subtlv_unrsv_bw unrsv_bw; + struct te_link_subtlv_rsc_clsclr rsc_clsclr; +}; + +/* + * Global variable to manage Opaque-LSA/MPLS-TE on this node. + * Note that all parameter values are stored in network byte order. + */ +static struct ospf_mpls_te OspfMplsTE; + +enum oifstate { + OI_ANY, OI_DOWN, OI_UP +}; + +enum sched_opcode { + REORIGINATE_PER_AREA, REFRESH_THIS_LSA, FLUSH_THIS_LSA +}; + +/*------------------------------------------------------------------------* + * Followings are initialize/terminate functions for MPLS-TE handling. + *------------------------------------------------------------------------*/ + +static int ospf_mpls_te_new_if (struct interface *ifp); +static int ospf_mpls_te_del_if (struct interface *ifp); +static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_status); +static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_status); +static void ospf_mpls_te_config_write_router (struct vty *vty); +static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp); +static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa); +static int ospf_mpls_te_lsa_originate (void *arg); +static void ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa); +static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode); + +static void del_mpls_te_link (void *val); +static void ospf_mpls_te_register_vty (void); + +int +ospf_mpls_te_init (void) +{ + int rc; + + rc = ospf_register_opaque_functab ( + OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, + ospf_mpls_te_new_if, + ospf_mpls_te_del_if, + ospf_mpls_te_ism_change, + ospf_mpls_te_nsm_change, + ospf_mpls_te_config_write_router, + ospf_mpls_te_config_write_if, + NULL,/* ospf_mpls_te_config_write_debug */ + ospf_mpls_te_show_info, + ospf_mpls_te_lsa_originate, + ospf_mpls_te_lsa_refresh, + NULL,/* ospf_mpls_te_new_lsa_hook */ + NULL /* ospf_mpls_te_del_lsa_hook */); + if (rc != 0) + { + zlog_warn ("ospf_mpls_te_init: Failed to register functions"); + goto out; + } + + memset (&OspfMplsTE, 0, sizeof (struct ospf_mpls_te)); + OspfMplsTE.status = disabled; + OspfMplsTE.iflist = list_new (); + OspfMplsTE.iflist->del = del_mpls_te_link; + + ospf_mpls_te_register_vty (); + +out: + return rc; +} + +void +ospf_mpls_te_term (void) +{ + list_delete (OspfMplsTE.iflist); + + OspfMplsTE.iflist = NULL; + OspfMplsTE.status = disabled; + + ospf_delete_opaque_functab (OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); + return; +} + +/*------------------------------------------------------------------------* + * Followings are control functions for MPLS-TE parameters management. + *------------------------------------------------------------------------*/ + +static void +del_mpls_te_link (void *val) +{ + XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, val); + return; +} + +static u_int32_t +get_mpls_te_instance_value () +{ + static u_int32_t seqno = 0; + + if (LEGAL_TE_INSTANCE_RANGE (seqno + 1)) + seqno += 1; + else + seqno = 1; /* Avoid zero. */ + + return seqno; +} + +static struct ospf_interface * +lookup_oi_by_ifp (struct interface *ifp, + struct ospf_area *area, enum oifstate oifstate) +{ + struct ospf_interface *oi = NULL; + struct route_node *rn; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + if ((oi = rn->info) == NULL) + continue; + + switch (oifstate) + { + case OI_ANY: + break; + case OI_DOWN: + if (ospf_if_is_enable (oi)) + continue; + break; + case OI_UP: + if (! ospf_if_is_enable (oi)) + continue; + break; + default: + zlog_warn ("lookup_oi_by_ifp: Unknown oifstate: %x", oifstate); + goto out; + } + + if (area == NULL || oi->area == area) + return oi; + } +out: + return NULL; +} + +static struct mpls_te_link * +lookup_linkparams_by_ifp (struct interface *ifp) +{ + listnode node; + struct mpls_te_link *lp; + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + if ((lp = getdata (node)) != NULL) + if (lp->ifp == ifp) + return lp; + + return NULL; +} + +static struct mpls_te_link * +lookup_linkparams_by_instance (struct ospf_lsa *lsa) +{ + listnode node; + struct mpls_te_link *lp; + int key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)); + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + if ((lp = getdata (node)) != NULL) + if (lp->instance == key) + return lp; + + zlog_warn ("lookup_linkparams_by_instance: Entry not found: key(%x)", key); + return NULL; +} + +static void +ospf_mpls_te_foreach_area ( + void (*func)(struct mpls_te_link *lp, enum sched_opcode), + enum sched_opcode sched_opcode) +{ + listnode node, node2; + struct mpls_te_link *lp; + struct ospf_area *area; + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + { + if ((lp = getdata (node)) == NULL) + continue; + if ((area = lp->area) == NULL) + continue; + if (lp->flags & LPFLG_LOOKUP_DONE) + continue; + + if (func != NULL) + (* func)(lp, sched_opcode); + + for (node2 = nextnode (node); node2; nextnode (node2)) + if ((lp = getdata (node2)) != NULL) + if (lp->area != NULL) + if (IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) + lp->flags |= LPFLG_LOOKUP_DONE; + } + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + if ((lp = getdata (node)) != NULL) + if (lp->area != NULL) + lp->flags &= ~LPFLG_LOOKUP_DONE; + + return; +} + +static void +set_mpls_te_router_addr (struct in_addr ipv4) +{ + OspfMplsTE.router_addr.header.type = htons (TE_TLV_ROUTER_ADDR); + OspfMplsTE.router_addr.header.length = htons (sizeof (ipv4)); + OspfMplsTE.router_addr.value = ipv4; + return; +} + +static void +set_linkparams_link_header (struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh; + u_int16_t length = 0; + + /* TE_LINK_SUBTLV_LINK_TYPE */ + if (ntohs (lp->link_type.header.type) != 0) + length += TLV_SIZE (&lp->link_type.header); + + /* TE_LINK_SUBTLV_LINK_ID */ + if (ntohs (lp->link_id.header.type) != 0) + length += TLV_SIZE (&lp->link_id.header); + + /* TE_LINK_SUBTLV_LCLIF_IPADDR */ + if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL + && ntohs (tlvh->type) != 0) + length += TLV_SIZE (tlvh); + + /* TE_LINK_SUBTLV_RMTIF_IPADDR */ + if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL + && ntohs (tlvh->type) != 0) + length += TLV_SIZE (tlvh); + + /* TE_LINK_SUBTLV_TE_METRIC */ + if (ntohs (lp->te_metric.header.type) != 0) + length += TLV_SIZE (&lp->te_metric.header); + + /* TE_LINK_SUBTLV_MAX_BW */ + if (ntohs (lp->max_bw.header.type) != 0) + length += TLV_SIZE (&lp->max_bw.header); + + /* TE_LINK_SUBTLV_MAX_RSV_BW */ + if (ntohs (lp->max_rsv_bw.header.type) != 0) + length += TLV_SIZE (&lp->max_rsv_bw.header); + + /* TE_LINK_SUBTLV_UNRSV_BW */ + if (ntohs (lp->unrsv_bw.header.type) != 0) + length += TLV_SIZE (&lp->unrsv_bw.header); + + /* TE_LINK_SUBTLV_RSC_CLSCLR */ + if (ntohs (lp->rsc_clsclr.header.type) != 0) + length += TLV_SIZE (&lp->rsc_clsclr.header); + + lp->link_header.header.type = htons (TE_TLV_LINK); + lp->link_header.header.length = htons (length); + + return; +} + +static void +set_linkparams_link_type (struct ospf_interface *oi, struct mpls_te_link *lp) +{ + lp->link_type.header.type = htons (TE_LINK_SUBTLV_LINK_TYPE); + lp->link_type.header.length = htons (sizeof (lp->link_type.link_type.value)); + + switch (oi->type) + { + case OSPF_IFTYPE_POINTOPOINT: + lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_PTP; + break; + case OSPF_IFTYPE_BROADCAST: + case OSPF_IFTYPE_NBMA: + lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_MA; + break; + default: + /* Not supported yet. *//* XXX */ + lp->link_type.header.type = htons (0); + break; + } + return; +} + +static void +set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp) +{ + struct ospf_neighbor *nbr; + int done = 0; + + lp->link_id.header.type = htons (TE_LINK_SUBTLV_LINK_ID); + lp->link_id.header.length = htons (sizeof (lp->link_id.value)); + + /* + * The Link ID is identical to the contents of the Link ID field + * in the Router LSA for these link types. + */ + switch (oi->type) + { + case OSPF_IFTYPE_POINTOPOINT: + /* Take the router ID of the neighbor. */ + if ((nbr = ospf_nbr_lookup_ptop (oi)) + && nbr->state == NSM_Full) + { + lp->link_id.value = nbr->router_id; + done = 1; + } + break; + case OSPF_IFTYPE_BROADCAST: + case OSPF_IFTYPE_NBMA: + /* Take the interface address of the designated router. */ + if ((nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi))) == NULL) + break; + + if (nbr->state == NSM_Full + || (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) + && ospf_nbr_count (oi, NSM_Full) > 0)) + { + lp->link_id.value = DR (oi); + done = 1; + } + break; + default: + /* Not supported yet. *//* XXX */ + lp->link_id.header.type = htons (0); + break; + } + + if (! done) + { + struct in_addr mask; + masklen2ip (oi->address->prefixlen, &mask); + lp->link_id.value.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; + } + return; +} + +static void +set_linkparams_te_metric (struct mpls_te_link *lp, u_int32_t te_metric) +{ + lp->te_metric.header.type = htons (TE_LINK_SUBTLV_TE_METRIC); + lp->te_metric.header.length = htons (sizeof (lp->te_metric.value)); + lp->te_metric.value = htonl (te_metric); + return; +} + +static void +set_linkparams_max_bw (struct mpls_te_link *lp, float *fp) +{ + lp->max_bw.header.type = htons (TE_LINK_SUBTLV_MAX_BW); + lp->max_bw.header.length = htons (sizeof (lp->max_bw.value)); + htonf (fp, &lp->max_bw.value); + return; +} + +static void +set_linkparams_max_rsv_bw (struct mpls_te_link *lp, float *fp) +{ + lp->max_rsv_bw.header.type = htons (TE_LINK_SUBTLV_MAX_RSV_BW); + lp->max_rsv_bw.header.length = htons (sizeof (lp->max_rsv_bw.value)); + htonf (fp, &lp->max_rsv_bw.value); + return; +} + +static void +set_linkparams_unrsv_bw (struct mpls_te_link *lp, int priority, float *fp) +{ + /* Note that TLV-length field is the size of array. */ + lp->unrsv_bw.header.type = htons (TE_LINK_SUBTLV_UNRSV_BW); + lp->unrsv_bw.header.length = htons (sizeof (lp->unrsv_bw.value)); + htonf (fp, &lp->unrsv_bw.value [priority]); + return; +} + +static void +set_linkparams_rsc_clsclr (struct mpls_te_link *lp, u_int32_t classcolor) +{ + lp->rsc_clsclr.header.type = htons (TE_LINK_SUBTLV_RSC_CLSCLR); + lp->rsc_clsclr.header.length = htons (sizeof (lp->rsc_clsclr.value)); + lp->rsc_clsclr.value = htonl (classcolor); + return; +} + +static void +initialize_linkparams (struct mpls_te_link *lp) +{ + struct interface *ifp = lp->ifp; + struct ospf_interface *oi; + float fval; + int i; + + if ((oi = lookup_oi_by_ifp (ifp, NULL, OI_ANY)) == NULL) + return; + + /* + * Try to set initial values those can be derived from + * zebra-interface information. + */ + set_linkparams_link_type (oi, lp); + + /* + * Linux and *BSD kernel holds bandwidth parameter as an "int" type. + * We may have to reconsider, if "ifp->bandwidth" type changes to float. + */ + fval = (float)((ifp->bandwidth ? ifp->bandwidth + : OSPF_DEFAULT_BANDWIDTH) * 1000 / 8); + + set_linkparams_max_bw (lp, &fval); + set_linkparams_max_rsv_bw (lp, &fval); + + for (i = 0; i < 8; i++) + set_linkparams_unrsv_bw (lp, i, &fval); + + return; +} + +static int +is_mandated_params_set (struct mpls_te_link *lp) +{ + int rc = 0; + + if (ntohs (OspfMplsTE.router_addr.header.type) == 0) + goto out; + + if (ntohs (lp->link_type.header.type) == 0) + goto out; + + if (ntohs (lp->link_id.header.type) == 0) + goto out; + + rc = 1; +out: + return rc; +} + +/*------------------------------------------------------------------------* + * Followings are callback functions against generic Opaque-LSAs handling. + *------------------------------------------------------------------------*/ + +static int +ospf_mpls_te_new_if (struct interface *ifp) +{ + struct mpls_te_link *new; + int rc = -1; + + if (lookup_linkparams_by_ifp (ifp) != NULL) + { + zlog_warn ("ospf_mpls_te_new_if: ifp(%p) already in use?", ifp); + rc = 0; /* Do nothing here. */ + goto out; + } + + if ((new = XMALLOC (MTYPE_OSPF_MPLS_TE_LINKPARAMS, + sizeof (struct mpls_te_link))) == NULL) + { + zlog_warn ("ospf_mpls_te_new_if: XMALLOC: %s", strerror (errno)); + goto out; + } + memset (new, 0, sizeof (struct mpls_te_link)); + + new->area = NULL; + new->flags = 0; + new->instance = get_mpls_te_instance_value (); + new->ifp = ifp; + + initialize_linkparams (new); + + listnode_add (OspfMplsTE.iflist, new); + + /* Schedule Opaque-LSA refresh. *//* XXX */ + + rc = 0; +out: + return rc; +} + +static int +ospf_mpls_te_del_if (struct interface *ifp) +{ + struct mpls_te_link *lp; + int rc = -1; + + if ((lp = lookup_linkparams_by_ifp (ifp)) != NULL) + { + list iflist = OspfMplsTE.iflist; + + /* Dequeue listnode entry from the list. */ + listnode_delete (iflist, lp); + + /* Avoid misjudgement in the next lookup. */ + if (listcount (iflist) == 0) + iflist->head = iflist->tail = NULL; + + XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, lp); + } + + /* Schedule Opaque-LSA refresh. *//* XXX */ + + rc = 0; +/*out:*/ + return rc; +} + +static void +ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_state) +{ + struct te_link_subtlv_link_type old_type; + struct te_link_subtlv_link_id old_id; + struct mpls_te_link *lp; + + if ((lp = lookup_linkparams_by_ifp (oi->ifp)) == NULL) + { + zlog_warn ("ospf_mpls_te_ism_change: Cannot get linkparams from OI(%s)?", IF_NAME (oi)); + goto out; + } + if (oi->area == NULL || oi->area->ospf == NULL) + { + zlog_warn ("ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?", +IF_NAME (oi)); + goto out; + } +#ifdef notyet + if ((lp->area != NULL + && ! IPV4_ADDR_SAME (&lp->area->area_id, &oi->area->area_id)) + || (lp->area != NULL && oi->area == NULL)) + { + /* How should we consider this case? */ + zlog_warn ("MPLS-TE: Area for OI(%s) has changed to [%s], flush previous LSAs", IF_NAME (oi), oi->area ? inet_ntoa (oi->area->area_id) : "N/A"); + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); + } +#endif + /* Keep Area information in conbination with linkparams. */ + lp->area = oi->area; + + switch (oi->state) + { + case ISM_PointToPoint: + case ISM_DROther: + case ISM_Backup: + case ISM_DR: + old_type = lp->link_type; + old_id = lp->link_id; + + set_linkparams_link_type (oi, lp); + set_linkparams_link_id (oi, lp); + + if ((ntohs (old_type.header.type) != ntohs (lp->link_type.header.type) + || old_type.link_type.value != lp->link_type.link_type.value) + || (ntohs (old_id.header.type) != ntohs (lp->link_id.header.type) + || ntohl (old_id.value.s_addr) != ntohl (lp->link_id.value.s_addr))) + { + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + } + break; + default: + lp->link_type.header.type = htons (0); + lp->link_id.header.type = htons (0); + + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); + break; + } + +out: + return; +} + +static void +ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_state) +{ + /* So far, nothing to do here. */ + return; +} + +/*------------------------------------------------------------------------* + * Followings are OSPF protocol processing functions for MPLS-TE. + *------------------------------------------------------------------------*/ + +static void +build_tlv_header (struct stream *s, struct te_tlv_header *tlvh) +{ + stream_put (s, tlvh, sizeof (struct te_tlv_header)); + return; +} + +static void +build_router_tlv (struct stream *s) +{ + struct te_tlv_header *tlvh = &OspfMplsTE.router_addr.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_link_type (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->link_type.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_link_id (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->link_id.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_lclif_ipaddr (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->lclif_ipaddr; + if (tlvh != NULL && ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_rmtif_ipaddr (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr; + if (tlvh != NULL && ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_te_metric (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->te_metric.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_max_bw (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->max_bw.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_max_rsv_bw (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->max_rsv_bw.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_unrsv_bw (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->unrsv_bw.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_subtlv_rsc_clsclr (struct stream *s, struct mpls_te_link *lp) +{ + struct te_tlv_header *tlvh = &lp->rsc_clsclr.header; + if (ntohs (tlvh->type) != 0) + { + build_tlv_header (s, tlvh); + stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); + } + return; +} + +static void +build_link_tlv (struct stream *s, struct mpls_te_link *lp) +{ + set_linkparams_link_header (lp); + build_tlv_header (s, &lp->link_header.header); + + build_link_subtlv_link_type (s, lp); + build_link_subtlv_link_id (s, lp); + build_link_subtlv_lclif_ipaddr (s, lp); + build_link_subtlv_rmtif_ipaddr (s, lp); + build_link_subtlv_te_metric (s, lp); + build_link_subtlv_max_bw (s, lp); + build_link_subtlv_max_rsv_bw (s, lp); + build_link_subtlv_unrsv_bw (s, lp); + build_link_subtlv_rsc_clsclr (s, lp); + return; +} + +static void +ospf_mpls_te_lsa_body_set (struct stream *s, struct mpls_te_link *lp) +{ + /* + * The router address TLV is type 1, and ... + * It must appear in exactly one + * Traffic Engineering LSA originated by a router. + */ + build_router_tlv (s); + + /* + * Only one Link TLV shall be carried in each LSA, allowing for fine + * granularity changes in topology. + */ + build_link_tlv (s, lp); + return; +} + +/* Create new opaque-LSA. */ +static struct ospf_lsa * +ospf_mpls_te_lsa_new (struct ospf_area *area, struct mpls_te_link *lp) +{ + struct stream *s; + struct lsa_header *lsah; + struct ospf_lsa *new = NULL; + u_char options, lsa_type; + struct in_addr lsa_id; + u_int32_t tmp; + u_int16_t length; + + /* Create a stream for LSA. */ + if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_new: stream_new() ?"); + goto out; + } + lsah = (struct lsa_header *) STREAM_DATA (s); + + options = LSA_OPTIONS_GET (area); +#ifdef HAVE_NSSA + options |= LSA_NSSA_GET (area); +#endif /* HAVE_NSSA */ + options |= OSPF_OPTION_O; /* Don't forget this :-) */ + + lsa_type = OSPF_OPAQUE_AREA_LSA; + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); + lsa_id.s_addr = htonl (tmp); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + zlog_info ("LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", lsa_type, inet_ntoa (lsa_id)); + + /* Set opaque-LSA header fields. */ + lsa_header_set (s, options, lsa_type, lsa_id, area->ospf->router_id); + + /* Set opaque-LSA body fields. */ + ospf_mpls_te_lsa_body_set (s, lp); + + /* Set length. */ + length = stream_get_endp (s); + lsah->length = htons (length); + + /* Now, create an OSPF LSA instance. */ + if ((new = ospf_lsa_new ()) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_new() ?"); + stream_free (s); + goto out; + } + if ((new->data = ospf_lsa_data_new (length)) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_data_new() ?"); + ospf_lsa_free (new); + new = NULL; + stream_free (s); + goto out; + } + + new->area = area; + SET_FLAG (new->flags, OSPF_LSA_SELF); + memcpy (new->data, lsah, length); + stream_free (s); + +out: + return new; +} + +static int +ospf_mpls_te_lsa_originate1 (struct ospf_area *area, struct mpls_te_link *lp) +{ + struct ospf_lsa *new; + int rc = -1; + + /* Create new Opaque-LSA/MPLS-TE instance. */ + if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_mpls_te_lsa_new() ?"); + goto out; + } + + /* Install this LSA into LSDB. */ + if (ospf_lsa_install (area->ospf, NULL/*oi*/, new) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_lsa_install() ?"); + ospf_lsa_free (new); + goto out; + } + + /* Now this linkparameter entry has associated LSA. */ + lp->flags |= LPFLG_LSA_ENGAGED; + + /* Update new LSA origination count. */ + area->ospf->lsa_originate_count++; + + /* Flood new LSA through area. */ + ospf_flood_through_area (area, NULL/*nbr*/, new); + + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + char area_id[INET_ADDRSTRLEN]; + strcpy (area_id, inet_ntoa (area->area_id)); + zlog_info ("LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE: Area(%s), Link(%s)", new->data->type, inet_ntoa (new->data->id), area_id, lp->ifp->name); + ospf_lsa_header_dump (new->data); + } + + rc = 0; +out: + return rc; +} + +static int +ospf_mpls_te_lsa_originate (void *arg) +{ + struct ospf_area *area = (struct ospf_area *) arg; + listnode node; + struct mpls_te_link *lp; + int rc = -1; + + if (OspfMplsTE.status == disabled) + { + zlog_info ("ospf_mpls_te_lsa_originate: MPLS-TE is disabled now."); + rc = 0; /* This is not an error case. */ + goto out; + } + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + { + if ((lp = getdata (node)) == NULL) + continue; + if (lp->area == NULL) + continue; + if (! IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) + continue; + + if (lp->flags & LPFLG_LSA_ENGAGED) + { + if (lp->flags & LPFLG_LSA_FORCED_REFRESH) + { + lp->flags &= ~LPFLG_LSA_FORCED_REFRESH; + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + } + continue; + } + if (! is_mandated_params_set (lp)) + { + zlog_warn ("ospf_mpls_te_lsa_originate: Link(%s) lacks some mandated MPLS-TE parameters.", lp->ifp ? lp->ifp->name : "?"); + continue; + } + + /* Ok, let's try to originate an LSA for this area and Link. */ + if (ospf_mpls_te_lsa_originate1 (area, lp) != 0) + goto out; + } + + rc = 0; +out: + return rc; +} + +static void +ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa) +{ + struct mpls_te_link *lp; + struct ospf_area *area = lsa->area; + struct ospf_lsa *new = NULL; + + if (OspfMplsTE.status == disabled) + { + /* + * This LSA must have flushed before due to MPLS-TE status change. + * It seems a slip among routers in the routing domain. + */ + zlog_info ("ospf_mpls_te_lsa_refresh: MPLS-TE is disabled now."); + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ + } + + /* At first, resolve lsa/lp relationship. */ + if ((lp = lookup_linkparams_by_instance (lsa)) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_refresh: Invalid parameter?"); + lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ + } + + /* If the lsa's age reached to MaxAge, start flushing procedure. */ + if (IS_LSA_MAXAGE (lsa)) + { + lp->flags &= ~LPFLG_LSA_ENGAGED; + ospf_opaque_lsa_flush_schedule (lsa); + goto out; + } + + /* Create new Opaque-LSA/MPLS-TE instance. */ + if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_mpls_te_lsa_new() ?"); + goto out; + } + new->data->ls_seqnum = lsa_seqnum_increment (lsa); + + /* Install this LSA into LSDB. */ + /* Given "lsa" will be freed in the next function. */ + if (ospf_lsa_install (area->ospf, NULL/*oi*/, new) == NULL) + { + zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?"); + ospf_lsa_free (new); + goto out; + } + + /* Flood updated LSA through area. */ + ospf_flood_through_area (area, NULL/*nbr*/, new); + + /* Debug logging. */ + if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) + { + zlog_info ("LSA[Type%d:%s]: Refresh Opaque-LSA/MPLS-TE", + new->data->type, inet_ntoa (new->data->id)); + ospf_lsa_header_dump (new->data); + } + +out: + return; +} + +static void +ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, + enum sched_opcode opcode) +{ + struct ospf_lsa lsa; + struct lsa_header lsah; + u_int32_t tmp; + + memset (&lsa, 0, sizeof (lsa)); + memset (&lsah, 0, sizeof (lsah)); + + lsa.area = lp->area; + lsa.data = &lsah; + lsah.type = OSPF_OPAQUE_AREA_LSA; + tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); + lsah.id.s_addr = htonl (tmp); + + switch (opcode) + { + case REORIGINATE_PER_AREA: + ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area, + OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); + break; + case REFRESH_THIS_LSA: + ospf_opaque_lsa_refresh_schedule (&lsa); + break; + case FLUSH_THIS_LSA: + lp->flags &= ~LPFLG_LSA_ENGAGED; + ospf_opaque_lsa_flush_schedule (&lsa); + break; + default: + zlog_warn ("ospf_mpls_te_lsa_schedule: Unknown opcode (%u)", opcode); + break; + } + + return; +} + +/*------------------------------------------------------------------------* + * Followings are vty session control functions. + *------------------------------------------------------------------------*/ + +static u_int16_t +show_vty_router_addr (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_tlv_router_addr *top = (struct te_tlv_router_addr *) tlvh; + + if (vty != NULL) + vty_out (vty, " Router-Address: %s%s", inet_ntoa (top->value), VTY_NEWLINE); + else + zlog_info (" Router-Address: %s", inet_ntoa (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_header (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_tlv_link *top = (struct te_tlv_link *) tlvh; + + if (vty != NULL) + vty_out (vty, " Link: %u octets of data%s", ntohs (top->header.length), VTY_NEWLINE); + else + zlog_info (" Link: %u octets of data", ntohs (top->header.length)); + + return TLV_HDR_SIZE; /* Here is special, not "TLV_SIZE". */ +} + +static u_int16_t +show_vty_link_subtlv_link_type (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_link_type *top; + const char *cp = "Unknown"; + + top = (struct te_link_subtlv_link_type *) tlvh; + switch (top->link_type.value) + { + case LINK_TYPE_SUBTLV_VALUE_PTP: + cp = "Point-to-point"; + break; + case LINK_TYPE_SUBTLV_VALUE_MA: + cp = "Multiaccess"; + break; + default: + break; + } + + if (vty != NULL) + vty_out (vty, " Link-Type: %s (%u)%s", cp, top->link_type.value, VTY_NEWLINE); + else + zlog_info (" Link-Type: %s (%u)", cp, top->link_type.value); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_link_id (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_link_id *top; + + top = (struct te_link_subtlv_link_id *) tlvh; + if (vty != NULL) + vty_out (vty, " Link-ID: %s%s", inet_ntoa (top->value), VTY_NEWLINE); + else + zlog_info (" Link-ID: %s", inet_ntoa (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_lclif_ipaddr *top; + int i, n; + + top = (struct te_link_subtlv_lclif_ipaddr *) tlvh; + n = ntohs (tlvh->length) / sizeof (top->value[0]); + + if (vty != NULL) + vty_out (vty, " Local Interface IP Address(es): %d%s", n, VTY_NEWLINE); + else + zlog_info (" Local Interface IP Address(es): %d", n); + + for (i = 0; i < n; i++) + { + if (vty != NULL) + vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE); + else + zlog_info (" #%d: %s", i, inet_ntoa (top->value[i])); + } + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_rmtif_ipaddr *top; + int i, n; + + top = (struct te_link_subtlv_rmtif_ipaddr *) tlvh; + n = ntohs (tlvh->length) / sizeof (top->value[0]); + if (vty != NULL) + vty_out (vty, " Remote Interface IP Address(es): %d%s", n, VTY_NEWLINE); + else + zlog_info (" Remote Interface IP Address(es): %d", n); + + for (i = 0; i < n; i++) + { + if (vty != NULL) + vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE); + else + zlog_info (" #%d: %s", i, inet_ntoa (top->value[i])); + } + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_te_metric (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_te_metric *top; + + top = (struct te_link_subtlv_te_metric *) tlvh; + if (vty != NULL) + vty_out (vty, " Traffic Engineering Metric: %u%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE); + else + zlog_info (" Traffic Engineering Metric: %u", (u_int32_t) ntohl (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_max_bw (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_max_bw *top; + float fval; + + top = (struct te_link_subtlv_max_bw *) tlvh; + ntohf (&top->value, &fval); + + if (vty != NULL) + vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + else + zlog_info (" Maximum Bandwidth: %g (Bytes/sec)", fval); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_max_rsv_bw (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_max_rsv_bw *top; + float fval; + + top = (struct te_link_subtlv_max_rsv_bw *) tlvh; + ntohf (&top->value, &fval); + + if (vty != NULL) + vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); + else + zlog_info (" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_unrsv_bw (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_unrsv_bw *top; + float fval; + int i; + + top = (struct te_link_subtlv_unrsv_bw *) tlvh; + for (i = 0; i < 8; i++) + { + ntohf (&top->value[i], &fval); + if (vty != NULL) + vty_out (vty, " Unreserved Bandwidth (pri %d): %g (Bytes/sec)%s", i, fval, VTY_NEWLINE); + else + zlog_info (" Unreserved Bandwidth (pri %d): %g (Bytes/sec)", i, fval); + } + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_link_subtlv_rsc_clsclr (struct vty *vty, struct te_tlv_header *tlvh) +{ + struct te_link_subtlv_rsc_clsclr *top; + + top = (struct te_link_subtlv_rsc_clsclr *) tlvh; + if (vty != NULL) + vty_out (vty, " Resource class/color: 0x%x%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE); + else + zlog_info (" Resource Class/Color: 0x%x", (u_int32_t) ntohl (top->value)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +show_vty_unknown_tlv (struct vty *vty, struct te_tlv_header *tlvh) +{ + if (vty != NULL) + vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE); + else + zlog_info (" Unknown TLV: [type(0x%x), length(0x%x)]", ntohs (tlvh->type), ntohs (tlvh->length)); + + return TLV_SIZE (tlvh); +} + +static u_int16_t +ospf_mpls_te_show_link_subtlv (struct vty *vty, struct te_tlv_header *tlvh0, + u_int16_t subtotal, u_int16_t total) +{ + struct te_tlv_header *tlvh, *next; + u_int16_t sum = subtotal; + + for (tlvh = tlvh0; sum < total; tlvh = (next ? next : TLV_HDR_NEXT (tlvh))) + { + next = NULL; + switch (ntohs (tlvh->type)) + { + case TE_LINK_SUBTLV_LINK_TYPE: + sum += show_vty_link_subtlv_link_type (vty, tlvh); + break; + case TE_LINK_SUBTLV_LINK_ID: + sum += show_vty_link_subtlv_link_id (vty, tlvh); + break; + case TE_LINK_SUBTLV_LCLIF_IPADDR: + sum += show_vty_link_subtlv_lclif_ipaddr (vty, tlvh); + break; + case TE_LINK_SUBTLV_RMTIF_IPADDR: + sum += show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh); + break; + case TE_LINK_SUBTLV_TE_METRIC: + sum += show_vty_link_subtlv_te_metric (vty, tlvh); + break; + case TE_LINK_SUBTLV_MAX_BW: + sum += show_vty_link_subtlv_max_bw (vty, tlvh); + break; + case TE_LINK_SUBTLV_MAX_RSV_BW: + sum += show_vty_link_subtlv_max_rsv_bw (vty, tlvh); + break; + case TE_LINK_SUBTLV_UNRSV_BW: + sum += show_vty_link_subtlv_unrsv_bw (vty, tlvh); + break; + case TE_LINK_SUBTLV_RSC_CLSCLR: + sum += show_vty_link_subtlv_rsc_clsclr (vty, tlvh); + break; + default: + sum += show_vty_unknown_tlv (vty, tlvh); + break; + } + } + return sum; +} + +static void +ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa) +{ + struct lsa_header *lsah = (struct lsa_header *) lsa->data; + struct te_tlv_header *tlvh, *next; + u_int16_t sum, total; + u_int16_t (* subfunc)(struct vty *vty, struct te_tlv_header *tlvh, + u_int16_t subtotal, u_int16_t total) = NULL; + + sum = 0; + total = ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE; + + for (tlvh = TLV_HDR_TOP (lsah); sum < total; + tlvh = (next ? next : TLV_HDR_NEXT (tlvh))) + { + if (subfunc != NULL) + { + sum = (* subfunc)(vty, tlvh, sum, total); + next = (struct te_tlv_header *)((char *) tlvh + sum); + subfunc = NULL; + continue; + } + + next = NULL; + switch (ntohs (tlvh->type)) + { + case TE_TLV_ROUTER_ADDR: + sum += show_vty_router_addr (vty, tlvh); + break; + case TE_TLV_LINK: + sum += show_vty_link_header (vty, tlvh); + subfunc = ospf_mpls_te_show_link_subtlv; + next = tlvh + 1; + break; + default: + sum += show_vty_unknown_tlv (vty, tlvh); + break; + } + } + return; +} + +static void +ospf_mpls_te_config_write_router (struct vty *vty) +{ + if (OspfMplsTE.status == enabled) + { + vty_out (vty, " mpls-te%s", VTY_NEWLINE); + vty_out (vty, " mpls-te router-address %s%s", + inet_ntoa (OspfMplsTE.router_addr.value), VTY_NEWLINE); + } + return; +} + +static void +ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp) +{ + struct mpls_te_link *lp; + + if ((OspfMplsTE.status == enabled) + && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) + && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) + { + float fval; + int i; + + vty_out (vty, " mpls-te link metric %u%s", + (u_int32_t) ntohl (lp->te_metric.value), VTY_NEWLINE); + + ntohf (&lp->max_bw.value, &fval); + if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) + vty_out (vty, " mpls-te link max-bw %g%s", fval, VTY_NEWLINE); + + ntohf (&lp->max_rsv_bw.value, &fval); + if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) + vty_out (vty, " mpls-te link max-rsv-bw %g%s", fval, VTY_NEWLINE); + + for (i = 0; i < 8; i++) + { + ntohf (&lp->unrsv_bw.value[i], &fval); + if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) + vty_out (vty, " mpls-te link unrsv-bw %d %g%s", + i, fval, VTY_NEWLINE); + } + + vty_out (vty, " mpls-te link rsc-clsclr 0x%x%s", + (u_int32_t) ntohl (lp->rsc_clsclr.value), VTY_NEWLINE); + } + return; +} + +/*------------------------------------------------------------------------* + * Followings are vty command functions. + *------------------------------------------------------------------------*/ + +DEFUN (mpls_te, + mpls_te_cmd, + "mpls-te", + "Configure MPLS-TE parameters\n" + "Enable the MPLS-TE functionality\n") +{ + listnode node; + struct mpls_te_link *lp; + + if (OspfMplsTE.status == enabled) + return CMD_SUCCESS; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("MPLS-TE: OFF -> ON"); + + OspfMplsTE.status = enabled; + + /* + * Following code is intended to handle two cases; + * + * 1) MPLS-TE was disabled at startup time, but now become enabled. + * 2) MPLS-TE was once enabled then disabled, and now enabled again. + */ + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + if ((lp = getdata (node)) != NULL) + initialize_linkparams (lp); + + ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); + + return CMD_SUCCESS; +} + +ALIAS (mpls_te, + mpls_te_on_cmd, + "mpls-te on", + "Configure MPLS-TE parameters\n" + "Enable the MPLS-TE functionality\n"); + +DEFUN (no_mpls_te, + no_mpls_te_cmd, + "no mpls-te", + NO_STR + "Configure MPLS-TE parameters\n" + "Disable the MPLS-TE functionality\n") +{ + listnode node; + struct mpls_te_link *lp; + + if (OspfMplsTE.status == disabled) + return CMD_SUCCESS; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("MPLS-TE: ON -> OFF"); + + OspfMplsTE.status = disabled; + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + if ((lp = getdata (node)) != NULL) + if (lp->area != NULL) + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); + + return CMD_SUCCESS; +} + +DEFUN (mpls_te_router_addr, + mpls_te_router_addr_cmd, + "mpls-te router-address A.B.C.D", + "MPLS-TE specific commands\n" + "Stable IP address of the advertising router\n" + "MPLS-TE router address in IPv4 address format\n") +{ + struct te_tlv_router_addr *ra = &OspfMplsTE.router_addr; + struct in_addr value; + + if (! inet_aton (argv[0], &value)) + { + vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohs (ra->header.type) == 0 + || ntohl (ra->value.s_addr) != ntohl (value.s_addr)) + { + listnode node; + struct mpls_te_link *lp; + int need_to_reoriginate = 0; + + set_mpls_te_router_addr (value); + + if (OspfMplsTE.status == disabled) + goto out; + + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + { + if ((lp = getdata (node)) == NULL) + continue; + if (lp->area == NULL) + continue; + + if ((lp->flags & LPFLG_LSA_ENGAGED) == 0) + { + need_to_reoriginate = 1; + break; + } + } + for (node = listhead (OspfMplsTE.iflist); node; nextnode (node)) + { + if ((lp = getdata (node)) == NULL) + continue; + if (lp->area == NULL) + continue; + + if (need_to_reoriginate) + lp->flags |= LPFLG_LSA_FORCED_REFRESH; + else + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + } + + if (need_to_reoriginate) + ospf_mpls_te_foreach_area ( + ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); + } +out: + return CMD_SUCCESS; +} + +DEFUN (mpls_te_link_metric, + mpls_te_link_metric_cmd, + "mpls-te link metric <0-4294967295>", + "MPLS-TE specific commands\n" + "Configure MPLS-TE link parameters\n" + "Link metric for MPLS-TE purpose\n" + "Metric\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct mpls_te_link *lp; + u_int32_t value; + + if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) + { + vty_out (vty, "mpls_te_link_metric: Something wrong!%s", VTY_NEWLINE); + return CMD_WARNING; + } + + value = strtoul (argv[0], NULL, 10); + + if (ntohs (lp->te_metric.header.type) == 0 + || ntohl (lp->te_metric.value) != value) + { + set_linkparams_te_metric (lp, value); + + if (OspfMplsTE.status == enabled) + if (lp->area != NULL) + { + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + } + } + return CMD_SUCCESS; +} + +DEFUN (mpls_te_link_maxbw, + mpls_te_link_maxbw_cmd, + "mpls-te link max-bw BANDWIDTH", + "MPLS-TE specific commands\n" + "Configure MPLS-TE link parameters\n" + "Maximum bandwidth that can be used\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct mpls_te_link *lp; + float f1, f2; + + if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) + { + vty_out (vty, "mpls_te_link_maxbw: Something wrong!%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ntohf (&lp->max_bw.value, &f1); + if (sscanf (argv[0], "%g", &f2) != 1) + { + vty_out (vty, "mpls_te_link_maxbw: fscanf: %s%s", strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohs (lp->max_bw.header.type) == 0 + || f1 != f2) + { + set_linkparams_max_bw (lp, &f2); + + if (OspfMplsTE.status == enabled) + if (lp->area != NULL) + { + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + } + } + return CMD_SUCCESS; +} + +DEFUN (mpls_te_link_max_rsv_bw, + mpls_te_link_max_rsv_bw_cmd, + "mpls-te link max-rsv-bw BANDWIDTH", + "MPLS-TE specific commands\n" + "Configure MPLS-TE link parameters\n" + "Maximum bandwidth that may be reserved\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct mpls_te_link *lp; + float f1, f2; + + if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) + { + vty_out (vty, "mpls_te_link_max_rsv_bw: Something wrong!%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ntohf (&lp->max_rsv_bw.value, &f1); + if (sscanf (argv[0], "%g", &f2) != 1) + { + vty_out (vty, "mpls_te_link_max_rsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohs (lp->max_rsv_bw.header.type) == 0 + || f1 != f2) + { + set_linkparams_max_rsv_bw (lp, &f2); + + if (OspfMplsTE.status == enabled) + if (lp->area != NULL) + { + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + } + } + return CMD_SUCCESS; +} + +DEFUN (mpls_te_link_unrsv_bw, + mpls_te_link_unrsv_bw_cmd, + "mpls-te link unrsv-bw <0-7> BANDWIDTH", + "MPLS-TE specific commands\n" + "Configure MPLS-TE link parameters\n" + "Unreserved bandwidth at each priority level\n" + "Priority\n" + "Bytes/second (IEEE floating point format)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct mpls_te_link *lp; + int priority; + float f1, f2; + + if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) + { + vty_out (vty, "mpls_te_link_unrsv_bw: Something wrong!%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* We don't have to consider about range check here. */ + if (sscanf (argv[0], "%d", &priority) != 1) + { + vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + ntohf (&lp->unrsv_bw.value [priority], &f1); + if (sscanf (argv[1], "%g", &f2) != 1) + { + vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohs (lp->unrsv_bw.header.type) == 0 + || f1 != f2) + { + set_linkparams_unrsv_bw (lp, priority, &f2); + + if (OspfMplsTE.status == enabled) + if (lp->area != NULL) + { + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + } + } + return CMD_SUCCESS; +} + +DEFUN (mpls_te_link_rsc_clsclr, + mpls_te_link_rsc_clsclr_cmd, + "mpls-te link rsc-clsclr BITPATTERN", + "MPLS-TE specific commands\n" + "Configure MPLS-TE link parameters\n" + "Administrative group membership\n" + "32-bit Hexadecimal value (ex. 0xa1)\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct mpls_te_link *lp; + unsigned long value; + + if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) + { + vty_out (vty, "mpls_te_link_rsc_clsclr: Something wrong!%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (sscanf (argv[0], "0x%lx", &value) != 1) + { + vty_out (vty, "mpls_te_link_rsc_clsclr: fscanf: %s%s", strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + if (ntohs (lp->rsc_clsclr.header.type) == 0 + || ntohl (lp->rsc_clsclr.value) != value) + { + set_linkparams_rsc_clsclr (lp, value); + + if (OspfMplsTE.status == enabled) + if (lp->area != NULL) + { + if (lp->flags & LPFLG_LSA_ENGAGED) + ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); + } + } + return CMD_SUCCESS; +} + +DEFUN (show_mpls_te_router, + show_mpls_te_router_cmd, + "show mpls-te router", + SHOW_STR + "MPLS-TE information\n" + "Router information\n") +{ + if (OspfMplsTE.status == enabled) + { + vty_out (vty, "--- MPLS-TE router parameters ---%s", + VTY_NEWLINE); + + if (ntohs (OspfMplsTE.router_addr.header.type) != 0) + show_vty_router_addr (vty, &OspfMplsTE.router_addr.header); + else if (vty != NULL) + vty_out (vty, " N/A%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +static void +show_mpls_te_link_sub (struct vty *vty, struct interface *ifp) +{ + struct mpls_te_link *lp; + struct te_tlv_header *tlvh; + + if ((OspfMplsTE.status == enabled) + && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) + && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) + { + vty_out (vty, "-- MPLS-TE link parameters for %s --%s", + ifp->name, VTY_NEWLINE); + + show_vty_link_subtlv_link_type (vty, &lp->link_type.header); + show_vty_link_subtlv_link_id (vty, &lp->link_id.header); + + if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL) + show_vty_link_subtlv_lclif_ipaddr (vty, tlvh); + if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL) + show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh); + + show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header); + + show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header); + show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header); + show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header); + show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header); + } + else + { + vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", + ifp->name, VTY_NEWLINE); + } + + return; +} + +DEFUN (show_mpls_te_link, + show_mpls_te_link_cmd, + "show mpls-te interface [INTERFACE]", + SHOW_STR + "MPLS-TE information\n" + "Interface information\n" + "Interface name\n") +{ + struct interface *ifp; + listnode node; + + /* Show All Interfaces. */ + if (argc == 0) + for (node = listhead (iflist); node; nextnode (node)) + show_mpls_te_link_sub (vty, node->data); + /* Interface name is specified. */ + else + { + if ((ifp = if_lookup_by_name (argv[0])) == NULL) + vty_out (vty, "No such interface name%s", VTY_NEWLINE); + else + show_mpls_te_link_sub (vty, ifp); + } + + return CMD_SUCCESS; +} + +static void +ospf_mpls_te_register_vty (void) +{ + install_element (VIEW_NODE, &show_mpls_te_router_cmd); + install_element (VIEW_NODE, &show_mpls_te_link_cmd); + install_element (ENABLE_NODE, &show_mpls_te_router_cmd); + install_element (ENABLE_NODE, &show_mpls_te_link_cmd); + + install_element (OSPF_NODE, &mpls_te_cmd); + install_element (OSPF_NODE, &no_mpls_te_cmd); + install_element (OSPF_NODE, &mpls_te_on_cmd); + install_element (OSPF_NODE, &mpls_te_router_addr_cmd); + + install_element (INTERFACE_NODE, &mpls_te_link_metric_cmd); + install_element (INTERFACE_NODE, &mpls_te_link_maxbw_cmd); + install_element (INTERFACE_NODE, &mpls_te_link_max_rsv_bw_cmd); + install_element (INTERFACE_NODE, &mpls_te_link_unrsv_bw_cmd); + install_element (INTERFACE_NODE, &mpls_te_link_rsc_clsclr_cmd); + + return; +} + +#endif /* HAVE_OSPF_TE */ diff --git a/ospfd/ospf_te.h b/ospfd/ospf_te.h new file mode 100644 index 0000000..8a7a98c --- /dev/null +++ b/ospfd/ospf_te.h @@ -0,0 +1,193 @@ +/* + * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt + * Copyright (C) 2001 KDD R&D Laboratories, Inc. + * http://www.kddlabs.co.jp/ + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_MPLS_TE_H +#define _ZEBRA_OSPF_MPLS_TE_H + +/* + * Opaque LSA's link state ID for Traffic Engineering is + * structured as follows. + * + * 24 16 8 0 + * +--------+--------+--------+--------+ + * | 1 | MBZ |........|........| + * +--------+--------+--------+--------+ + * |<-Type->||<-- Instance --->| + * + * + * Type: IANA has assigned '1' for Traffic Engineering. + * MBZ: Reserved, must be set to zero. + * Instance: User may select an arbitrary 16-bit value. + * + */ + +#define LEGAL_TE_INSTANCE_RANGE(i) (0 <= (i) && (i) <= 0xffff) + +/* + * 24 16 8 0 + * +--------+--------+--------+--------+ --- + * | LS age |Options | 10 | A + * +--------+--------+--------+--------+ | + * | 1 | 0 | Instance | | + * +--------+--------+--------+--------+ | + * | Advertising router | | Standard (Opaque) LSA header; + * +--------+--------+--------+--------+ | Only type-10 is used. + * | LS sequence number | | + * +--------+--------+--------+--------+ | + * | LS checksum | Length | V + * +--------+--------+--------+--------+ --- + * | Type | Length | A + * +--------+--------+--------+--------+ | TLV part for TE; Values might be + * | Values ... | V structured as a set of sub-TLVs. + * +--------+--------+--------+--------+ --- + */ + +/* + * Following section defines TLV (tag, length, value) structures, + * used for Traffic Engineering. + */ +struct te_tlv_header +{ + u_int16_t type; /* TE_TLV_XXX (see below) */ + u_int16_t length; /* Value portion only, in octets */ +}; + +#define TLV_HDR_SIZE \ + sizeof (struct te_tlv_header) + +#define TLV_BODY_SIZE(tlvh) \ + ROUNDUP (ntohs ((tlvh)->length), sizeof (u_int32_t)) + +#define TLV_SIZE(tlvh) \ + (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)) + +#define TLV_HDR_TOP(lsah) \ + (struct te_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE) + +#define TLV_HDR_NEXT(tlvh) \ + (struct te_tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh)) + +/* + * Following section defines TLV body parts. + */ +/* Router Address TLV *//* Mandatory */ +#define TE_TLV_ROUTER_ADDR 1 +struct te_tlv_router_addr +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + struct in_addr value; +}; + +/* Link TLV */ +#define TE_TLV_LINK 2 +struct te_tlv_link +{ + struct te_tlv_header header; + /* A set of link-sub-TLVs will follow. */ +}; + +/* Link Type Sub-TLV *//* Mandatory */ +#define TE_LINK_SUBTLV_LINK_TYPE 1 +struct te_link_subtlv_link_type +{ + struct te_tlv_header header; /* Value length is 1 octet. */ + struct { +#define LINK_TYPE_SUBTLV_VALUE_PTP 1 +#define LINK_TYPE_SUBTLV_VALUE_MA 2 + u_char value; + u_char padding[3]; + } link_type; +}; + +/* Link Sub-TLV: Link ID *//* Mandatory */ +#define TE_LINK_SUBTLV_LINK_ID 2 +struct te_link_subtlv_link_id +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + struct in_addr value; /* Same as router-lsa's link-id. */ +}; + +/* Link Sub-TLV: Local Interface IP Address *//* Optional */ +#define TE_LINK_SUBTLV_LCLIF_IPADDR 3 +struct te_link_subtlv_lclif_ipaddr +{ + struct te_tlv_header header; /* Value length is 4 x N octets. */ + struct in_addr value[1]; /* Local IP address(es). */ +}; + +/* Link Sub-TLV: Remote Interface IP Address *//* Optional */ +#define TE_LINK_SUBTLV_RMTIF_IPADDR 4 +struct te_link_subtlv_rmtif_ipaddr +{ + struct te_tlv_header header; /* Value length is 4 x N octets. */ + struct in_addr value[1]; /* Neighbor's IP address(es). */ +}; + +/* Link Sub-TLV: Traffic Engineering Metric *//* Optional */ +#define TE_LINK_SUBTLV_TE_METRIC 5 +struct te_link_subtlv_te_metric +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + u_int32_t value; /* Link metric for TE purpose. */ +}; + +/* Link Sub-TLV: Maximum Bandwidth *//* Optional */ +#define TE_LINK_SUBTLV_MAX_BW 6 +struct te_link_subtlv_max_bw +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + float value; /* bytes/sec */ +}; + +/* Link Sub-TLV: Maximum Reservable Bandwidth *//* Optional */ +#define TE_LINK_SUBTLV_MAX_RSV_BW 7 +struct te_link_subtlv_max_rsv_bw +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + float value; /* bytes/sec */ +}; + +/* Link Sub-TLV: Unreserved Bandwidth *//* Optional */ +#define TE_LINK_SUBTLV_UNRSV_BW 8 +struct te_link_subtlv_unrsv_bw +{ + struct te_tlv_header header; /* Value length is 32 octets. */ + float value[8]; /* One for each priority level. */ +}; + +/* Link Sub-TLV: Resource Class/Color *//* Optional */ +#define TE_LINK_SUBTLV_RSC_CLSCLR 9 +struct te_link_subtlv_rsc_clsclr +{ + struct te_tlv_header header; /* Value length is 4 octets. */ + u_int32_t value; /* Admin. group membership. */ +}; + +/* Here are "non-official" architechtual constants. */ +#define MPLS_TE_MINIMUM_BANDWIDTH 1.0 /* Reasonable? *//* XXX */ + +/* Prototypes. */ +extern int ospf_mpls_te_init (void); +extern void ospf_mpls_te_term (void); + +#endif /* _ZEBRA_OSPF_MPLS_TE_H */ diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c new file mode 100644 index 0000000..ee15b2e --- /dev/null +++ b/ospfd/ospf_vty.c @@ -0,0 +1,7719 @@ +/* OSPF VTY interface. + * Copyright (C) 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "thread.h" +#include "prefix.h" +#include "table.h" +#include "vty.h" +#include "command.h" +#include "plist.h" +#include "log.h" +#include "zclient.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" +/*#include "ospfd/ospf_routemap.h" */ +#include "ospfd/ospf_vty.h" +#include "ospfd/ospf_dump.h" + + +static char *ospf_network_type_str[] = + { + "Null", + "POINTOPOINT", + "BROADCAST", + "NBMA", + "POINTOMULTIPOINT", + "VIRTUALLINK", + "LOOPBACK" + }; + + +/* Utility functions. */ +int +ospf_str2area_id (char *str, struct in_addr *area_id, int *format) +{ + char *endptr = NULL; + unsigned long ret; + + /* match "A.B.C.D". */ + if (strchr (str, '.') != NULL) + { + ret = inet_aton (str, area_id); + if (!ret) + return -1; + *format = OSPF_AREA_ID_FORMAT_ADDRESS; + } + /* match "<0-4294967295>". */ + else + { + ret = strtoul (str, &endptr, 10); + if (*endptr != '\0' || (ret == ULONG_MAX && errno == ERANGE)) + return -1; + + area_id->s_addr = htonl (ret); + *format = OSPF_AREA_ID_FORMAT_DECIMAL; + } + + return 0; +} + + +int +str2distribute_source (char *str, int *source) +{ + /* Sanity check. */ + if (str == NULL) + return 0; + + if (strncmp (str, "k", 1) == 0) + *source = ZEBRA_ROUTE_KERNEL; + else if (strncmp (str, "c", 1) == 0) + *source = ZEBRA_ROUTE_CONNECT; + else if (strncmp (str, "s", 1) == 0) + *source = ZEBRA_ROUTE_STATIC; + else if (strncmp (str, "r", 1) == 0) + *source = ZEBRA_ROUTE_RIP; + else if (strncmp (str, "b", 1) == 0) + *source = ZEBRA_ROUTE_BGP; + else + return 0; + + return 1; +} + +int +str2metric (char *str, int *metric) +{ + /* Sanity check. */ + if (str == NULL) + return 0; + + *metric = strtol (str, NULL, 10); + if (*metric < 0 && *metric > 16777214) + { + /* vty_out (vty, "OSPF metric value is invalid%s", VTY_NEWLINE); */ + return 0; + } + + return 1; +} + +int +str2metric_type (char *str, int *metric_type) +{ + /* Sanity check. */ + if (str == NULL) + return 0; + + if (strncmp (str, "1", 1) == 0) + *metric_type = EXTERNAL_METRIC_TYPE_1; + else if (strncmp (str, "2", 1) == 0) + *metric_type = EXTERNAL_METRIC_TYPE_2; + else + return 0; + + return 1; +} + +int +ospf_oi_count (struct interface *ifp) +{ + struct route_node *rn; + int i = 0; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + if (rn->info) + i++; + + return i; +} + + +DEFUN (router_ospf, + router_ospf_cmd, + "router ospf", + "Enable a routing process\n" + "Start OSPF configuration\n") +{ + vty->node = OSPF_NODE; + vty->index = ospf_get (); + + return CMD_SUCCESS; +} + +DEFUN (no_router_ospf, + no_router_ospf_cmd, + "no router ospf", + NO_STR + "Enable a routing process\n" + "Start OSPF configuration\n") +{ + struct ospf *ospf; + + ospf = ospf_lookup (); + if (ospf == NULL) + { + vty_out (vty, "There isn't active ospf instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ospf_finish (ospf); + + return CMD_SUCCESS; +} + +DEFUN (ospf_router_id, + ospf_router_id_cmd, + "ospf router-id A.B.C.D", + "OSPF specific commands\n" + "router-id for the OSPF process\n" + "OSPF router-id in IP address format\n") +{ + struct ospf *ospf = vty->index; + struct in_addr router_id; + int ret; + + ret = inet_aton (argv[0], &router_id); + if (!ret) + { + vty_out (vty, "Please specify Router ID by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ospf->router_id_static = router_id; + + if (ospf->t_router_id_update == NULL) + OSPF_TIMER_ON (ospf->t_router_id_update, ospf_router_id_update_timer, + OSPF_ROUTER_ID_UPDATE_DELAY); + + return CMD_SUCCESS; +} + +ALIAS (ospf_router_id, + router_ospf_id_cmd, + "router-id A.B.C.D", + "router-id for the OSPF process\n" + "OSPF router-id in IP address format\n"); + +DEFUN (no_ospf_router_id, + no_ospf_router_id_cmd, + "no ospf router-id", + NO_STR + "OSPF specific commands\n" + "router-id for the OSPF process\n") +{ + struct ospf *ospf = vty->index; + + ospf->router_id_static.s_addr = 0; + + ospf_router_id_update (ospf); + + return CMD_SUCCESS; +} + +ALIAS (no_ospf_router_id, + no_router_ospf_id_cmd, + "no router-id", + NO_STR + "router-id for the OSPF process\n"); + +DEFUN (ospf_passive_interface, + ospf_passive_interface_addr_cmd, + "passive-interface IFNAME A.B.C.D", + "Suppress routing updates on an interface\n" + "Interface's name\n") +{ + struct interface *ifp; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = if_lookup_by_name (argv[0]); + + if (ifp == NULL) + { + vty_out (vty, "Please specify an existing interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + + params = IF_DEF_PARAMS (ifp); + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, passive_interface); + params->passive_interface = OSPF_IF_PASSIVE; + + return CMD_SUCCESS; +} + +ALIAS (ospf_passive_interface, + ospf_passive_interface_cmd, + "passive-interface IFNAME", + "Suppress routing updates on an interface\n" + "Interface's name\n"); + +DEFUN (no_ospf_passive_interface, + no_ospf_passive_interface_addr_cmd, + "no passive-interface IFNAME A.B.C.D", + NO_STR + "Allow routing updates on an interface\n" + "Interface's name\n") +{ + struct interface *ifp; + struct in_addr addr; + struct ospf_if_params *params; + int ret; + + ifp = if_lookup_by_name (argv[0]); + + if (ifp == NULL) + { + vty_out (vty, "Please specify an existing interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + + params = IF_DEF_PARAMS (ifp); + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, passive_interface); + params->passive_interface = OSPF_IF_ACTIVE; + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ospf_passive_interface, + no_ospf_passive_interface_cmd, + "no passive-interface IFNAME", + NO_STR + "Allow routing updates on an interface\n" + "Interface's name\n"); + +DEFUN (ospf_network_area, + ospf_network_area_cmd, + "network A.B.C.D/M area (A.B.C.D|<0-4294967295>)", + "Enable routing on an IP network\n" + "OSPF network prefix\n" + "Set the OSPF area ID\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n") +{ + struct ospf *ospf= vty->index; + struct prefix_ipv4 p; + struct in_addr area_id; + int ret, format; + + /* Get network prefix and Area ID. */ + VTY_GET_IPV4_PREFIX ("network prefix", p, argv[0]); + VTY_GET_OSPF_AREA_ID (area_id, format, argv[1]); + + ret = ospf_network_set (ospf, &p, area_id); + if (ret == 0) + { + vty_out (vty, "There is already same network statement.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_network_area, + no_ospf_network_area_cmd, + "no network A.B.C.D/M area (A.B.C.D|<0-4294967295>)", + NO_STR + "Enable routing on an IP network\n" + "OSPF network prefix\n" + "Set the OSPF area ID\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n") +{ + struct ospf *ospf = (struct ospf *) vty->index; + struct prefix_ipv4 p; + struct in_addr area_id; + int ret, format; + + /* Get network prefix and Area ID. */ + VTY_GET_IPV4_PREFIX ("network prefix", p, argv[0]); + VTY_GET_OSPF_AREA_ID (area_id, format, argv[1]); + + ret = ospf_network_unset (ospf, &p, area_id); + if (ret == 0) + { + vty_out (vty, "Can't find specified network area configuration.%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + + +DEFUN (ospf_area_range, + ospf_area_range_cmd, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n") +{ + struct ospf *ospf = vty->index; + struct prefix_ipv4 p; + struct in_addr area_id; + int format; + u_int32_t cost; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); + + ospf_area_range_set (ospf, area_id, &p, OSPF_AREA_RANGE_ADVERTISE); + if (argc > 2) + { + VTY_GET_UINT32 ("range cost", cost, argv[2]); + ospf_area_range_cost_set (ospf, area_id, &p, cost); + } + + return CMD_SUCCESS; +} + +ALIAS (ospf_area_range, + ospf_area_range_advertise_cmd, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "OSPF area range for route advertise (default)\n" + "Area range prefix\n" + "Advertise this range (default)\n"); + +ALIAS (ospf_area_range, + ospf_area_range_cost_cmd, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "User specified metric for this range\n" + "Advertised metric for this range\n"); + +ALIAS (ospf_area_range, + ospf_area_range_advertise_cost_cmd, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Advertise this range (default)\n" + "User specified metric for this range\n" + "Advertised metric for this range\n"); + +DEFUN (ospf_area_range_not_advertise, + ospf_area_range_not_advertise_cmd, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M not-advertise", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "DoNotAdvertise this range\n") +{ + struct ospf *ospf = vty->index; + struct prefix_ipv4 p; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); + + ospf_area_range_set (ospf, area_id, &p, 0); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_area_range, + no_ospf_area_range_cmd, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n") +{ + struct ospf *ospf = vty->index; + struct prefix_ipv4 p; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); + + ospf_area_range_unset (ospf, area_id, &p); + + return CMD_SUCCESS; +} + +ALIAS (no_ospf_area_range, + no_ospf_area_range_advertise_cmd, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M (advertise|not-advertise)", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Advertise this range (default)\n" + "DoNotAdvertise this range\n"); + +ALIAS (no_ospf_area_range, + no_ospf_area_range_cost_cmd, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "User specified metric for this range\n" + "Advertised metric for this range\n"); + +ALIAS (no_ospf_area_range, + no_ospf_area_range_advertise_cost_cmd, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Advertise this range (default)\n" + "User specified metric for this range\n" + "Advertised metric for this range\n"); + +DEFUN (ospf_area_range_substitute, + ospf_area_range_substitute_cmd, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Announce area range as another prefix\n" + "Network prefix to be announced instead of range\n") +{ + struct ospf *ospf = vty->index; + struct prefix_ipv4 p, s; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); + VTY_GET_IPV4_PREFIX ("substituted network prefix", s, argv[2]); + + ospf_area_range_substitute_set (ospf, area_id, &p, &s); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_area_range_substitute, + no_ospf_area_range_substitute_cmd, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Announce area range as another prefix\n" + "Network prefix to be announced instead of range\n") +{ + struct ospf *ospf = vty->index; + struct prefix_ipv4 p, s; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); + VTY_GET_IPV4_PREFIX ("substituted network prefix", s, argv[2]); + + ospf_area_range_substitute_unset (ospf, area_id, &p); + + return CMD_SUCCESS; +} + + +/* Command Handler Logic in VLink stuff is delicate!! + +ALTER AT YOUR OWN RISK!!!! + +Various dummy values are used to represent 'NoChange' state for +VLink configuration NOT being changed by a VLink command, and +special syntax is used within the command strings so that the +typed in command verbs can be seen in the configuration command +bacckend handler. This is to drastically reduce the verbeage +required to coe up with a reasonably compatible Cisco VLink command + +- Matthew Grant +Wed, 21 Feb 2001 15:13:52 +1300 +*/ + + +/* Configuration data for virtual links + */ +struct ospf_vl_config_data { + struct vty *vty; /* vty stuff */ + struct in_addr area_id; /* area ID from command line */ + int format; /* command line area ID format */ + struct in_addr vl_peer; /* command line vl_peer */ + int auth_type; /* Authehntication type, if given */ + char *auth_key; /* simple password if present */ + int crypto_key_id; /* Cryptographic key ID */ + char *md5_key; /* MD5 authentication key */ + int hello_interval; /* Obvious what these are... */ + int retransmit_interval; + int transmit_delay; + int dead_interval; +}; + +void +ospf_vl_config_data_init (struct ospf_vl_config_data *vl_config, + struct vty *vty) +{ + memset (vl_config, 0, sizeof (struct ospf_vl_config_data)); + vl_config->auth_type = OSPF_AUTH_CMD_NOTSEEN; + vl_config->vty = vty; +} + +struct ospf_vl_data * +ospf_find_vl_data (struct ospf *ospf, struct ospf_vl_config_data *vl_config) +{ + struct ospf_area *area; + struct ospf_vl_data *vl_data; + struct vty *vty; + struct in_addr area_id; + + vty = vl_config->vty; + area_id = vl_config->area_id; + + if (area_id.s_addr == OSPF_AREA_BACKBONE) + { + vty_out (vty, + "Configuring VLs over the backbone is not allowed%s", + VTY_NEWLINE); + return NULL; + } + area = ospf_area_get (ospf, area_id, vl_config->format); + + if (area->external_routing != OSPF_AREA_DEFAULT) + { + if (vl_config->format == OSPF_AREA_ID_FORMAT_ADDRESS) + vty_out (vty, "Area %s is %s%s", + inet_ntoa (area_id), +#ifdef HAVE_NSSA + area->external_routing == OSPF_AREA_NSSA?"nssa":"stub", +#else + "stub", +#endif /* HAVE_NSSA */ + VTY_NEWLINE); + else + vty_out (vty, "Area %ld is %s%s", + (u_long)ntohl (area_id.s_addr), +#ifdef HAVE_NSSA + area->external_routing == OSPF_AREA_NSSA?"nssa":"stub", +#else + "stub", +#endif /* HAVE_NSSA */ + VTY_NEWLINE); + return NULL; + } + + if ((vl_data = ospf_vl_lookup (area, vl_config->vl_peer)) == NULL) + { + vl_data = ospf_vl_data_new (area, vl_config->vl_peer); + if (vl_data->vl_oi == NULL) + { + vl_data->vl_oi = ospf_vl_new (ospf, vl_data); + ospf_vl_add (ospf, vl_data); + ospf_spf_calculate_schedule (ospf); + } + } + return vl_data; +} + + +int +ospf_vl_set_security (struct ospf_vl_data *vl_data, + struct ospf_vl_config_data *vl_config) +{ + struct crypt_key *ck; + struct vty *vty; + struct interface *ifp = vl_data->vl_oi->ifp; + + vty = vl_config->vty; + + if (vl_config->auth_type != OSPF_AUTH_CMD_NOTSEEN) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type); + IF_DEF_PARAMS (ifp)->auth_type = vl_config->auth_type; + } + + if (vl_config->auth_key) + { + memset(IF_DEF_PARAMS (ifp)->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE+1); + strncpy (IF_DEF_PARAMS (ifp)->auth_simple, vl_config->auth_key, + OSPF_AUTH_SIMPLE_SIZE); + } + else if (vl_config->md5_key) + { + if (ospf_crypt_key_lookup (IF_DEF_PARAMS (ifp)->auth_crypt, vl_config->crypto_key_id) + != NULL) + { + vty_out (vty, "OSPF: Key %d already exists%s", + vl_config->crypto_key_id, VTY_NEWLINE); + return CMD_WARNING; + } + ck = ospf_crypt_key_new (); + ck->key_id = vl_config->crypto_key_id; + memset(ck->auth_key, 0, OSPF_AUTH_MD5_SIZE+1); + strncpy (ck->auth_key, vl_config->md5_key, OSPF_AUTH_MD5_SIZE); + + ospf_crypt_key_add (IF_DEF_PARAMS (ifp)->auth_crypt, ck); + } + else if (vl_config->crypto_key_id != 0) + { + /* Delete a key */ + + if (ospf_crypt_key_lookup (IF_DEF_PARAMS (ifp)->auth_crypt, + vl_config->crypto_key_id) == NULL) + { + vty_out (vty, "OSPF: Key %d does not exist%s", + vl_config->crypto_key_id, VTY_NEWLINE); + return CMD_WARNING; + } + + ospf_crypt_key_delete (IF_DEF_PARAMS (ifp)->auth_crypt, vl_config->crypto_key_id); + + } + + return CMD_SUCCESS; +} + + + +int +ospf_vl_set_timers (struct ospf_vl_data *vl_data, + struct ospf_vl_config_data *vl_config) +{ + struct interface *ifp = ifp = vl_data->vl_oi->ifp; + /* Virtual Link data initialised to defaults, so only set + if a value given */ + if (vl_config->hello_interval) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello); + IF_DEF_PARAMS (ifp)->v_hello = vl_config->hello_interval; + } + + if (vl_config->dead_interval) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait); + IF_DEF_PARAMS (ifp)->v_wait = vl_config->dead_interval; + } + + if (vl_config->retransmit_interval) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), retransmit_interval); + IF_DEF_PARAMS (ifp)->retransmit_interval + = vl_config->retransmit_interval; + } + + if (vl_config->transmit_delay) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), transmit_delay); + IF_DEF_PARAMS (ifp)->transmit_delay = vl_config->transmit_delay; + } + + return CMD_SUCCESS; +} + + + +/* The business end of all of the above */ +int +ospf_vl_set (struct ospf *ospf, struct ospf_vl_config_data *vl_config) +{ + struct ospf_vl_data *vl_data; + int ret; + + vl_data = ospf_find_vl_data (ospf, vl_config); + if (!vl_data) + return CMD_WARNING; + + /* Process this one first as it can have a fatal result, which can + only logically occur if the virtual link exists already + Thus a command error does not result in a change to the + running configuration such as unexpectedly altered timer + values etc.*/ + ret = ospf_vl_set_security (vl_data, vl_config); + if (ret != CMD_SUCCESS) + return ret; + + /* Set any time based parameters, these area already range checked */ + + ret = ospf_vl_set_timers (vl_data, vl_config); + if (ret != CMD_SUCCESS) + return ret; + + return CMD_SUCCESS; + +} + +/* This stuff exists to make specifying all the alias commands A LOT simpler + */ +#define VLINK_HELPSTR_IPADDR \ + "OSPF area parameters\n" \ + "OSPF area ID in IP address format\n" \ + "OSPF area ID as a decimal value\n" \ + "Configure a virtual link\n" \ + "Router ID of the remote ABR\n" + +#define VLINK_HELPSTR_AUTHTYPE_SIMPLE \ + "Enable authentication on this virtual link\n" \ + "dummy string \n" + +#define VLINK_HELPSTR_AUTHTYPE_ALL \ + VLINK_HELPSTR_AUTHTYPE_SIMPLE \ + "Use null authentication\n" \ + "Use message-digest authentication\n" + +#define VLINK_HELPSTR_TIME_PARAM_NOSECS \ + "Time between HELLO packets\n" \ + "Time between retransmitting lost link state advertisements\n" \ + "Link state transmit delay\n" \ + "Interval after which a neighbor is declared dead\n" + +#define VLINK_HELPSTR_TIME_PARAM \ + VLINK_HELPSTR_TIME_PARAM_NOSECS \ + "Seconds\n" + +#define VLINK_HELPSTR_AUTH_SIMPLE \ + "Authentication password (key)\n" \ + "The OSPF password (key)" + +#define VLINK_HELPSTR_AUTH_MD5 \ + "Message digest authentication password (key)\n" \ + "dummy string \n" \ + "Key ID\n" \ + "Use MD5 algorithm\n" \ + "The OSPF password (key)" + +DEFUN (ospf_area_vlink, + ospf_area_vlink_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D", + VLINK_HELPSTR_IPADDR) +{ + struct ospf *ospf = vty->index; + struct ospf_vl_config_data vl_config; + char auth_key[OSPF_AUTH_SIMPLE_SIZE+1]; + char md5_key[OSPF_AUTH_MD5_SIZE+1]; + int i; + int ret; + + ospf_vl_config_data_init(&vl_config, vty); + + /* Read off first 2 parameters and check them */ + ret = ospf_str2area_id (argv[0], &vl_config.area_id, &vl_config.format); + if (ret < 0) + { + vty_out (vty, "OSPF area ID is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = inet_aton (argv[1], &vl_config.vl_peer); + if (! ret) + { + vty_out (vty, "Please specify valid Router ID as a.b.c.d%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc <=2) + { + /* Thats all folks! - BUGS B. strikes again!!!*/ + + return ospf_vl_set (ospf, &vl_config); + } + + /* Deal with other parameters */ + for (i=2; i < argc; i++) + { + + /* vty_out (vty, "argv[%d] - %s%s", i, argv[i], VTY_NEWLINE); */ + + switch (argv[i][0]) + { + + case 'a': + if (i > 2 || strncmp (argv[i], "authentication-", 15) == 0) + { + /* authentication-key - this option can occur anywhere on + command line. At start of command line + must check for authentication option. */ + memset (auth_key, 0, OSPF_AUTH_SIMPLE_SIZE + 1); + strncpy (auth_key, argv[i+1], OSPF_AUTH_SIMPLE_SIZE); + vl_config.auth_key = auth_key; + i++; + } + else if (strncmp (argv[i], "authentication", 14) == 0) + { + /* authentication - this option can only occur at start + of command line */ + vl_config.auth_type = OSPF_AUTH_SIMPLE; + if ((i+1) < argc) + { + if (strncmp (argv[i+1], "n", 1) == 0) + { + /* "authentication null" */ + vl_config.auth_type = OSPF_AUTH_NULL; + i++; + } + else if (strncmp (argv[i+1], "m", 1) == 0 + && strcmp (argv[i+1], "message-digest-") != 0) + { + /* "authentication message-digest" */ + vl_config.auth_type = OSPF_AUTH_CRYPTOGRAPHIC; + i++; + } + } + } + break; + + case 'm': + /* message-digest-key */ + i++; + vl_config.crypto_key_id = strtol (argv[i], NULL, 10); + if (vl_config.crypto_key_id < 0) + return CMD_WARNING; + i++; + memset(md5_key, 0, OSPF_AUTH_MD5_SIZE+1); + strncpy (md5_key, argv[i], OSPF_AUTH_MD5_SIZE); + vl_config.md5_key = md5_key; + break; + + case 'h': + /* Hello interval */ + i++; + vl_config.hello_interval = strtol (argv[i], NULL, 10); + if (vl_config.hello_interval < 0) + return CMD_WARNING; + break; + + case 'r': + /* Retransmit Interval */ + i++; + vl_config.retransmit_interval = strtol (argv[i], NULL, 10); + if (vl_config.retransmit_interval < 0) + return CMD_WARNING; + break; + + case 't': + /* Transmit Delay */ + i++; + vl_config.transmit_delay = strtol (argv[i], NULL, 10); + if (vl_config.transmit_delay < 0) + return CMD_WARNING; + break; + + case 'd': + /* Dead Interval */ + i++; + vl_config.dead_interval = strtol (argv[i], NULL, 10); + if (vl_config.dead_interval < 0) + return CMD_WARNING; + break; + } + } + + + /* Action configuration */ + + return ospf_vl_set (ospf, &vl_config); + +} + +DEFUN (no_ospf_area_vlink, + no_ospf_area_vlink_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D", + NO_STR + VLINK_HELPSTR_IPADDR) +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct ospf_vl_config_data vl_config; + struct ospf_vl_data *vl_data = NULL; + char auth_key[OSPF_AUTH_SIMPLE_SIZE+1]; + int i; + int ret, format; + + ospf_vl_config_data_init(&vl_config, vty); + + ret = ospf_str2area_id (argv[0], &vl_config.area_id, &format); + if (ret < 0) + { + vty_out (vty, "OSPF area ID is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + area = ospf_area_lookup_by_area_id (ospf, vl_config.area_id); + if (!area) + { + vty_out (vty, "Area does not exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = inet_aton (argv[1], &vl_config.vl_peer); + if (! ret) + { + vty_out (vty, "Please specify valid Router ID as a.b.c.d%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc <=2) + { + /* Basic VLink no command */ + /* Thats all folks! - BUGS B. strikes again!!!*/ + if ((vl_data = ospf_vl_lookup (area, vl_config.vl_peer))) + ospf_vl_delete (ospf, vl_data); + + ospf_area_check_free (ospf, vl_config.area_id); + + return CMD_SUCCESS; + } + + /* If we are down here, we are reseting parameters */ + + /* Deal with other parameters */ + for (i=2; i < argc; i++) + { + /* vty_out (vty, "argv[%d] - %s%s", i, argv[i], VTY_NEWLINE); */ + + switch (argv[i][0]) + { + + case 'a': + if (i > 2 || strncmp (argv[i], "authentication-", 15) == 0) + { + /* authentication-key - this option can occur anywhere on + command line. At start of command line + must check for authentication option. */ + memset (auth_key, 0, OSPF_AUTH_SIMPLE_SIZE + 1); + vl_config.auth_key = auth_key; + } + else if (strncmp (argv[i], "authentication", 14) == 0) + { + /* authentication - this option can only occur at start + of command line */ + vl_config.auth_type = OSPF_AUTH_NOTSET; + } + break; + + case 'm': + /* message-digest-key */ + /* Delete one key */ + i++; + vl_config.crypto_key_id = strtol (argv[i], NULL, 10); + if (vl_config.crypto_key_id < 0) + return CMD_WARNING; + vl_config.md5_key = NULL; + break; + + case 'h': + /* Hello interval */ + vl_config.hello_interval = OSPF_HELLO_INTERVAL_DEFAULT; + break; + + case 'r': + /* Retransmit Interval */ + vl_config.retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + break; + + case 't': + /* Transmit Delay */ + vl_config.transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; + break; + + case 'd': + /* Dead Interval */ + i++; + vl_config.dead_interval = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; + break; + } + } + + + /* Action configuration */ + + return ospf_vl_set (ospf, &vl_config); +} + +ALIAS (ospf_area_vlink, + ospf_area_vlink_param1_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM); + +ALIAS (no_ospf_area_vlink, + no_ospf_area_vlink_param1_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM); + +ALIAS (ospf_area_vlink, + ospf_area_vlink_param2_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM); + +ALIAS (no_ospf_area_vlink, + no_ospf_area_vlink_param2_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM); + +ALIAS (ospf_area_vlink, + ospf_area_vlink_param3_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM); + +ALIAS (no_ospf_area_vlink, + no_ospf_area_vlink_param3_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM); + +ALIAS (ospf_area_vlink, + ospf_area_vlink_param4_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM); + +ALIAS (no_ospf_area_vlink, + no_ospf_area_vlink_param4_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM + VLINK_HELPSTR_TIME_PARAM); + +ALIAS (ospf_area_vlink, + ospf_area_vlink_authtype_args_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) (message-digest|null)", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_ALL); + +ALIAS (ospf_area_vlink, + ospf_area_vlink_authtype_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|)", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_SIMPLE); + +ALIAS (no_ospf_area_vlink, + no_ospf_area_vlink_authtype_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_SIMPLE); + +ALIAS (ospf_area_vlink, + ospf_area_vlink_md5_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(message-digest-key|) <1-255> md5 KEY", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTH_MD5); + +ALIAS (no_ospf_area_vlink, + no_ospf_area_vlink_md5_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(message-digest-key|) <1-255>", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTH_MD5); + +ALIAS (ospf_area_vlink, + ospf_area_vlink_authkey_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication-key|) AUTH_KEY", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTH_SIMPLE); + +ALIAS (no_ospf_area_vlink, + no_ospf_area_vlink_authkey_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication-key|)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTH_SIMPLE); + +ALIAS (ospf_area_vlink, + ospf_area_vlink_authtype_args_authkey_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) (message-digest|null) " + "(authentication-key|) AUTH_KEY", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_ALL + VLINK_HELPSTR_AUTH_SIMPLE); + +ALIAS (ospf_area_vlink, + ospf_area_vlink_authtype_authkey_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) " + "(authentication-key|) AUTH_KEY", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_SIMPLE + VLINK_HELPSTR_AUTH_SIMPLE); + +ALIAS (no_ospf_area_vlink, + no_ospf_area_vlink_authtype_authkey_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) " + "(authentication-key|)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_SIMPLE + VLINK_HELPSTR_AUTH_SIMPLE); + +ALIAS (ospf_area_vlink, + ospf_area_vlink_authtype_args_md5_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) (message-digest|null) " + "(message-digest-key|) <1-255> md5 KEY", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_ALL + VLINK_HELPSTR_AUTH_MD5); + +ALIAS (ospf_area_vlink, + ospf_area_vlink_authtype_md5_cmd, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) " + "(message-digest-key|) <1-255> md5 KEY", + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_SIMPLE + VLINK_HELPSTR_AUTH_MD5); + +ALIAS (no_ospf_area_vlink, + no_ospf_area_vlink_authtype_md5_cmd, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) " + "(message-digest-key|)", + NO_STR + VLINK_HELPSTR_IPADDR + VLINK_HELPSTR_AUTHTYPE_SIMPLE + VLINK_HELPSTR_AUTH_MD5); + + +DEFUN (ospf_area_shortcut, + ospf_area_shortcut_cmd, + "area (A.B.C.D|<0-4294967295>) shortcut (default|enable|disable)", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure the area's shortcutting mode\n" + "Set default shortcutting behavior\n" + "Enable shortcutting through the area\n" + "Disable shortcutting through the area\n") +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct in_addr area_id; + int mode; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("shortcut", area_id, format, argv[0]); + + area = ospf_area_get (ospf, area_id, format); + + if (strncmp (argv[1], "de", 2) == 0) + mode = OSPF_SHORTCUT_DEFAULT; + else if (strncmp (argv[1], "di", 2) == 0) + mode = OSPF_SHORTCUT_DISABLE; + else if (strncmp (argv[1], "e", 1) == 0) + mode = OSPF_SHORTCUT_ENABLE; + else + return CMD_WARNING; + + ospf_area_shortcut_set (ospf, area, mode); + + if (ospf->abr_type != OSPF_ABR_SHORTCUT) + vty_out (vty, "Shortcut area setting will take effect " + "only when the router is configured as Shortcut ABR%s", + VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_area_shortcut, + no_ospf_area_shortcut_cmd, + "no area (A.B.C.D|<0-4294967295>) shortcut (enable|disable)", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Deconfigure the area's shortcutting mode\n" + "Deconfigure enabled shortcutting through the area\n" + "Deconfigure disabled shortcutting through the area\n") +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("shortcut", area_id, format, argv[0]); + + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (!area) + return CMD_SUCCESS; + + ospf_area_shortcut_unset (ospf, area); + + return CMD_SUCCESS; +} + + +DEFUN (ospf_area_stub, + ospf_area_stub_cmd, + "area (A.B.C.D|<0-4294967295>) stub", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as stub\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int ret, format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]); + + ret = ospf_area_stub_set (ospf, area_id); + if (ret == 0) + { + vty_out (vty, "First deconfigure all virtual link through this area%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ospf_area_no_summary_unset (ospf, area_id); + + return CMD_SUCCESS; +} + +DEFUN (ospf_area_stub_no_summary, + ospf_area_stub_no_summary_cmd, + "area (A.B.C.D|<0-4294967295>) stub no-summary", + "OSPF stub parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as stub\n" + "Do not inject inter-area routes into stub\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int ret, format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]); + + ret = ospf_area_stub_set (ospf, area_id); + if (ret == 0) + { + vty_out (vty, "%% Area cannot be nssa as it contains a virtual link%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ospf_area_no_summary_set (ospf, area_id); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_area_stub, + no_ospf_area_stub_cmd, + "no area (A.B.C.D|<0-4294967295>) stub", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as stub\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]); + + ospf_area_stub_unset (ospf, area_id); + ospf_area_no_summary_unset (ospf, area_id); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_area_stub_no_summary, + no_ospf_area_stub_no_summary_cmd, + "no area (A.B.C.D|<0-4294967295>) stub no-summary", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as stub\n" + "Do not inject inter-area routes into area\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]); + ospf_area_no_summary_unset (ospf, area_id); + + return CMD_SUCCESS; +} + +#ifdef HAVE_NSSA +DEFUN (ospf_area_nssa, + ospf_area_nssa_cmd, + "area (A.B.C.D|<0-4294967295>) nssa", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int ret, format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]); + + ret = ospf_area_nssa_set (ospf, area_id); + if (ret == 0) + { + vty_out (vty, "%% Area cannot be nssa as it contains a virtual link%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc > 1) + { + if (strncmp (argv[1], "translate-c", 11) == 0) + ospf_area_nssa_translator_role_set (ospf, area_id, + OSPF_NSSA_ROLE_CANDIDATE); + else if (strncmp (argv[1], "translate-n", 11) == 0) + ospf_area_nssa_translator_role_set (ospf, area_id, + OSPF_NSSA_ROLE_NEVER); + else if (strncmp (argv[1], "translate-a", 11) == 0) + ospf_area_nssa_translator_role_set (ospf, area_id, + OSPF_NSSA_ROLE_ALWAYS); + } + + if (argc > 2) + ospf_area_no_summary_set (ospf, area_id); + + return CMD_SUCCESS; +} + +ALIAS (ospf_area_nssa, + ospf_area_nssa_translate_no_summary_cmd, + "area (A.B.C.D|<0-4294967295>) nssa (translate-candidate|translate-never|translate-always) (no-summary|)", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n" + "Configure NSSA-ABR for translate election (default)\n" + "Configure NSSA-ABR to never translate\n" + "Configure NSSA-ABR to always translate\n" + "Do not inject inter-area routes into nssa\n" + "dummy\n"); + +ALIAS (ospf_area_nssa, + ospf_area_nssa_translate_cmd, + "area (A.B.C.D|<0-4294967295>) nssa (translate-candidate|translate-never|translate-always)", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n" + "Configure NSSA-ABR for translate election (default)\n" + "Configure NSSA-ABR to never translate\n" + "Configure NSSA-ABR to always translate\n"); + +DEFUN (ospf_area_nssa_no_summary, + ospf_area_nssa_no_summary_cmd, + "area (A.B.C.D|<0-4294967295>) nssa no-summary", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n" + "Do not inject inter-area routes into nssa\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int ret, format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]); + + ret = ospf_area_nssa_set (ospf, area_id); + if (ret == 0) + { + vty_out (vty, "%% Area cannot be nssa as it contains a virtual link%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ospf_area_no_summary_set (ospf, area_id); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_area_nssa, + no_ospf_area_nssa_cmd, + "no area (A.B.C.D|<0-4294967295>) nssa", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]); + + ospf_area_nssa_unset (ospf, area_id); + ospf_area_no_summary_unset (ospf, area_id); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_area_nssa_no_summary, + no_ospf_area_nssa_no_summary_cmd, + "no area (A.B.C.D|<0-4294967295>) nssa no-summary", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n" + "Do not inject inter-area routes into nssa\n") +{ + struct ospf *ospf = vty->index; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]); + ospf_area_no_summary_unset (ospf, area_id); + + return CMD_SUCCESS; +} + +#endif /* HAVE_NSSA */ + +DEFUN (ospf_area_default_cost, + ospf_area_default_cost_cmd, + "area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Set the summary-default cost of a NSSA or stub area\n" + "Stub's advertised default summary cost\n") +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct in_addr area_id; + u_int32_t cost; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("default-cost", area_id, format, argv[0]); + VTY_GET_INTEGER_RANGE ("stub default cost", cost, argv[1], 0, 16777215); + + area = ospf_area_get (ospf, area_id, format); + + if (area->external_routing == OSPF_AREA_DEFAULT) + { + vty_out (vty, "The area is neither stub, nor NSSA%s", VTY_NEWLINE); + return CMD_WARNING; + } + + area->default_cost = cost; + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_area_default_cost, + no_ospf_area_default_cost_cmd, + "no area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Set the summary-default cost of a NSSA or stub area\n" + "Stub's advertised default summary cost\n") +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct in_addr area_id; + u_int32_t cost; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("default-cost", area_id, format, argv[0]); + VTY_GET_INTEGER_RANGE ("stub default cost", cost, argv[1], 0, 16777215); + + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (area == NULL) + return CMD_SUCCESS; + + if (area->external_routing == OSPF_AREA_DEFAULT) + { + vty_out (vty, "The area is neither stub, nor NSSA%s", VTY_NEWLINE); + return CMD_WARNING; + } + + area->default_cost = 1; + + ospf_area_check_free (ospf, area_id); + + return CMD_SUCCESS; +} + +DEFUN (ospf_area_export_list, + ospf_area_export_list_cmd, + "area (A.B.C.D|<0-4294967295>) export-list NAME", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Set the filter for networks announced to other areas\n" + "Name of the access-list\n") +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("export-list", area_id, format, argv[0]); + + area = ospf_area_get (ospf, area_id, format); + ospf_area_export_list_set (ospf, area, argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_area_export_list, + no_ospf_area_export_list_cmd, + "no area (A.B.C.D|<0-4294967295>) export-list NAME", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Unset the filter for networks announced to other areas\n" + "Name of the access-list\n") +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("export-list", area_id, format, argv[0]); + + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (area == NULL) + return CMD_SUCCESS; + + ospf_area_export_list_unset (ospf, area); + + return CMD_SUCCESS; +} + + +DEFUN (ospf_area_import_list, + ospf_area_import_list_cmd, + "area (A.B.C.D|<0-4294967295>) import-list NAME", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Set the filter for networks from other areas announced to the specified one\n" + "Name of the access-list\n") +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("import-list", area_id, format, argv[0]); + + area = ospf_area_get (ospf, area_id, format); + ospf_area_import_list_set (ospf, area, argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_area_import_list, + no_ospf_area_import_list_cmd, + "no area (A.B.C.D|<0-4294967295>) import-list NAME", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Unset the filter for networks announced to other areas\n" + "Name of the access-list\n") +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID_NO_BB ("import-list", area_id, format, argv[0]); + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (area == NULL) + return CMD_SUCCESS; + + ospf_area_import_list_unset (ospf, area); + + return CMD_SUCCESS; +} + +DEFUN (ospf_area_filter_list, + ospf_area_filter_list_cmd, + "area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Filter networks between OSPF areas\n" + "Filter prefixes between OSPF areas\n" + "Name of an IP prefix-list\n" + "Filter networks sent to this area\n" + "Filter networks sent from this area\n") +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct in_addr area_id; + struct prefix_list *plist; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + + area = ospf_area_get (ospf, area_id, format); + plist = prefix_list_lookup (AFI_IP, argv[1]); + if (strncmp (argv[2], "in", 2) == 0) + { + PREFIX_LIST_IN (area) = plist; + if (PREFIX_NAME_IN (area)) + free (PREFIX_NAME_IN (area)); + + PREFIX_NAME_IN (area) = strdup (argv[1]); + ospf_schedule_abr_task (ospf); + } + else + { + PREFIX_LIST_OUT (area) = plist; + if (PREFIX_NAME_OUT (area)) + free (PREFIX_NAME_OUT (area)); + + PREFIX_NAME_OUT (area) = strdup (argv[1]); + ospf_schedule_abr_task (ospf); + } + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_area_filter_list, + no_ospf_area_filter_list_cmd, + "no area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Filter networks between OSPF areas\n" + "Filter prefixes between OSPF areas\n" + "Name of an IP prefix-list\n" + "Filter networks sent to this area\n" + "Filter networks sent from this area\n") +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct in_addr area_id; + struct prefix_list *plist; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + + area = ospf_area_lookup_by_area_id (ospf, area_id); + plist = prefix_list_lookup (AFI_IP, argv[1]); + if (strncmp (argv[2], "in", 2) == 0) + { + if (PREFIX_NAME_IN (area)) + if (strcmp (PREFIX_NAME_IN (area), argv[1]) != 0) + return CMD_SUCCESS; + + PREFIX_LIST_IN (area) = NULL; + if (PREFIX_NAME_IN (area)) + free (PREFIX_NAME_IN (area)); + + PREFIX_NAME_IN (area) = NULL; + + ospf_schedule_abr_task (ospf); + } + else + { + if (PREFIX_NAME_OUT (area)) + if (strcmp (PREFIX_NAME_OUT (area), argv[1]) != 0) + return CMD_SUCCESS; + + PREFIX_LIST_OUT (area) = NULL; + if (PREFIX_NAME_OUT (area)) + free (PREFIX_NAME_OUT (area)); + + PREFIX_NAME_OUT (area) = NULL; + + ospf_schedule_abr_task (ospf); + } + + return CMD_SUCCESS; +} + + +DEFUN (ospf_area_authentication_message_digest, + ospf_area_authentication_message_digest_cmd, + "area (A.B.C.D|<0-4294967295>) authentication message-digest", + "OSPF area parameters\n" + "Enable authentication\n" + "Use message-digest authentication\n") +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + + area = ospf_area_get (ospf, area_id, format); + area->auth_type = OSPF_AUTH_CRYPTOGRAPHIC; + + return CMD_SUCCESS; +} + +DEFUN (ospf_area_authentication, + ospf_area_authentication_cmd, + "area (A.B.C.D|<0-4294967295>) authentication", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Enable authentication\n") +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + + area = ospf_area_get (ospf, area_id, format); + area->auth_type = OSPF_AUTH_SIMPLE; + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_area_authentication, + no_ospf_area_authentication_cmd, + "no area (A.B.C.D|<0-4294967295>) authentication", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Enable authentication\n") +{ + struct ospf *ospf = vty->index; + struct ospf_area *area; + struct in_addr area_id; + int format; + + VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); + + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (area == NULL) + return CMD_SUCCESS; + + area->auth_type = OSPF_AUTH_NULL; + + ospf_area_check_free (ospf, area_id); + + return CMD_SUCCESS; +} + + +DEFUN (ospf_abr_type, + ospf_abr_type_cmd, + "ospf abr-type (cisco|ibm|shortcut|standard)", + "OSPF specific commands\n" + "Set OSPF ABR type\n" + "Alternative ABR, cisco implementation\n" + "Alternative ABR, IBM implementation\n" + "Shortcut ABR\n" + "Standard behavior (RFC2328)\n") +{ + struct ospf *ospf = vty->index; + u_char abr_type = OSPF_ABR_UNKNOWN; + + if (strncmp (argv[0], "c", 1) == 0) + abr_type = OSPF_ABR_CISCO; + else if (strncmp (argv[0], "i", 1) == 0) + abr_type = OSPF_ABR_IBM; + else if (strncmp (argv[0], "sh", 2) == 0) + abr_type = OSPF_ABR_SHORTCUT; + else if (strncmp (argv[0], "st", 2) == 0) + abr_type = OSPF_ABR_STAND; + else + return CMD_WARNING; + + /* If ABR type value is changed, schedule ABR task. */ + if (ospf->abr_type != abr_type) + { + ospf->abr_type = abr_type; + ospf_schedule_abr_task (ospf); + } + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_abr_type, + no_ospf_abr_type_cmd, + "no ospf abr-type (cisco|ibm|shortcut)", + NO_STR + "OSPF specific commands\n" + "Set OSPF ABR type\n" + "Alternative ABR, cisco implementation\n" + "Alternative ABR, IBM implementation\n" + "Shortcut ABR\n") +{ + struct ospf *ospf = vty->index; + u_char abr_type = OSPF_ABR_UNKNOWN; + + if (strncmp (argv[0], "c", 1) == 0) + abr_type = OSPF_ABR_CISCO; + else if (strncmp (argv[0], "i", 1) == 0) + abr_type = OSPF_ABR_IBM; + else if (strncmp (argv[0], "s", 1) == 0) + abr_type = OSPF_ABR_SHORTCUT; + else + return CMD_WARNING; + + /* If ABR type value is changed, schedule ABR task. */ + if (ospf->abr_type == abr_type) + { + ospf->abr_type = OSPF_ABR_STAND; + ospf_schedule_abr_task (ospf); + } + + return CMD_SUCCESS; +} + +DEFUN (ospf_compatible_rfc1583, + ospf_compatible_rfc1583_cmd, + "compatible rfc1583", + "OSPF compatibility list\n" + "compatible with RFC 1583\n") +{ + struct ospf *ospf = vty->index; + + if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) + { + SET_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE); + ospf_spf_calculate_schedule (ospf); + } + return CMD_SUCCESS; +} + +DEFUN (no_ospf_compatible_rfc1583, + no_ospf_compatible_rfc1583_cmd, + "no compatible rfc1583", + NO_STR + "OSPF compatibility list\n" + "compatible with RFC 1583\n") +{ + struct ospf *ospf = vty->index; + + if (CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) + { + UNSET_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE); + ospf_spf_calculate_schedule (ospf); + } + return CMD_SUCCESS; +} + +ALIAS (ospf_compatible_rfc1583, + ospf_rfc1583_flag_cmd, + "ospf rfc1583compatibility", + "OSPF specific commands\n" + "Enable the RFC1583Compatibility flag\n"); + +ALIAS (no_ospf_compatible_rfc1583, + no_ospf_rfc1583_flag_cmd, + "no ospf rfc1583compatibility", + NO_STR + "OSPF specific commands\n" + "Disable the RFC1583Compatibility flag\n"); + +DEFUN (ospf_timers_spf, + ospf_timers_spf_cmd, + "timers spf <0-4294967295> <0-4294967295>", + "Adjust routing timers\n" + "OSPF SPF timers\n" + "Delay between receiving a change to SPF calculation\n" + "Hold time between consecutive SPF calculations\n") +{ + struct ospf *ospf = vty->index; + u_int32_t delay, hold; + + VTY_GET_UINT32 ("SPF delay timer", delay, argv[0]); + VTY_GET_UINT32 ("SPF hold timer", hold, argv[1]); + + ospf_timers_spf_set (ospf, delay, hold); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_timers_spf, + no_ospf_timers_spf_cmd, + "no timers spf", + NO_STR + "Adjust routing timers\n" + "OSPF SPF timers\n") +{ + struct ospf *ospf = vty->index; + + ospf->spf_delay = OSPF_SPF_DELAY_DEFAULT; + ospf->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; + + return CMD_SUCCESS; +} + + +DEFUN (ospf_neighbor, + ospf_neighbor_cmd, + "neighbor A.B.C.D", + NEIGHBOR_STR + "Neighbor IP address\n") +{ + struct ospf *ospf = vty->index; + struct in_addr nbr_addr; + int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; + int interval = OSPF_POLL_INTERVAL_DEFAULT; + + VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]); + + if (argc > 1) + VTY_GET_INTEGER_RANGE ("neighbor priority", priority, argv[1], 0, 255); + + if (argc > 2) + VTY_GET_INTEGER_RANGE ("poll interval", interval, argv[2], 1, 65535); + + ospf_nbr_nbma_set (ospf, nbr_addr); + if (argc > 1) + ospf_nbr_nbma_priority_set (ospf, nbr_addr, priority); + if (argc > 2) + ospf_nbr_nbma_poll_interval_set (ospf, nbr_addr, priority); + + return CMD_SUCCESS; +} + +ALIAS (ospf_neighbor, + ospf_neighbor_priority_poll_interval_cmd, + "neighbor A.B.C.D priority <0-255> poll-interval <1-65535>", + NEIGHBOR_STR + "Neighbor IP address\n" + "Neighbor Priority\n" + "Priority\n" + "Dead Neighbor Polling interval\n" + "Seconds\n"); + +ALIAS (ospf_neighbor, + ospf_neighbor_priority_cmd, + "neighbor A.B.C.D priority <0-255>", + NEIGHBOR_STR + "Neighbor IP address\n" + "Neighbor Priority\n" + "Seconds\n"); + +DEFUN (ospf_neighbor_poll_interval, + ospf_neighbor_poll_interval_cmd, + "neighbor A.B.C.D poll-interval <1-65535>", + NEIGHBOR_STR + "Neighbor IP address\n" + "Dead Neighbor Polling interval\n" + "Seconds\n") +{ + struct ospf *ospf = vty->index; + struct in_addr nbr_addr; + int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; + int interval = OSPF_POLL_INTERVAL_DEFAULT; + + VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]); + + if (argc > 1) + VTY_GET_INTEGER_RANGE ("poll interval", interval, argv[1], 1, 65535); + + if (argc > 2) + VTY_GET_INTEGER_RANGE ("neighbor priority", priority, argv[2], 0, 255); + + ospf_nbr_nbma_set (ospf, nbr_addr); + if (argc > 1) + ospf_nbr_nbma_poll_interval_set (ospf, nbr_addr, interval); + if (argc > 2) + ospf_nbr_nbma_priority_set (ospf, nbr_addr, priority); + + return CMD_SUCCESS; +} + +ALIAS (ospf_neighbor_poll_interval, + ospf_neighbor_poll_interval_priority_cmd, + "neighbor A.B.C.D poll-interval <1-65535> priority <0-255>", + NEIGHBOR_STR + "Neighbor address\n" + "OSPF dead-router polling interval\n" + "Seconds\n" + "OSPF priority of non-broadcast neighbor\n" + "Priority\n"); + +DEFUN (no_ospf_neighbor, + no_ospf_neighbor_cmd, + "no neighbor A.B.C.D", + NO_STR + NEIGHBOR_STR + "Neighbor IP address\n") +{ + struct ospf *ospf = vty->index; + struct in_addr nbr_addr; + int ret; + + VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]); + + ret = ospf_nbr_nbma_unset (ospf, nbr_addr); + + return CMD_SUCCESS; +} + +ALIAS (no_ospf_neighbor, + no_ospf_neighbor_priority_cmd, + "no neighbor A.B.C.D priority <0-255>", + NO_STR + NEIGHBOR_STR + "Neighbor IP address\n" + "Neighbor Priority\n" + "Priority\n"); + +ALIAS (no_ospf_neighbor, + no_ospf_neighbor_poll_interval_cmd, + "no neighbor A.B.C.D poll-interval <1-65535>", + NO_STR + NEIGHBOR_STR + "Neighbor IP address\n" + "Dead Neighbor Polling interval\n" + "Seconds\n"); + +ALIAS (no_ospf_neighbor, + no_ospf_neighbor_priority_pollinterval_cmd, + "no neighbor A.B.C.D priority <0-255> poll-interval <1-65535>", + NO_STR + NEIGHBOR_STR + "Neighbor IP address\n" + "Neighbor Priority\n" + "Priority\n" + "Dead Neighbor Polling interval\n" + "Seconds\n"); + + +DEFUN (ospf_refresh_timer, ospf_refresh_timer_cmd, + "refresh timer <10-1800>", + "Adjust refresh parameters\n" + "Set refresh timer\n" + "Timer value in seconds\n") +{ + struct ospf *ospf = vty->index; + int interval; + + VTY_GET_INTEGER_RANGE ("refresh timer", interval, argv[0], 10, 1800); + interval = (interval / 10) * 10; + + ospf_timers_refresh_set (ospf, interval); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_refresh_timer, no_ospf_refresh_timer_val_cmd, + "no refresh timer <10-1800>", + "Adjust refresh parameters\n" + "Unset refresh timer\n" + "Timer value in seconds\n") +{ + struct ospf *ospf = vty->index; + int interval; + + if (argc == 1) + { + VTY_GET_INTEGER_RANGE ("refresh timer", interval, argv[0], 10, 1800); + + if (ospf->lsa_refresh_interval != interval || + interval == OSPF_LSA_REFRESH_INTERVAL_DEFAULT) + return CMD_SUCCESS; + } + + ospf_timers_refresh_unset (ospf); + + return CMD_SUCCESS; +} + +ALIAS (no_ospf_refresh_timer, + no_ospf_refresh_timer_cmd, + "no refresh timer", + "Adjust refresh parameters\n" + "Unset refresh timer\n"); + +DEFUN (ospf_auto_cost_reference_bandwidth, + ospf_auto_cost_reference_bandwidth_cmd, + "auto-cost reference-bandwidth <1-4294967>", + "Calculate OSPF interface cost according to bandwidth\n" + "Use reference bandwidth method to assign OSPF cost\n" + "The reference bandwidth in terms of Mbits per second\n") +{ + struct ospf *ospf = vty->index; + u_int32_t refbw; + listnode node; + + refbw = strtol (argv[0], NULL, 10); + if (refbw < 1 || refbw > 4294967) + { + vty_out (vty, "reference-bandwidth value is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* If reference bandwidth is changed. */ + if ((refbw * 1000) == ospf->ref_bandwidth) + return CMD_SUCCESS; + + ospf->ref_bandwidth = refbw * 1000; + vty_out (vty, "%% OSPF: Reference bandwidth is changed.%s", VTY_NEWLINE); + vty_out (vty, " Please ensure reference bandwidth is consistent across all routers%s", VTY_NEWLINE); + + for (node = listhead (om->iflist); node; nextnode (node)) + ospf_if_recalculate_output_cost (getdata (node)); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_auto_cost_reference_bandwidth, + no_ospf_auto_cost_reference_bandwidth_cmd, + "no auto-cost reference-bandwidth", + NO_STR + "Calculate OSPF interface cost according to bandwidth\n" + "Use reference bandwidth method to assign OSPF cost\n") +{ + struct ospf *ospf = vty->index; + listnode node; + + if (ospf->ref_bandwidth == OSPF_DEFAULT_REF_BANDWIDTH) + return CMD_SUCCESS; + + ospf->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH; + vty_out (vty, "%% OSPF: Reference bandwidth is changed.%s", VTY_NEWLINE); + vty_out (vty, " Please ensure reference bandwidth is consistent across all routers%s", VTY_NEWLINE); + + for (node = listhead (om->iflist); node; nextnode (node)) + ospf_if_recalculate_output_cost (getdata (node)); + + return CMD_SUCCESS; +} + +char *ospf_abr_type_descr_str[] = + { + "Unknown", + "Standard (RFC2328)", + "Alternative IBM", + "Alternative Cisco", + "Alternative Shortcut" + }; + +char *ospf_shortcut_mode_descr_str[] = + { + "Default", + "Enabled", + "Disabled" + }; + + + +void +show_ip_ospf_area (struct vty *vty, struct ospf_area *area) +{ + /* Show Area ID. */ + vty_out (vty, " Area ID: %s", inet_ntoa (area->area_id)); + + /* Show Area type/mode. */ + if (OSPF_IS_AREA_BACKBONE (area)) + vty_out (vty, " (Backbone)%s", VTY_NEWLINE); + else + { + if (area->external_routing == OSPF_AREA_STUB) + vty_out (vty, " (Stub%s%s)", + area->no_summary ? ", no summary" : "", + area->shortcut_configured ? "; " : ""); + +#ifdef HAVE_NSSA + + else + if (area->external_routing == OSPF_AREA_NSSA) + vty_out (vty, " (NSSA%s%s)", + area->no_summary ? ", no summary" : "", + area->shortcut_configured ? "; " : ""); +#endif /* HAVE_NSSA */ + + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, " Shortcutting mode: %s", + ospf_shortcut_mode_descr_str[area->shortcut_configured]); + vty_out (vty, ", S-bit consensus: %s%s", + area->shortcut_capability ? "ok" : "no", VTY_NEWLINE); + } + + /* Show number of interfaces. */ + vty_out (vty, " Number of interfaces in this area: Total: %d, " + "Active: %d%s", listcount (area->oiflist), + area->act_ints, VTY_NEWLINE); + +#ifdef HAVE_NSSA + if (area->external_routing == OSPF_AREA_NSSA) + { + vty_out (vty, " It is an NSSA configuration. %s Elected NSSA/ABR performs type-7/type-5 LSA translation. %s", VTY_NEWLINE, VTY_NEWLINE); + if (! IS_OSPF_ABR (area->ospf)) + vty_out (vty, " It is not ABR, therefore not Translator. %s", + VTY_NEWLINE); + else + { + if (area->NSSATranslator) + vty_out (vty, " We are an ABR and the NSSA Elected Translator. %s", VTY_NEWLINE); + else + vty_out (vty, " We are an ABR, but not the NSSA Elected Translator. %s", VTY_NEWLINE); + } + } +#endif /* HAVE_NSSA */ + + /* Show number of fully adjacent neighbors. */ + vty_out (vty, " Number of fully adjacent neighbors in this area:" + " %d%s", area->full_nbrs, VTY_NEWLINE); + + /* Show authentication type. */ + vty_out (vty, " Area has "); + if (area->auth_type == OSPF_AUTH_NULL) + vty_out (vty, "no authentication%s", VTY_NEWLINE); + else if (area->auth_type == OSPF_AUTH_SIMPLE) + vty_out (vty, "simple password authentication%s", VTY_NEWLINE); + else if (area->auth_type == OSPF_AUTH_CRYPTOGRAPHIC) + vty_out (vty, "message digest authentication%s", VTY_NEWLINE); + + if (!OSPF_IS_AREA_BACKBONE (area)) + vty_out (vty, " Number of full virtual adjacencies going through" + " this area: %d%s", area->full_vls, VTY_NEWLINE); + + /* Show SPF calculation times. */ + vty_out (vty, " SPF algorithm executed %d times%s", + area->spf_calculation, VTY_NEWLINE); + + /* Show number of LSA. */ + vty_out (vty, " Number of LSA %ld%s", area->lsdb->total, VTY_NEWLINE); + + vty_out (vty, "%s", VTY_NEWLINE); +} + +DEFUN (show_ip_ospf, + show_ip_ospf_cmd, + "show ip ospf", + SHOW_STR + IP_STR + "OSPF information\n") +{ + listnode node; + struct ospf_area * area; + struct ospf *ospf; + + /* Check OSPF is enable. */ + ospf = ospf_lookup (); + if (ospf == NULL) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* Show Router ID. */ + vty_out (vty, " OSPF Routing Process, Router ID: %s%s", + inet_ntoa (ospf->router_id), + VTY_NEWLINE); + + /* Show capability. */ + vty_out (vty, " Supports only single TOS (TOS0) routes%s", VTY_NEWLINE); + vty_out (vty, " This implementation conforms to RFC2328%s", VTY_NEWLINE); + vty_out (vty, " RFC1583Compatibility flag is %s%s", + CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE) ? + "enabled" : "disabled", VTY_NEWLINE); +#ifdef HAVE_OPAQUE_LSA + vty_out (vty, " OpaqueCapability flag is %s%s%s", + CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE) ? + "enabled" : "disabled", + IS_OPAQUE_LSA_ORIGINATION_BLOCKED (ospf->opaque) ? + " (origination blocked)" : "", + VTY_NEWLINE); +#endif /* HAVE_OPAQUE_LSA */ + + /* Show SPF timers. */ + vty_out (vty, " SPF schedule delay %d secs, Hold time between two SPFs %d secs%s", + ospf->spf_delay, ospf->spf_holdtime, VTY_NEWLINE); + + /* Show refresh parameters. */ + vty_out (vty, " Refresh timer %d secs%s", + ospf->lsa_refresh_interval, VTY_NEWLINE); + + /* Show ABR/ASBR flags. */ + if (CHECK_FLAG (ospf->flags, OSPF_FLAG_ABR)) + vty_out (vty, " This router is an ABR, ABR type is: %s%s", + ospf_abr_type_descr_str[ospf->abr_type], VTY_NEWLINE); + + if (CHECK_FLAG (ospf->flags, OSPF_FLAG_ASBR)) + vty_out (vty, " This router is an ASBR " + "(injecting external routing information)%s", VTY_NEWLINE); + + /* Show Number of AS-external-LSAs. */ + vty_out (vty, " Number of external LSA %ld%s", + ospf_lsdb_count_all (ospf->lsdb), VTY_NEWLINE); + + /* Show number of areas attached. */ + vty_out (vty, " Number of areas attached to this router: %d%s%s", + listcount (ospf->areas), VTY_NEWLINE, VTY_NEWLINE); + + /* Show each area status. */ + for (node = listhead (ospf->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + show_ip_ospf_area (vty, area); + + return CMD_SUCCESS; +} + + +void +show_ip_ospf_interface_sub (struct vty *vty, struct ospf *ospf, + struct interface *ifp) +{ + struct ospf_neighbor *nbr; + int oi_count; + struct route_node *rn; + char buf[9]; + + oi_count = ospf_oi_count (ifp); + + /* Is interface up? */ + if (if_is_up (ifp)) + vty_out (vty, "%s is up, line protocol is up%s", ifp->name, VTY_NEWLINE); + else + { + vty_out (vty, "%s is down, line protocol is down%s", ifp->name, + VTY_NEWLINE); + + + if (oi_count == 0) + vty_out (vty, " OSPF not enabled on this interface%s", VTY_NEWLINE); + else + vty_out (vty, " OSPF is enabled, but not running on this interface%s", + VTY_NEWLINE); + return; + } + + /* Is interface OSPF enabled? */ + if (oi_count == 0) + { + vty_out (vty, " OSPF not enabled on this interface%s", VTY_NEWLINE); + return; + } + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct ospf_interface *oi = rn->info; + + if (oi == NULL) + continue; + + /* Show OSPF interface information. */ + vty_out (vty, " Internet Address %s/%d,", + inet_ntoa (oi->address->u.prefix4), oi->address->prefixlen); + + vty_out (vty, " Area %s%s", ospf_area_desc_string (oi->area), + VTY_NEWLINE); + + vty_out (vty, " Router ID %s, Network Type %s, Cost: %d%s", + inet_ntoa (ospf->router_id), ospf_network_type_str[oi->type], + oi->output_cost, VTY_NEWLINE); + + vty_out (vty, " Transmit Delay is %d sec, State %s, Priority %d%s", + OSPF_IF_PARAM (oi,transmit_delay), LOOKUP (ospf_ism_state_msg, oi->state), + PRIORITY (oi), VTY_NEWLINE); + + /* Show DR information. */ + if (DR (oi).s_addr == 0) + vty_out (vty, " No designated router on this network%s", VTY_NEWLINE); + else + { + nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi)); + if (nbr == NULL) + vty_out (vty, " No designated router on this network%s", VTY_NEWLINE); + else + { + vty_out (vty, " Designated Router (ID) %s,", + inet_ntoa (nbr->router_id)); + vty_out (vty, " Interface Address %s%s", + inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE); + } + } + + /* Show BDR information. */ + if (BDR (oi).s_addr == 0) + vty_out (vty, " No backup designated router on this network%s", + VTY_NEWLINE); + else + { + nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &BDR (oi)); + if (nbr == NULL) + vty_out (vty, " No backup designated router on this network%s", + VTY_NEWLINE); + else + { + vty_out (vty, " Backup Designated Router (ID) %s,", + inet_ntoa (nbr->router_id)); + vty_out (vty, " Interface Address %s%s", + inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE); + } + } + vty_out (vty, " Timer intervals configured,"); + vty_out (vty, " Hello %d, Dead %d, Wait %d, Retransmit %d%s", + OSPF_IF_PARAM (oi, v_hello), OSPF_IF_PARAM (oi, v_wait), + OSPF_IF_PARAM (oi, v_wait), + OSPF_IF_PARAM (oi, retransmit_interval), + VTY_NEWLINE); + + if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_ACTIVE) + vty_out (vty, " Hello due in %s%s", + ospf_timer_dump (oi->t_hello, buf, 9), VTY_NEWLINE); + else /* OSPF_IF_PASSIVE is set */ + vty_out (vty, " No Hellos (Passive interface)%s", VTY_NEWLINE); + + vty_out (vty, " Neighbor Count is %d, Adjacent neighbor count is %d%s", + ospf_nbr_count (oi, 0), ospf_nbr_count (oi, NSM_Full), + VTY_NEWLINE); + } +} + +DEFUN (show_ip_ospf_interface, + show_ip_ospf_interface_cmd, + "show ip ospf interface [INTERFACE]", + SHOW_STR + IP_STR + "OSPF information\n" + "Interface information\n" + "Interface name\n") +{ + struct interface *ifp; + struct ospf *ospf; + listnode node; + + ospf = ospf_lookup (); + + /* Show All Interfaces. */ + if (argc == 0) + for (node = listhead (iflist); node; nextnode (node)) + show_ip_ospf_interface_sub (vty, ospf, node->data); + /* Interface name is specified. */ + else + { + if ((ifp = if_lookup_by_name (argv[0])) == NULL) + vty_out (vty, "No such interface name%s", VTY_NEWLINE); + else + show_ip_ospf_interface_sub (vty, ospf, ifp); + } + + return CMD_SUCCESS; +} + +void +show_ip_ospf_neighbor_sub (struct vty *vty, struct ospf_interface *oi) +{ + struct route_node *rn; + struct ospf_neighbor *nbr; + char msgbuf[16]; + char timebuf[9]; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + /* Do not show myself. */ + if (nbr != oi->nbr_self) + /* Down state is not shown. */ + if (nbr->state != NSM_Down) + { + ospf_nbr_state_message (nbr, msgbuf, 16); + + if (nbr->state == NSM_Attempt && nbr->router_id.s_addr == 0) + vty_out (vty, "%-15s %3d %-15s %8s ", + "-", nbr->priority, + msgbuf, ospf_timer_dump (nbr->t_inactivity, timebuf, 9)); + else + vty_out (vty, "%-15s %3d %-15s %8s ", + inet_ntoa (nbr->router_id), nbr->priority, + msgbuf, ospf_timer_dump (nbr->t_inactivity, timebuf, 9)); + vty_out (vty, "%-15s ", inet_ntoa (nbr->src)); + vty_out (vty, "%-15s %5ld %5ld %5d%s", + IF_NAME (oi), ospf_ls_retransmit_count (nbr), + ospf_ls_request_count (nbr), ospf_db_summary_count (nbr), + VTY_NEWLINE); + } +} + +DEFUN (show_ip_ospf_neighbor, + show_ip_ospf_neighbor_cmd, + "show ip ospf neighbor", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n") +{ + struct ospf *ospf; + listnode node; + + ospf = ospf_lookup (); + if (ospf == NULL) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* Show All neighbors. */ + vty_out (vty, "%sNeighbor ID Pri State Dead " + "Time Address Interface RXmtL " + "RqstL DBsmL%s", VTY_NEWLINE, VTY_NEWLINE); + + for (node = listhead (ospf->oiflist); node; nextnode (node)) + show_ip_ospf_neighbor_sub (vty, getdata (node)); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_ospf_neighbor_all, + show_ip_ospf_neighbor_all_cmd, + "show ip ospf neighbor all", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n" + "include down status neighbor\n") +{ + struct ospf *ospf = vty->index; + listnode node; + + if (ospf == NULL) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* Show All neighbors. */ + vty_out (vty, "%sNeighbor ID Pri State Dead " + "Time Address Interface RXmtL " + "RqstL DBsmL%s", VTY_NEWLINE, VTY_NEWLINE); + + for (node = listhead (ospf->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + listnode nbr_node; + + show_ip_ospf_neighbor_sub (vty, oi); + + /* print Down neighbor status */ + for (nbr_node = listhead (oi->nbr_nbma); nbr_node; nextnode (nbr_node)) + { + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = getdata (nbr_node); + + if (nbr_nbma->nbr == NULL + || nbr_nbma->nbr->state == NSM_Down) + { + vty_out (vty, "%-15s %3d %-15s %8s ", + "-", nbr_nbma->priority, "Down", "-"); + vty_out (vty, "%-15s %-15s %5d %5d %5d%s", + inet_ntoa (nbr_nbma->addr), IF_NAME (oi), + 0, 0, 0, VTY_NEWLINE); + } + } + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_ospf_neighbor_int, + show_ip_ospf_neighbor_int_cmd, + "show ip ospf neighbor A.B.C.D", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n" + "Interface name\n") +{ + struct ospf *ospf; + struct ospf_interface *oi; + struct in_addr addr; + int ret; + + ret = inet_aton (argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ospf = ospf_lookup (); + if (ospf == NULL) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + if ((oi = ospf_if_is_configured (ospf, &addr)) == NULL) + vty_out (vty, "No such interface address%s", VTY_NEWLINE); + else + { + vty_out (vty, "%sNeighbor ID Pri State Dead " + "Time Address Interface RXmtL " + "RqstL DBsmL%s", VTY_NEWLINE, VTY_NEWLINE); + show_ip_ospf_neighbor_sub (vty, oi); + } + + return CMD_SUCCESS; +} + +void +show_ip_ospf_nbr_nbma_detail_sub (struct vty *vty, struct ospf_interface *oi, + struct ospf_nbr_nbma *nbr_nbma) +{ + char timebuf[9]; + + /* Show neighbor ID. */ + vty_out (vty, " Neighbor %s,", "-"); + + /* Show interface address. */ + vty_out (vty, " interface address %s%s", + inet_ntoa (nbr_nbma->addr), VTY_NEWLINE); + /* Show Area ID. */ + vty_out (vty, " In the area %s via interface %s%s", + ospf_area_desc_string (oi->area), IF_NAME (oi), VTY_NEWLINE); + /* Show neighbor priority and state. */ + vty_out (vty, " Neighbor priority is %d, State is %s,", + nbr_nbma->priority, "Down"); + /* Show state changes. */ + vty_out (vty, " %d state changes%s", nbr_nbma->state_change, VTY_NEWLINE); + + /* Show PollInterval */ + vty_out (vty, " Poll interval %d%s", nbr_nbma->v_poll, VTY_NEWLINE); + + /* Show poll-interval timer. */ + vty_out (vty, " Poll timer due in %s%s", + ospf_timer_dump (nbr_nbma->t_poll, timebuf, 9), VTY_NEWLINE); + + /* Show poll-interval timer thread. */ + vty_out (vty, " Thread Poll Timer %s%s", + nbr_nbma->t_poll != NULL ? "on" : "off", VTY_NEWLINE); +} + +void +show_ip_ospf_neighbor_detail_sub (struct vty *vty, struct ospf_interface *oi, + struct ospf_neighbor *nbr) +{ + char timebuf[9]; + + /* Show neighbor ID. */ + if (nbr->state == NSM_Attempt && nbr->router_id.s_addr == 0) + vty_out (vty, " Neighbor %s,", "-"); + else + vty_out (vty, " Neighbor %s,", inet_ntoa (nbr->router_id)); + + /* Show interface address. */ + vty_out (vty, " interface address %s%s", + inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE); + /* Show Area ID. */ + vty_out (vty, " In the area %s via interface %s%s", + ospf_area_desc_string (oi->area), oi->ifp->name, VTY_NEWLINE); + /* Show neighbor priority and state. */ + vty_out (vty, " Neighbor priority is %d, State is %s,", + nbr->priority, LOOKUP (ospf_nsm_state_msg, nbr->state)); + /* Show state changes. */ + vty_out (vty, " %d state changes%s", nbr->state_change, VTY_NEWLINE); + + /* Show Designated Rotuer ID. */ + vty_out (vty, " DR is %s,", inet_ntoa (nbr->d_router)); + /* Show Backup Designated Rotuer ID. */ + vty_out (vty, " BDR is %s%s", inet_ntoa (nbr->bd_router), VTY_NEWLINE); + /* Show options. */ + vty_out (vty, " Options %d %s%s", nbr->options, + ospf_options_dump (nbr->options), VTY_NEWLINE); + /* Show Router Dead interval timer. */ + vty_out (vty, " Dead timer due in %s%s", + ospf_timer_dump (nbr->t_inactivity, timebuf, 9), VTY_NEWLINE); + /* Show Database Summary list. */ + vty_out (vty, " Database Summary List %d%s", + ospf_db_summary_count (nbr), VTY_NEWLINE); + /* Show Link State Request list. */ + vty_out (vty, " Link State Request List %ld%s", + ospf_ls_request_count (nbr), VTY_NEWLINE); + /* Show Link State Retransmission list. */ + vty_out (vty, " Link State Retransmission List %ld%s", + ospf_ls_retransmit_count (nbr), VTY_NEWLINE); + /* Show inactivity timer thread. */ + vty_out (vty, " Thread Inactivity Timer %s%s", + nbr->t_inactivity != NULL ? "on" : "off", VTY_NEWLINE); + /* Show Database Description retransmission thread. */ + vty_out (vty, " Thread Database Description Retransmision %s%s", + nbr->t_db_desc != NULL ? "on" : "off", VTY_NEWLINE); + /* Show Link State Request Retransmission thread. */ + vty_out (vty, " Thread Link State Request Retransmission %s%s", + nbr->t_ls_req != NULL ? "on" : "off", VTY_NEWLINE); + /* Show Link State Update Retransmission thread. */ + vty_out (vty, " Thread Link State Update Retransmission %s%s%s", + nbr->t_ls_upd != NULL ? "on" : "off", VTY_NEWLINE, VTY_NEWLINE); +} + +DEFUN (show_ip_ospf_neighbor_id, + show_ip_ospf_neighbor_id_cmd, + "show ip ospf neighbor A.B.C.D", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n" + "Neighbor ID\n") +{ + struct ospf *ospf; + listnode node; + struct ospf_neighbor *nbr; + struct in_addr router_id; + int ret; + + ret = inet_aton (argv[0], &router_id); + if (!ret) + { + vty_out (vty, "Please specify Neighbor ID by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ospf = ospf_lookup (); + if (ospf == NULL) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + for (node = listhead (ospf->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + + if ((nbr = ospf_nbr_lookup_by_routerid (oi->nbrs, &router_id))) + { + show_ip_ospf_neighbor_detail_sub (vty, oi, nbr); + return CMD_SUCCESS; + } + } + + /* Nothing to show. */ + return CMD_SUCCESS; +} + +DEFUN (show_ip_ospf_neighbor_detail, + show_ip_ospf_neighbor_detail_cmd, + "show ip ospf neighbor detail", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n" + "detail of all neighbors\n") +{ + struct ospf *ospf; + listnode node; + + ospf = ospf_lookup (); + if (ospf == NULL) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + for (node = listhead (ospf->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + struct route_node *rn; + struct ospf_neighbor *nbr; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + if (nbr != oi->nbr_self) + if (nbr->state != NSM_Down) + show_ip_ospf_neighbor_detail_sub (vty, oi, nbr); + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_ospf_neighbor_detail_all, + show_ip_ospf_neighbor_detail_all_cmd, + "show ip ospf neighbor detail all", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n" + "detail of all neighbors\n" + "include down status neighbor\n") +{ + struct ospf *ospf; + listnode node; + + ospf = ospf_lookup (); + if (ospf == NULL) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + for (node = listhead (ospf->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + struct route_node *rn; + struct ospf_neighbor *nbr; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + if (nbr != oi->nbr_self) + if (oi->type == OSPF_IFTYPE_NBMA && nbr->state != NSM_Down) + show_ip_ospf_neighbor_detail_sub (vty, oi, rn->info); + + if (oi->type == OSPF_IFTYPE_NBMA) + { + listnode nd; + + for (nd = listhead (oi->nbr_nbma); nd; nextnode (nd)) + { + struct ospf_nbr_nbma *nbr_nbma = getdata (nd); + if (nbr_nbma->nbr == NULL + || nbr_nbma->nbr->state == NSM_Down) + show_ip_ospf_nbr_nbma_detail_sub (vty, oi, nbr_nbma); + } + } + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_ospf_neighbor_int_detail, + show_ip_ospf_neighbor_int_detail_cmd, + "show ip ospf neighbor A.B.C.D detail", + SHOW_STR + IP_STR + "OSPF information\n" + "Neighbor list\n" + "Interface address\n" + "detail of all neighbors") +{ + struct ospf *ospf; + struct ospf_interface *oi; + struct in_addr addr; + int ret; + + ret = inet_aton (argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ospf = ospf_lookup (); + if (ospf == NULL) + { + vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + if ((oi = ospf_if_is_configured (ospf, &addr)) == NULL) + vty_out (vty, "No such interface address%s", VTY_NEWLINE); + else + { + struct route_node *rn; + struct ospf_neighbor *nbr; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + if (nbr != oi->nbr_self) + if (nbr->state != NSM_Down) + show_ip_ospf_neighbor_detail_sub (vty, oi, nbr); + } + + return CMD_SUCCESS; +} + + +/* Show functions */ +int +show_lsa_summary (struct vty *vty, struct ospf_lsa *lsa, int self) +{ + struct router_lsa *rl; + struct summary_lsa *sl; + struct as_external_lsa *asel; + struct prefix_ipv4 p; + + if (lsa != NULL) + /* If self option is set, check LSA self flag. */ + if (self == 0 || IS_LSA_SELF (lsa)) + { + /* LSA common part show. */ + vty_out (vty, "%-15s ", inet_ntoa (lsa->data->id)); + vty_out (vty, "%-15s %4d 0x%08lx 0x%04x", + inet_ntoa (lsa->data->adv_router), LS_AGE (lsa), + (u_long)ntohl (lsa->data->ls_seqnum), ntohs (lsa->data->checksum)); + /* LSA specific part show. */ + switch (lsa->data->type) + { + case OSPF_ROUTER_LSA: + rl = (struct router_lsa *) lsa->data; + vty_out (vty, " %-d", ntohs (rl->links)); + break; + case OSPF_SUMMARY_LSA: + sl = (struct summary_lsa *) lsa->data; + + p.family = AF_INET; + p.prefix = sl->header.id; + p.prefixlen = ip_masklen (sl->mask); + apply_mask_ipv4 (&p); + + vty_out (vty, " %s/%d", inet_ntoa (p.prefix), p.prefixlen); + break; + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_NSSA + case OSPF_AS_NSSA_LSA: +#endif /* HAVE_NSSA */ + asel = (struct as_external_lsa *) lsa->data; + + p.family = AF_INET; + p.prefix = asel->header.id; + p.prefixlen = ip_masklen (asel->mask); + apply_mask_ipv4 (&p); + + vty_out (vty, " %s %s/%d [0x%lx]", + IS_EXTERNAL_METRIC (asel->e[0].tos) ? "E2" : "E1", + inet_ntoa (p.prefix), p.prefixlen, + (u_long)ntohl (asel->e[0].route_tag)); + break; + case OSPF_NETWORK_LSA: + case OSPF_ASBR_SUMMARY_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + default: + break; + } + vty_out (vty, VTY_NEWLINE); + } + + return 0; +} + +char *show_database_desc[] = + { + "unknown", + "Router Link States", + "Net Link States", + "Summary Link States", + "ASBR-Summary Link States", + "AS External Link States", +#if defined (HAVE_NSSA) || defined (HAVE_OPAQUE_LSA) + "Group Membership LSA", + "NSSA-external Link States", +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA + "Type-8 LSA", + "Link-Local Opaque-LSA", + "Area-Local Opaque-LSA", + "AS-external Opaque-LSA", +#endif /* HAVE_OPAQUE_LSA */ + }; + +#define SHOW_OSPF_COMMON_HEADER \ + "Link ID ADV Router Age Seq# CkSum" + +char *show_database_header[] = + { + "", + "Link ID ADV Router Age Seq# CkSum Link count", + "Link ID ADV Router Age Seq# CkSum", + "Link ID ADV Router Age Seq# CkSum Route", + "Link ID ADV Router Age Seq# CkSum", + "Link ID ADV Router Age Seq# CkSum Route", +#ifdef HAVE_NSSA + " --- header for Group Member ----", + "Link ID ADV Router Age Seq# CkSum Route", +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA +#ifndef HAVE_NSSA + " --- type-6 ---", + " --- type-7 ---", +#endif /* HAVE_NSSA */ + " --- type-8 ---", + "Opaque-Type/Id ADV Router Age Seq# CkSum", + "Opaque-Type/Id ADV Router Age Seq# CkSum", + "Opaque-Type/Id ADV Router Age Seq# CkSum", +#endif /* HAVE_OPAQUE_LSA */ + }; + +void +show_ip_ospf_database_header (struct vty *vty, struct ospf_lsa *lsa) +{ + struct router_lsa *rlsa = (struct router_lsa*) lsa->data; + + vty_out (vty, " LS age: %d%s", LS_AGE (lsa), VTY_NEWLINE); + vty_out (vty, " Options: %d%s", lsa->data->options, VTY_NEWLINE); + + if (lsa->data->type == OSPF_ROUTER_LSA) + { + vty_out (vty, " Flags: 0x%x" , rlsa->flags); + + if (rlsa->flags) + vty_out (vty, " :%s%s%s%s", + IS_ROUTER_LSA_BORDER (rlsa) ? " ABR" : "", + IS_ROUTER_LSA_EXTERNAL (rlsa) ? " ASBR" : "", + IS_ROUTER_LSA_VIRTUAL (rlsa) ? " VL-endpoint" : "", + IS_ROUTER_LSA_SHORTCUT (rlsa) ? " Shortcut" : ""); + + vty_out (vty, "%s", VTY_NEWLINE); + } + vty_out (vty, " LS Type: %s%s", + LOOKUP (ospf_lsa_type_msg, lsa->data->type), VTY_NEWLINE); + vty_out (vty, " Link State ID: %s %s%s", inet_ntoa (lsa->data->id), + LOOKUP (ospf_link_state_id_type_msg, lsa->data->type), VTY_NEWLINE); + vty_out (vty, " Advertising Router: %s%s", + inet_ntoa (lsa->data->adv_router), VTY_NEWLINE); + vty_out (vty, " LS Seq Number: %08lx%s", (u_long)ntohl (lsa->data->ls_seqnum), + VTY_NEWLINE); + vty_out (vty, " Checksum: 0x%04x%s", ntohs (lsa->data->checksum), + VTY_NEWLINE); + vty_out (vty, " Length: %d%s", ntohs (lsa->data->length), VTY_NEWLINE); +} + +char *link_type_desc[] = + { + "(null)", + "another Router (point-to-point)", + "a Transit Network", + "Stub Network", + "a Virtual Link", + }; + +char *link_id_desc[] = + { + "(null)", + "Neighboring Router ID", + "Designated Router address", + "Net", + "Neighboring Router ID", + }; + +char *link_data_desc[] = + { + "(null)", + "Router Interface address", + "Router Interface address", + "Network Mask", + "Router Interface address", + }; + +/* Show router-LSA each Link information. */ +void +show_ip_ospf_database_router_links (struct vty *vty, + struct router_lsa *rl) +{ + int len, i, type; + + len = ntohs (rl->header.length) - 4; + for (i = 0; i < ntohs (rl->links) && len > 0; len -= 12, i++) + { + type = rl->link[i].type; + + vty_out (vty, " Link connected to: %s%s", + link_type_desc[type], VTY_NEWLINE); + vty_out (vty, " (Link ID) %s: %s%s", link_id_desc[type], + inet_ntoa (rl->link[i].link_id), VTY_NEWLINE); + vty_out (vty, " (Link Data) %s: %s%s", link_data_desc[type], + inet_ntoa (rl->link[i].link_data), VTY_NEWLINE); + vty_out (vty, " Number of TOS metrics: 0%s", VTY_NEWLINE); + vty_out (vty, " TOS 0 Metric: %d%s", + ntohs (rl->link[i].metric), VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +/* Show router-LSA detail information. */ +int +show_router_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + if (lsa != NULL) + { + struct router_lsa *rl = (struct router_lsa *) lsa->data; + + show_ip_ospf_database_header (vty, lsa); + + vty_out (vty, " Number of Links: %d%s%s", ntohs (rl->links), + VTY_NEWLINE, VTY_NEWLINE); + + show_ip_ospf_database_router_links (vty, rl); + } + + return 0; +} + +/* Show network-LSA detail information. */ +int +show_network_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + int length, i; + + if (lsa != NULL) + { + struct network_lsa *nl = (struct network_lsa *) lsa->data; + + show_ip_ospf_database_header (vty, lsa); + + vty_out (vty, " Network Mask: /%d%s", + ip_masklen (nl->mask), VTY_NEWLINE); + + length = ntohs (lsa->data->length) - OSPF_LSA_HEADER_SIZE - 4; + + for (i = 0; length > 0; i++, length -= 4) + vty_out (vty, " Attached Router: %s%s", + inet_ntoa (nl->routers[i]), VTY_NEWLINE); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + return 0; +} + +/* Show summary-LSA detail information. */ +int +show_summary_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + if (lsa != NULL) + { + struct summary_lsa *sl = (struct summary_lsa *) lsa->data; + + show_ip_ospf_database_header (vty, lsa); + + vty_out (vty, " Network Mask: /%d%s", ip_masklen (sl->mask), + VTY_NEWLINE); + vty_out (vty, " TOS: 0 Metric: %d%s", GET_METRIC (sl->metric), + VTY_NEWLINE); + } + + return 0; +} + +/* Show summary-ASBR-LSA detail information. */ +int +show_summary_asbr_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + if (lsa != NULL) + { + struct summary_lsa *sl = (struct summary_lsa *) lsa->data; + + show_ip_ospf_database_header (vty, lsa); + + vty_out (vty, " Network Mask: /%d%s", + ip_masklen (sl->mask), VTY_NEWLINE); + vty_out (vty, " TOS: 0 Metric: %d%s", GET_METRIC (sl->metric), + VTY_NEWLINE); + } + + return 0; +} + +/* Show AS-external-LSA detail information. */ +int +show_as_external_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + if (lsa != NULL) + { + struct as_external_lsa *al = (struct as_external_lsa *) lsa->data; + + show_ip_ospf_database_header (vty, lsa); + + vty_out (vty, " Network Mask: /%d%s", + ip_masklen (al->mask), VTY_NEWLINE); + vty_out (vty, " Metric Type: %s%s", + IS_EXTERNAL_METRIC (al->e[0].tos) ? + "2 (Larger than any link state path)" : "1", VTY_NEWLINE); + vty_out (vty, " TOS: 0%s", VTY_NEWLINE); + vty_out (vty, " Metric: %d%s", + GET_METRIC (al->e[0].metric), VTY_NEWLINE); + vty_out (vty, " Forward Address: %s%s", + inet_ntoa (al->e[0].fwd_addr), VTY_NEWLINE); + + vty_out (vty, " External Route Tag: %lu%s%s", + (u_long)ntohl (al->e[0].route_tag), VTY_NEWLINE, VTY_NEWLINE); + } + + return 0; +} + +#ifdef HAVE_NSSA +int +show_as_external_lsa_stdvty (struct ospf_lsa *lsa) +{ + struct as_external_lsa *al = (struct as_external_lsa *) lsa->data; + + /* show_ip_ospf_database_header (vty, lsa); */ + + zlog_info( " Network Mask: /%d%s", + ip_masklen (al->mask), "\n"); + zlog_info( " Metric Type: %s%s", + IS_EXTERNAL_METRIC (al->e[0].tos) ? + "2 (Larger than any link state path)" : "1", "\n"); + zlog_info( " TOS: 0%s", "\n"); + zlog_info( " Metric: %d%s", + GET_METRIC (al->e[0].metric), "\n"); + zlog_info( " Forward Address: %s%s", + inet_ntoa (al->e[0].fwd_addr), "\n"); + + zlog_info( " External Route Tag: %u%s%s", + ntohl (al->e[0].route_tag), "\n", "\n"); + + return 0; +} + +/* Show AS-NSSA-LSA detail information. */ +int +show_as_nssa_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + if (lsa != NULL) + { + struct as_external_lsa *al = (struct as_external_lsa *) lsa->data; + + show_ip_ospf_database_header (vty, lsa); + + vty_out (vty, " Network Mask: /%d%s", + ip_masklen (al->mask), VTY_NEWLINE); + vty_out (vty, " Metric Type: %s%s", + IS_EXTERNAL_METRIC (al->e[0].tos) ? + "2 (Larger than any link state path)" : "1", VTY_NEWLINE); + vty_out (vty, " TOS: 0%s", VTY_NEWLINE); + vty_out (vty, " Metric: %d%s", + GET_METRIC (al->e[0].metric), VTY_NEWLINE); + vty_out (vty, " NSSA: Forward Address: %s%s", + inet_ntoa (al->e[0].fwd_addr), VTY_NEWLINE); + + vty_out (vty, " External Route Tag: %u%s%s", + ntohl (al->e[0].route_tag), VTY_NEWLINE, VTY_NEWLINE); + } + + return 0; +} + +#endif /* HAVE_NSSA */ + +int +show_func_dummy (struct vty *vty, struct ospf_lsa *lsa) +{ + return 0; +} + +#ifdef HAVE_OPAQUE_LSA +int +show_opaque_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) +{ + if (lsa != NULL) + { + show_ip_ospf_database_header (vty, lsa); + show_opaque_info_detail (vty, lsa); + + vty_out (vty, "%s", VTY_NEWLINE); + } + return 0; +} +#endif /* HAVE_OPAQUE_LSA */ + +int (*show_function[])(struct vty *, struct ospf_lsa *) = +{ + NULL, + show_router_lsa_detail, + show_network_lsa_detail, + show_summary_lsa_detail, + show_summary_asbr_lsa_detail, + show_as_external_lsa_detail, +#ifdef HAVE_NSSA + show_func_dummy, + show_as_nssa_lsa_detail, /* almost same as external */ +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA +#ifndef HAVE_NSSA + show_func_dummy, + show_func_dummy, +#endif /* HAVE_NSSA */ + NULL, /* type-8 */ + show_opaque_lsa_detail, + show_opaque_lsa_detail, + show_opaque_lsa_detail, +#endif /* HAVE_OPAQUE_LSA */ +}; + +void +show_lsa_prefix_set (struct vty *vty, struct prefix_ls *lp, struct in_addr *id, + struct in_addr *adv_router) +{ + memset (lp, 0, sizeof (struct prefix_ls)); + lp->family = 0; + if (id == NULL) + lp->prefixlen = 0; + else if (adv_router == NULL) + { + lp->prefixlen = 32; + lp->id = *id; + } + else + { + lp->prefixlen = 64; + lp->id = *id; + lp->adv_router = *adv_router; + } +} + +void +show_lsa_detail_proc (struct vty *vty, struct route_table *rt, + struct in_addr *id, struct in_addr *adv_router) +{ + struct prefix_ls lp; + struct route_node *rn, *start; + struct ospf_lsa *lsa; + + show_lsa_prefix_set (vty, &lp, id, adv_router); + start = route_node_get (rt, (struct prefix *) &lp); + if (start) + { + route_lock_node (start); + for (rn = start; rn; rn = route_next_until (rn, start)) + if ((lsa = rn->info)) + { +#ifdef HAVE_NSSA + /* Stay away from any Local Translated Type-7 LSAs */ + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) + continue; +#endif /* HAVE_NSSA */ + + if (show_function[lsa->data->type] != NULL) + show_function[lsa->data->type] (vty, lsa); + } + route_unlock_node (start); + } +} + +/* Show detail LSA information + -- if id is NULL then show all LSAs. */ +void +show_lsa_detail (struct vty *vty, struct ospf *ospf, int type, + struct in_addr *id, struct in_addr *adv_router) +{ + listnode node; + + switch (type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + vty_out (vty, " %s %s%s", + show_database_desc[type], + VTY_NEWLINE, VTY_NEWLINE); + show_lsa_detail_proc (vty, AS_LSDB (ospf, type), id, adv_router); + break; + default: + for (node = listhead (ospf->areas); node; nextnode (node)) + { + struct ospf_area *area = node->data; + vty_out (vty, "%s %s (Area %s)%s%s", + VTY_NEWLINE, show_database_desc[type], + ospf_area_desc_string (area), VTY_NEWLINE, VTY_NEWLINE); + show_lsa_detail_proc (vty, AREA_LSDB (area, type), id, adv_router); + } + break; + } +} + +void +show_lsa_detail_adv_router_proc (struct vty *vty, struct route_table *rt, + struct in_addr *adv_router) +{ + struct route_node *rn; + struct ospf_lsa *lsa; + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((lsa = rn->info)) + if (IPV4_ADDR_SAME (adv_router, &lsa->data->adv_router)) + { +#ifdef HAVE_NSSA + if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) + continue; +#endif /* HAVE_NSSA */ + if (show_function[lsa->data->type] != NULL) + show_function[lsa->data->type] (vty, lsa); + } +} + +/* Show detail LSA information. */ +void +show_lsa_detail_adv_router (struct vty *vty, struct ospf *ospf, int type, + struct in_addr *adv_router) +{ + listnode node; + + switch (type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + vty_out (vty, " %s %s%s", + show_database_desc[type], + VTY_NEWLINE, VTY_NEWLINE); + show_lsa_detail_adv_router_proc (vty, AS_LSDB (ospf, type), + adv_router); + break; + default: + for (node = listhead (ospf->areas); node; nextnode (node)) + { + struct ospf_area *area = node->data; + vty_out (vty, "%s %s (Area %s)%s%s", + VTY_NEWLINE, show_database_desc[type], + ospf_area_desc_string (area), VTY_NEWLINE, VTY_NEWLINE); + show_lsa_detail_adv_router_proc (vty, AREA_LSDB (area, type), + adv_router); + } + break; + } +} + +void +show_ip_ospf_database_summary (struct vty *vty, struct ospf *ospf, int self) +{ + struct ospf_lsa *lsa; + struct route_node *rn; + listnode node; + int type; + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + struct ospf_area *area = node->data; + for (type = OSPF_MIN_LSA; type < OSPF_MAX_LSA; type++) + { + switch (type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + continue; + default: + break; + } + if (ospf_lsdb_count_self (area->lsdb, type) > 0 || + (!self && ospf_lsdb_count (area->lsdb, type) > 0)) + { + vty_out (vty, " %s (Area %s)%s%s", + show_database_desc[type], + ospf_area_desc_string (area), + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, "%s%s", show_database_header[type], VTY_NEWLINE); + + LSDB_LOOP (AREA_LSDB (area, type), rn, lsa) + show_lsa_summary (vty, lsa, self); + + vty_out (vty, "%s", VTY_NEWLINE); + } + } + } + + for (type = OSPF_MIN_LSA; type < OSPF_MAX_LSA; type++) + { + switch (type) + { + case OSPF_AS_EXTERNAL_LSA: +#ifdef HAVE_OPAQUE_LSA + case OSPF_OPAQUE_AS_LSA: +#endif /* HAVE_OPAQUE_LSA */ + break;; + default: + continue; + } + if (ospf_lsdb_count_self (ospf->lsdb, type) || + (!self && ospf_lsdb_count (ospf->lsdb, type))) + { + vty_out (vty, " %s%s%s", + show_database_desc[type], + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, "%s%s", show_database_header[type], + VTY_NEWLINE); + + LSDB_LOOP (AS_LSDB (ospf, type), rn, lsa) + show_lsa_summary (vty, lsa, self); + + vty_out (vty, "%s", VTY_NEWLINE); + } + } + + vty_out (vty, "%s", VTY_NEWLINE); +} + +void +show_ip_ospf_database_maxage (struct vty *vty, struct ospf *ospf) +{ + listnode node; + struct ospf_lsa *lsa; + + vty_out (vty, "%s MaxAge Link States:%s%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + for (node = listhead (ospf->maxage_lsa); node; nextnode (node)) + if ((lsa = node->data) != NULL) + { + vty_out (vty, "Link type: %d%s", lsa->data->type, VTY_NEWLINE); + vty_out (vty, "Link State ID: %s%s", + inet_ntoa (lsa->data->id), VTY_NEWLINE); + vty_out (vty, "Advertising Router: %s%s", + inet_ntoa (lsa->data->adv_router), VTY_NEWLINE); + vty_out (vty, "LSA lock count: %d%s", lsa->lock, VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +#ifdef HAVE_NSSA +#define OSPF_LSA_TYPE_NSSA_DESC "NSSA external link state\n" +#define OSPF_LSA_TYPE_NSSA_CMD_STR "|nssa-external" +#else /* HAVE_NSSA */ +#define OSPF_LSA_TYPE_NSSA_DESC "" +#define OSPF_LSA_TYPE_NSSA_CMD_STR "" +#endif /* HAVE_NSSA */ + +#ifdef HAVE_OPAQUE_LSA +#define OSPF_LSA_TYPE_OPAQUE_LINK_DESC "Link local Opaque-LSA\n" +#define OSPF_LSA_TYPE_OPAQUE_AREA_DESC "Link area Opaque-LSA\n" +#define OSPF_LSA_TYPE_OPAQUE_AS_DESC "Link AS Opaque-LSA\n" +#define OSPF_LSA_TYPE_OPAQUE_CMD_STR "|opaque-link|opaque-area|opaque-as" +#else /* HAVE_OPAQUE_LSA */ +#define OSPF_LSA_TYPE_OPAQUE_LINK_DESC "" +#define OSPF_LSA_TYPE_OPAQUE_AREA_DESC "" +#define OSPF_LSA_TYPE_OPAQUE_AS_DESC "" +#define OSPF_LSA_TYPE_OPAQUE_CMD_STR "" +#endif /* HAVE_OPAQUE_LSA */ + +#define OSPF_LSA_TYPES_CMD_STR \ + "asbr-summary|external|network|router|summary" \ + OSPF_LSA_TYPE_NSSA_CMD_STR \ + OSPF_LSA_TYPE_OPAQUE_CMD_STR + +#define OSPF_LSA_TYPES_DESC \ + "ASBR summary link states\n" \ + "External link states\n" \ + "Network link states\n" \ + "Router link states\n" \ + "Network summary link states\n" \ + OSPF_LSA_TYPE_NSSA_DESC \ + OSPF_LSA_TYPE_OPAQUE_LINK_DESC \ + OSPF_LSA_TYPE_OPAQUE_AREA_DESC \ + OSPF_LSA_TYPE_OPAQUE_AS_DESC + +DEFUN (show_ip_ospf_database, + show_ip_ospf_database_cmd, + "show ip ospf database", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n") +{ + struct ospf *ospf; + int type, ret; + struct in_addr id, adv_router; + + ospf = ospf_lookup (); + if (ospf == NULL) + return CMD_SUCCESS; + + vty_out (vty, "%s OSPF Router with ID (%s)%s%s", VTY_NEWLINE, + inet_ntoa (ospf->router_id), VTY_NEWLINE, VTY_NEWLINE); + + /* Show all LSA. */ + if (argc == 0) + { + show_ip_ospf_database_summary (vty, ospf, 0); + return CMD_SUCCESS; + } + + /* Set database type to show. */ + if (strncmp (argv[0], "r", 1) == 0) + type = OSPF_ROUTER_LSA; + else if (strncmp (argv[0], "ne", 2) == 0) + type = OSPF_NETWORK_LSA; +#ifdef HAVE_NSSA + else if (strncmp (argv[0], "ns", 2) == 0) + type = OSPF_AS_NSSA_LSA; +#endif /* HAVE_NSSA */ + else if (strncmp (argv[0], "su", 2) == 0) + type = OSPF_SUMMARY_LSA; + else if (strncmp (argv[0], "a", 1) == 0) + type = OSPF_ASBR_SUMMARY_LSA; + else if (strncmp (argv[0], "e", 1) == 0) + type = OSPF_AS_EXTERNAL_LSA; + else if (strncmp (argv[0], "se", 2) == 0) + { + show_ip_ospf_database_summary (vty, ospf, 1); + return CMD_SUCCESS; + } + else if (strncmp (argv[0], "m", 1) == 0) + { + show_ip_ospf_database_maxage (vty, ospf); + return CMD_SUCCESS; + } +#ifdef HAVE_OPAQUE_LSA + else if (strncmp (argv[0], "opaque-l", 8) == 0) + type = OSPF_OPAQUE_LINK_LSA; + else if (strncmp (argv[0], "opaque-ar", 9) == 0) + type = OSPF_OPAQUE_AREA_LSA; + else if (strncmp (argv[0], "opaque-as", 9) == 0) + type = OSPF_OPAQUE_AS_LSA; +#endif /* HAVE_OPAQUE_LSA */ + else + return CMD_WARNING; + + /* `show ip ospf database LSA'. */ + if (argc == 1) + show_lsa_detail (vty, ospf, type, NULL, NULL); + else if (argc >= 2) + { + ret = inet_aton (argv[1], &id); + if (!ret) + return CMD_WARNING; + + /* `show ip ospf database LSA ID'. */ + if (argc == 2) + show_lsa_detail (vty, ospf, type, &id, NULL); + /* `show ip ospf database LSA ID adv-router ADV_ROUTER'. */ + else if (argc == 3) + { + if (strncmp (argv[2], "s", 1) == 0) + adv_router = ospf->router_id; + else + { + ret = inet_aton (argv[2], &adv_router); + if (!ret) + return CMD_WARNING; + } + show_lsa_detail (vty, ospf, type, &id, &adv_router); + } + } + + return CMD_SUCCESS; +} + +ALIAS (show_ip_ospf_database, + show_ip_ospf_database_type_cmd, + "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR "|max-age|self-originate)", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "LSAs in MaxAge list\n" + "Self-originated link states\n"); + +ALIAS (show_ip_ospf_database, + show_ip_ospf_database_type_id_cmd, + "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Link State ID (as an IP address)\n"); + +ALIAS (show_ip_ospf_database, + show_ip_ospf_database_type_id_adv_router_cmd, + "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D adv-router A.B.C.D", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Link State ID (as an IP address)\n" + "Advertising Router link states\n" + "Advertising Router (as an IP address)\n"); + +ALIAS (show_ip_ospf_database, + show_ip_ospf_database_type_id_self_cmd, + "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D (self-originate|)", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Link State ID (as an IP address)\n" + "Self-originated link states\n" + "\n"); + +DEFUN (show_ip_ospf_database_type_adv_router, + show_ip_ospf_database_type_adv_router_cmd, + "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") adv-router A.B.C.D", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Advertising Router link states\n" + "Advertising Router (as an IP address)\n") +{ + struct ospf *ospf; + int type, ret; + struct in_addr adv_router; + + ospf = ospf_lookup (); + if (ospf == NULL) + return CMD_SUCCESS; + + vty_out (vty, "%s OSPF Router with ID (%s)%s%s", VTY_NEWLINE, + inet_ntoa (ospf->router_id), VTY_NEWLINE, VTY_NEWLINE); + + if (argc != 2) + return CMD_WARNING; + + /* Set database type to show. */ + if (strncmp (argv[0], "r", 1) == 0) + type = OSPF_ROUTER_LSA; + else if (strncmp (argv[0], "ne", 2) == 0) + type = OSPF_NETWORK_LSA; +#ifdef HAVE_NSSA + else if (strncmp (argv[0], "ns", 2) == 0) + type = OSPF_AS_NSSA_LSA; +#endif /* HAVE_NSSA */ + else if (strncmp (argv[0], "s", 1) == 0) + type = OSPF_SUMMARY_LSA; + else if (strncmp (argv[0], "a", 1) == 0) + type = OSPF_ASBR_SUMMARY_LSA; + else if (strncmp (argv[0], "e", 1) == 0) + type = OSPF_AS_EXTERNAL_LSA; +#ifdef HAVE_OPAQUE_LSA + else if (strncmp (argv[0], "opaque-l", 8) == 0) + type = OSPF_OPAQUE_LINK_LSA; + else if (strncmp (argv[0], "opaque-ar", 9) == 0) + type = OSPF_OPAQUE_AREA_LSA; + else if (strncmp (argv[0], "opaque-as", 9) == 0) + type = OSPF_OPAQUE_AS_LSA; +#endif /* HAVE_OPAQUE_LSA */ + else + return CMD_WARNING; + + /* `show ip ospf database LSA adv-router ADV_ROUTER'. */ + if (strncmp (argv[1], "s", 1) == 0) + adv_router = ospf->router_id; + else + { + ret = inet_aton (argv[1], &adv_router); + if (!ret) + return CMD_WARNING; + } + + show_lsa_detail_adv_router (vty, ospf, type, &adv_router); + + return CMD_SUCCESS; +} + +ALIAS (show_ip_ospf_database_type_adv_router, + show_ip_ospf_database_type_self_cmd, + "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") (self-originate|)", + SHOW_STR + IP_STR + "OSPF information\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Self-originated link states\n"); + + +DEFUN (ip_ospf_authentication_args, + ip_ospf_authentication_args_addr_cmd, + "ip ospf authentication (null|message-digest) A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n" + "Use null authentication\n" + "Use message-digest authentication\n" + "Address of interface") +{ + struct interface *ifp; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + /* Handle null authentication */ + if ( argv[0][0] == 'n' ) + { + SET_IF_PARAM (params, auth_type); + params->auth_type = OSPF_AUTH_NULL; + return CMD_SUCCESS; + } + + /* Handle message-digest authentication */ + if ( argv[0][0] == 'm' ) + { + SET_IF_PARAM (params, auth_type); + params->auth_type = OSPF_AUTH_CRYPTOGRAPHIC; + return CMD_SUCCESS; + } + + vty_out (vty, "You shouldn't get here!%s", VTY_NEWLINE); + return CMD_WARNING; +} + +ALIAS (ip_ospf_authentication_args, + ip_ospf_authentication_args_cmd, + "ip ospf authentication (null|message-digest)", + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n" + "Use null authentication\n" + "Use message-digest authentication\n"); + +DEFUN (ip_ospf_authentication, + ip_ospf_authentication_addr_cmd, + "ip ospf authentication A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n" + "Address of interface") +{ + struct interface *ifp; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, auth_type); + params->auth_type = OSPF_AUTH_SIMPLE; + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_authentication, + ip_ospf_authentication_cmd, + "ip ospf authentication", + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n"); + +DEFUN (no_ip_ospf_authentication, + no_ip_ospf_authentication_addr_cmd, + "no ip ospf authentication A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n" + "Address of interface") +{ + struct interface *ifp; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + params->auth_type = OSPF_AUTH_NOTSET; + UNSET_IF_PARAM (params, auth_type); + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_authentication, + no_ip_ospf_authentication_cmd, + "no ip ospf authentication", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n"); + +DEFUN (ip_ospf_authentication_key, + ip_ospf_authentication_key_addr_cmd, + "ip ospf authentication-key AUTH_KEY A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Authentication password (key)\n" + "The OSPF password (key)\n" + "Address of interface") +{ + struct interface *ifp; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + + memset (params->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE + 1); + strncpy (params->auth_simple, argv[0], OSPF_AUTH_SIMPLE_SIZE); + SET_IF_PARAM (params, auth_simple); + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_authentication_key, + ip_ospf_authentication_key_cmd, + "ip ospf authentication-key AUTH_KEY", + "IP Information\n" + "OSPF interface commands\n" + "Authentication password (key)\n" + "The OSPF password (key)"); + +ALIAS (ip_ospf_authentication_key, + ospf_authentication_key_cmd, + "ospf authentication-key AUTH_KEY", + "OSPF interface commands\n" + "Authentication password (key)\n" + "The OSPF password (key)"); + +DEFUN (no_ip_ospf_authentication_key, + no_ip_ospf_authentication_key_addr_cmd, + "no ip ospf authentication-key A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Authentication password (key)\n" + "Address of interface") +{ + struct interface *ifp; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + memset (params->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE); + UNSET_IF_PARAM (params, auth_simple); + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_authentication_key, + no_ip_ospf_authentication_key_cmd, + "no ip ospf authentication-key", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Authentication password (key)\n"); + +ALIAS (no_ip_ospf_authentication_key, + no_ospf_authentication_key_cmd, + "no ospf authentication-key", + NO_STR + "OSPF interface commands\n" + "Authentication password (key)\n"); + +DEFUN (ip_ospf_message_digest_key, + ip_ospf_message_digest_key_addr_cmd, + "ip ospf message-digest-key <1-255> md5 KEY A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n" + "Use MD5 algorithm\n" + "The OSPF password (key)" + "Address of interface") +{ + struct interface *ifp; + struct crypt_key *ck; + u_char key_id; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 3) + { + ret = inet_aton(argv[2], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + key_id = strtol (argv[0], NULL, 10); + if (ospf_crypt_key_lookup (params->auth_crypt, key_id) != NULL) + { + vty_out (vty, "OSPF: Key %d already exists%s", key_id, VTY_NEWLINE); + return CMD_WARNING; + } + + ck = ospf_crypt_key_new (); + ck->key_id = (u_char) key_id; + memset (ck->auth_key, 0, OSPF_AUTH_MD5_SIZE+1); + strncpy (ck->auth_key, argv[1], OSPF_AUTH_MD5_SIZE); + + ospf_crypt_key_add (params->auth_crypt, ck); + SET_IF_PARAM (params, auth_crypt); + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_message_digest_key, + ip_ospf_message_digest_key_cmd, + "ip ospf message-digest-key <1-255> md5 KEY", + "IP Information\n" + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n" + "Use MD5 algorithm\n" + "The OSPF password (key)"); + +ALIAS (ip_ospf_message_digest_key, + ospf_message_digest_key_cmd, + "ospf message-digest-key <1-255> md5 KEY", + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n" + "Use MD5 algorithm\n" + "The OSPF password (key)"); + +DEFUN (no_ip_ospf_message_digest_key, + no_ip_ospf_message_digest_key_addr_cmd, + "no ip ospf message-digest-key <1-255> A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n" + "Address of interface") +{ + struct interface *ifp; + struct crypt_key *ck; + int key_id; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + key_id = strtol (argv[0], NULL, 10); + ck = ospf_crypt_key_lookup (params->auth_crypt, key_id); + if (ck == NULL) + { + vty_out (vty, "OSPF: Key %d does not exist%s", key_id, VTY_NEWLINE); + return CMD_WARNING; + } + + ospf_crypt_key_delete (params->auth_crypt, key_id); + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_message_digest_key, + no_ip_ospf_message_digest_key_cmd, + "no ip ospf message-digest-key <1-255>", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n"); + +ALIAS (no_ip_ospf_message_digest_key, + no_ospf_message_digest_key_cmd, + "no ospf message-digest-key <1-255>", + NO_STR + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n"); + +DEFUN (ip_ospf_cost, + ip_ospf_cost_addr_cmd, + "ip ospf cost <1-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Interface cost\n" + "Cost\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + u_int32_t cost; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + params = IF_DEF_PARAMS (ifp); + + cost = strtol (argv[0], NULL, 10); + + /* cost range is <1-65535>. */ + if (cost < 1 || cost > 65535) + { + vty_out (vty, "Interface output cost is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, output_cost_cmd); + params->output_cost_cmd = cost; + + ospf_if_recalculate_output_cost (ifp); + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_cost, + ip_ospf_cost_cmd, + "ip ospf cost <1-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Interface cost\n" + "Cost"); + +ALIAS (ip_ospf_cost, + ospf_cost_cmd, + "ospf cost <1-65535>", + "OSPF interface commands\n" + "Interface cost\n" + "Cost"); + +DEFUN (no_ip_ospf_cost, + no_ip_ospf_cost_addr_cmd, + "no ip ospf cost A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Interface cost\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, output_cost_cmd); + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + ospf_if_recalculate_output_cost (ifp); + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_cost, + no_ip_ospf_cost_cmd, + "no ip ospf cost", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Interface cost\n"); + +ALIAS (no_ip_ospf_cost, + no_ospf_cost_cmd, + "no ospf cost", + NO_STR + "OSPF interface commands\n" + "Interface cost\n"); + +void +ospf_nbr_timer_update (struct ospf_interface *oi) +{ + struct route_node *rn; + struct ospf_neighbor *nbr; + + for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) + if ((nbr = rn->info)) + { + nbr->v_inactivity = OSPF_IF_PARAM (oi, v_wait); + nbr->v_db_desc = OSPF_IF_PARAM (oi, retransmit_interval); + nbr->v_ls_req = OSPF_IF_PARAM (oi, retransmit_interval); + nbr->v_ls_upd = OSPF_IF_PARAM (oi, retransmit_interval); + } +} + +DEFUN (ip_ospf_dead_interval, + ip_ospf_dead_interval_addr_cmd, + "ip ospf dead-interval <1-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n" + "Seconds\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + u_int32_t seconds; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + struct ospf_interface *oi; + struct route_node *rn; + struct ospf *ospf; + + ospf = ospf_lookup (); + + params = IF_DEF_PARAMS (ifp); + + seconds = strtol (argv[0], NULL, 10); + + /* dead_interval range is <1-65535>. */ + if (seconds < 1 || seconds > 65535) + { + vty_out (vty, "Router Dead Interval is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, v_wait); + params->v_wait = seconds; + + /* Update timer values in neighbor structure. */ + if (argc == 2) + { + if (ospf) + { + oi = ospf_if_lookup_by_local_addr (ospf, ifp, addr); + if (oi) + ospf_nbr_timer_update (oi); + } + } + else + { + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + if ((oi = rn->info)) + ospf_nbr_timer_update (oi); + } + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_dead_interval, + ip_ospf_dead_interval_cmd, + "ip ospf dead-interval <1-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n" + "Seconds\n"); + +ALIAS (ip_ospf_dead_interval, + ospf_dead_interval_cmd, + "ospf dead-interval <1-65535>", + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n" + "Seconds\n"); + +DEFUN (no_ip_ospf_dead_interval, + no_ip_ospf_dead_interval_addr_cmd, + "no ip ospf dead-interval A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + struct ospf_interface *oi; + struct route_node *rn; + struct ospf *ospf; + + ospf = ospf_lookup (); + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, v_wait); + params->v_wait = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + /* Update timer values in neighbor structure. */ + if (argc == 1) + { + if (ospf) + { + oi = ospf_if_lookup_by_local_addr (ospf, ifp, addr); + if (oi) + ospf_nbr_timer_update (oi); + } + } + else + { + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + if ((oi = rn->info)) + ospf_nbr_timer_update (oi); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_dead_interval, + no_ip_ospf_dead_interval_cmd, + "no ip ospf dead-interval", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n"); + +ALIAS (no_ip_ospf_dead_interval, + no_ospf_dead_interval_cmd, + "no ospf dead-interval", + NO_STR + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n"); + +DEFUN (ip_ospf_hello_interval, + ip_ospf_hello_interval_addr_cmd, + "ip ospf hello-interval <1-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Time between HELLO packets\n" + "Seconds\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + u_int32_t seconds; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + params = IF_DEF_PARAMS (ifp); + + seconds = strtol (argv[0], NULL, 10); + + /* HelloInterval range is <1-65535>. */ + if (seconds < 1 || seconds > 65535) + { + vty_out (vty, "Hello Interval is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, v_hello); + params->v_hello = seconds; + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_hello_interval, + ip_ospf_hello_interval_cmd, + "ip ospf hello-interval <1-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Time between HELLO packets\n" + "Seconds\n"); + +ALIAS (ip_ospf_hello_interval, + ospf_hello_interval_cmd, + "ospf hello-interval <1-65535>", + "OSPF interface commands\n" + "Time between HELLO packets\n" + "Seconds\n"); + +DEFUN (no_ip_ospf_hello_interval, + no_ip_ospf_hello_interval_addr_cmd, + "no ip ospf hello-interval A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Time between HELLO packets\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, v_hello); + params->v_hello = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_hello_interval, + no_ip_ospf_hello_interval_cmd, + "no ip ospf hello-interval", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Time between HELLO packets\n"); + +ALIAS (no_ip_ospf_hello_interval, + no_ospf_hello_interval_cmd, + "no ospf hello-interval", + NO_STR + "OSPF interface commands\n" + "Time between HELLO packets\n"); + +DEFUN (ip_ospf_network, + ip_ospf_network_cmd, + "ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", + "IP Information\n" + "OSPF interface commands\n" + "Network type\n" + "Specify OSPF broadcast multi-access network\n" + "Specify OSPF NBMA network\n" + "Specify OSPF point-to-multipoint network\n" + "Specify OSPF point-to-point network\n") +{ + struct interface *ifp = vty->index; + int old_type = IF_DEF_PARAMS (ifp)->type; + struct route_node *rn; + + if (strncmp (argv[0], "b", 1) == 0) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST; + else if (strncmp (argv[0], "n", 1) == 0) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_NBMA; + else if (strncmp (argv[0], "point-to-m", 10) == 0) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOMULTIPOINT; + else if (strncmp (argv[0], "point-to-p", 10) == 0) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOPOINT; + + if (IF_DEF_PARAMS (ifp)->type == old_type) + return CMD_SUCCESS; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), type); + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct ospf_interface *oi = rn->info; + + if (!oi) + continue; + + oi->type = IF_DEF_PARAMS (ifp)->type; + + if (oi->state > ISM_Down) + { + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp); + } + } + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_network, + ospf_network_cmd, + "ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", + "OSPF interface commands\n" + "Network type\n" + "Specify OSPF broadcast multi-access network\n" + "Specify OSPF NBMA network\n" + "Specify OSPF point-to-multipoint network\n" + "Specify OSPF point-to-point network\n"); + +DEFUN (no_ip_ospf_network, + no_ip_ospf_network_cmd, + "no ip ospf network", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Network type\n") +{ + struct interface *ifp = vty->index; + int old_type = IF_DEF_PARAMS (ifp)->type; + struct route_node *rn; + + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST; + + if (IF_DEF_PARAMS (ifp)->type == old_type) + return CMD_SUCCESS; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct ospf_interface *oi = rn->info; + + if (!oi) + continue; + + oi->type = IF_DEF_PARAMS (ifp)->type; + + if (oi->state > ISM_Down) + { + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); + OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp); + } + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_network, + no_ospf_network_cmd, + "no ospf network", + NO_STR + "OSPF interface commands\n" + "Network type\n"); + +DEFUN (ip_ospf_priority, + ip_ospf_priority_addr_cmd, + "ip ospf priority <0-255> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Router priority\n" + "Priority\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + u_int32_t priority; + struct route_node *rn; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + params = IF_DEF_PARAMS (ifp); + + priority = strtol (argv[0], NULL, 10); + + /* Router Priority range is <0-255>. */ + if (priority < 0 || priority > 255) + { + vty_out (vty, "Router Priority is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, priority); + params->priority = priority; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct ospf_interface *oi = rn->info; + + if (!oi) + continue; + + + if (PRIORITY (oi) != OSPF_IF_PARAM (oi, priority)) + { + PRIORITY (oi) = OSPF_IF_PARAM (oi, priority); + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); + } + } + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_priority, + ip_ospf_priority_cmd, + "ip ospf priority <0-255>", + "IP Information\n" + "OSPF interface commands\n" + "Router priority\n" + "Priority\n"); + +ALIAS (ip_ospf_priority, + ospf_priority_cmd, + "ospf priority <0-255>", + "OSPF interface commands\n" + "Router priority\n" + "Priority\n"); + +DEFUN (no_ip_ospf_priority, + no_ip_ospf_priority_addr_cmd, + "no ip ospf priority A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Router priority\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + struct route_node *rn; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, priority); + params->priority = OSPF_ROUTER_PRIORITY_DEFAULT; + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct ospf_interface *oi = rn->info; + + if (!oi) + continue; + + + if (PRIORITY (oi) != OSPF_IF_PARAM (oi, priority)) + { + PRIORITY (oi) = OSPF_IF_PARAM (oi, priority); + OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); + } + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_priority, + no_ip_ospf_priority_cmd, + "no ip ospf priority", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Router priority\n"); + +ALIAS (no_ip_ospf_priority, + no_ospf_priority_cmd, + "no ospf priority", + NO_STR + "OSPF interface commands\n" + "Router priority\n"); + +DEFUN (ip_ospf_retransmit_interval, + ip_ospf_retransmit_interval_addr_cmd, + "ip ospf retransmit-interval <3-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n" + "Seconds\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + u_int32_t seconds; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + params = IF_DEF_PARAMS (ifp); + seconds = strtol (argv[0], NULL, 10); + + /* Retransmit Interval range is <3-65535>. */ + if (seconds < 3 || seconds > 65535) + { + vty_out (vty, "Retransmit Interval is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, retransmit_interval); + params->retransmit_interval = seconds; + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_retransmit_interval, + ip_ospf_retransmit_interval_cmd, + "ip ospf retransmit-interval <3-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n" + "Seconds\n"); + +ALIAS (ip_ospf_retransmit_interval, + ospf_retransmit_interval_cmd, + "ospf retransmit-interval <3-65535>", + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n" + "Seconds\n"); + +DEFUN (no_ip_ospf_retransmit_interval, + no_ip_ospf_retransmit_interval_addr_cmd, + "no ip ospf retransmit-interval A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, retransmit_interval); + params->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_retransmit_interval, + no_ip_ospf_retransmit_interval_cmd, + "no ip ospf retransmit-interval", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n"); + +ALIAS (no_ip_ospf_retransmit_interval, + no_ospf_retransmit_interval_cmd, + "no ospf retransmit-interval", + NO_STR + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n"); + +DEFUN (ip_ospf_transmit_delay, + ip_ospf_transmit_delay_addr_cmd, + "ip ospf transmit-delay <1-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Link state transmit delay\n" + "Seconds\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + u_int32_t seconds; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + params = IF_DEF_PARAMS (ifp); + seconds = strtol (argv[0], NULL, 10); + + /* Transmit Delay range is <1-65535>. */ + if (seconds < 1 || seconds > 65535) + { + vty_out (vty, "Transmit Delay is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 2) + { + ret = inet_aton(argv[1], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_get_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + SET_IF_PARAM (params, transmit_delay); + params->transmit_delay = seconds; + + return CMD_SUCCESS; +} + +ALIAS (ip_ospf_transmit_delay, + ip_ospf_transmit_delay_cmd, + "ip ospf transmit-delay <1-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Link state transmit delay\n" + "Seconds\n"); + +ALIAS (ip_ospf_transmit_delay, + ospf_transmit_delay_cmd, + "ospf transmit-delay <1-65535>", + "OSPF interface commands\n" + "Link state transmit delay\n" + "Seconds\n"); + +DEFUN (no_ip_ospf_transmit_delay, + no_ip_ospf_transmit_delay_addr_cmd, + "no ip ospf transmit-delay A.B.C.D", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Link state transmit delay\n" + "Address of interface") +{ + struct interface *ifp = vty->index; + struct in_addr addr; + int ret; + struct ospf_if_params *params; + + ifp = vty->index; + params = IF_DEF_PARAMS (ifp); + + if (argc == 1) + { + ret = inet_aton(argv[0], &addr); + if (!ret) + { + vty_out (vty, "Please specify interface address by A.B.C.D%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + params = ospf_lookup_if_params (ifp, addr); + if (params == NULL) + return CMD_SUCCESS; + } + + UNSET_IF_PARAM (params, transmit_delay); + params->transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; + + if (params != IF_DEF_PARAMS (ifp)) + { + ospf_free_if_params (ifp, addr); + ospf_if_update_params (ifp, addr); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ip_ospf_transmit_delay, + no_ip_ospf_transmit_delay_cmd, + "no ip ospf transmit-delay", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Link state transmit delay\n"); + +ALIAS (no_ip_ospf_transmit_delay, + no_ospf_transmit_delay_cmd, + "no ospf transmit-delay", + NO_STR + "OSPF interface commands\n" + "Link state transmit delay\n"); + + +DEFUN (ospf_redistribute_source_metric_type, + ospf_redistribute_source_metric_type_routemap_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> metric-type (1|2) route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Metric for redistributed routes\n" + "OSPF default metric\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + int source; + int type = -1; + int metric = -1; + + /* Get distribute source. */ + if (!str2distribute_source (argv[0], &source)) + return CMD_WARNING; + + /* Get metric value. */ + if (argc >= 2) + if (!str2metric (argv[1], &metric)) + return CMD_WARNING; + + /* Get metric type. */ + if (argc >= 3) + if (!str2metric_type (argv[2], &type)) + return CMD_WARNING; + + if (argc == 4) + ospf_routemap_set (ospf, source, argv[3]); + else + ospf_routemap_unset (ospf, source); + + return ospf_redistribute_set (ospf, source, type, metric); +} + +ALIAS (ospf_redistribute_source_metric_type, + ospf_redistribute_source_metric_type_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> metric-type (1|2)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Metric for redistributed routes\n" + "OSPF default metric\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n"); + +ALIAS (ospf_redistribute_source_metric_type, + ospf_redistribute_source_metric_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Metric for redistributed routes\n" + "OSPF default metric\n"); + +DEFUN (ospf_redistribute_source_type_metric, + ospf_redistribute_source_type_metric_routemap_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Metric for redistributed routes\n" + "OSPF default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + int source; + int type = -1; + int metric = -1; + + /* Get distribute source. */ + if (!str2distribute_source (argv[0], &source)) + return CMD_WARNING; + + /* Get metric value. */ + if (argc >= 2) + if (!str2metric_type (argv[1], &type)) + return CMD_WARNING; + + /* Get metric type. */ + if (argc >= 3) + if (!str2metric (argv[2], &metric)) + return CMD_WARNING; + + if (argc == 4) + ospf_routemap_set (ospf, source, argv[3]); + else + ospf_routemap_unset (ospf, source); + + return ospf_redistribute_set (ospf, source, type, metric); +} + +ALIAS (ospf_redistribute_source_type_metric, + ospf_redistribute_source_type_metric_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Metric for redistributed routes\n" + "OSPF default metric\n"); + +ALIAS (ospf_redistribute_source_type_metric, + ospf_redistribute_source_type_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n"); + +ALIAS (ospf_redistribute_source_type_metric, + ospf_redistribute_source_cmd, + "redistribute (kernel|connected|static|rip|bgp)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n"); + +DEFUN (ospf_redistribute_source_metric_routemap, + ospf_redistribute_source_metric_routemap_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Metric for redistributed routes\n" + "OSPF default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + int source; + int metric = -1; + + /* Get distribute source. */ + if (!str2distribute_source (argv[0], &source)) + return CMD_WARNING; + + /* Get metric value. */ + if (argc >= 2) + if (!str2metric (argv[1], &metric)) + return CMD_WARNING; + + if (argc == 3) + ospf_routemap_set (ospf, source, argv[2]); + else + ospf_routemap_unset (ospf, source); + + return ospf_redistribute_set (ospf, source, -1, metric); +} + +DEFUN (ospf_redistribute_source_type_routemap, + ospf_redistribute_source_type_routemap_cmd, + "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + int source; + int type = -1; + + /* Get distribute source. */ + if (!str2distribute_source (argv[0], &source)) + return CMD_WARNING; + + /* Get metric value. */ + if (argc >= 2) + if (!str2metric_type (argv[1], &type)) + return CMD_WARNING; + + if (argc == 3) + ospf_routemap_set (ospf, source, argv[2]); + else + ospf_routemap_unset (ospf, source); + + return ospf_redistribute_set (ospf, source, type, -1); +} + +DEFUN (ospf_redistribute_source_routemap, + ospf_redistribute_source_routemap_cmd, + "redistribute (kernel|connected|static|rip|bgp) route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + int source; + + /* Get distribute source. */ + if (!str2distribute_source (argv[0], &source)) + return CMD_WARNING; + + if (argc == 2) + ospf_routemap_set (ospf, source, argv[1]); + else + ospf_routemap_unset (ospf, source); + + return ospf_redistribute_set (ospf, source, -1, -1); +} + +DEFUN (no_ospf_redistribute_source, + no_ospf_redistribute_source_cmd, + "no redistribute (kernel|connected|static|rip|bgp)", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n") +{ + struct ospf *ospf = vty->index; + int source; + + if (!str2distribute_source (argv[0], &source)) + return CMD_WARNING; + + ospf_routemap_unset (ospf, source); + return ospf_redistribute_unset (ospf, source); +} + +DEFUN (ospf_distribute_list_out, + ospf_distribute_list_out_cmd, + "distribute-list WORD out (kernel|connected|static|rip|bgp)", + "Filter networks in routing updates\n" + "Access-list name\n" + OUT_STR + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n") +{ + struct ospf *ospf = vty->index; + int source; + + /* Get distribute source. */ + if (!str2distribute_source (argv[1], &source)) + return CMD_WARNING; + + return ospf_distribute_list_out_set (ospf, source, argv[0]); +} + +DEFUN (no_ospf_distribute_list_out, + no_ospf_distribute_list_out_cmd, + "no distribute-list WORD out (kernel|connected|static|rip|bgp)", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + OUT_STR + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n") +{ + struct ospf *ospf = vty->index; + int source; + + if (!str2distribute_source (argv[1], &source)) + return CMD_WARNING; + + return ospf_distribute_list_out_unset (ospf, source, argv[0]); +} + +/* Default information originate. */ +DEFUN (ospf_default_information_originate_metric_type_routemap, + ospf_default_information_originate_metric_type_routemap_cmd, + "default-information originate metric <0-16777214> metric-type (1|2) route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + int type = -1; + int metric = -1; + + /* Get metric value. */ + if (argc >= 1) + if (!str2metric (argv[0], &metric)) + return CMD_WARNING; + + /* Get metric type. */ + if (argc >= 2) + if (!str2metric_type (argv[1], &type)) + return CMD_WARNING; + + if (argc == 3) + ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[2]); + else + ospf_routemap_unset (ospf, DEFAULT_ROUTE); + + return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, + type, metric); +} + +ALIAS (ospf_default_information_originate_metric_type_routemap, + ospf_default_information_originate_metric_type_cmd, + "default-information originate metric <0-16777214> metric-type (1|2)", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n"); + +ALIAS (ospf_default_information_originate_metric_type_routemap, + ospf_default_information_originate_metric_cmd, + "default-information originate metric <0-16777214>", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF default metric\n" + "OSPF metric\n"); + +ALIAS (ospf_default_information_originate_metric_type_routemap, + ospf_default_information_originate_cmd, + "default-information originate", + "Control distribution of default information\n" + "Distribute a default route\n"); + +/* Default information originate. */ +DEFUN (ospf_default_information_originate_metric_routemap, + ospf_default_information_originate_metric_routemap_cmd, + "default-information originate metric <0-16777214> route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + int metric = -1; + + /* Get metric value. */ + if (argc >= 1) + if (!str2metric (argv[0], &metric)) + return CMD_WARNING; + + if (argc == 2) + ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[1]); + else + ospf_routemap_unset (ospf, DEFAULT_ROUTE); + + return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, + -1, metric); +} + +/* Default information originate. */ +DEFUN (ospf_default_information_originate_routemap, + ospf_default_information_originate_routemap_cmd, + "default-information originate route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + + if (argc == 1) + ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[0]); + else + ospf_routemap_unset (ospf, DEFAULT_ROUTE); + + return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, -1, -1); +} + +DEFUN (ospf_default_information_originate_type_metric_routemap, + ospf_default_information_originate_type_metric_routemap_cmd, + "default-information originate metric-type (1|2) metric <0-16777214> route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "OSPF default metric\n" + "OSPF metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + int type = -1; + int metric = -1; + + /* Get metric type. */ + if (argc >= 1) + if (!str2metric_type (argv[0], &type)) + return CMD_WARNING; + + /* Get metric value. */ + if (argc >= 2) + if (!str2metric (argv[1], &metric)) + return CMD_WARNING; + + if (argc == 3) + ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[2]); + else + ospf_routemap_unset (ospf, DEFAULT_ROUTE); + + return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, + type, metric); +} + +ALIAS (ospf_default_information_originate_type_metric_routemap, + ospf_default_information_originate_type_metric_cmd, + "default-information originate metric-type (1|2) metric <0-16777214>", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "OSPF default metric\n" + "OSPF metric\n"); + +ALIAS (ospf_default_information_originate_type_metric_routemap, + ospf_default_information_originate_type_cmd, + "default-information originate metric-type (1|2)", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n"); + +DEFUN (ospf_default_information_originate_type_routemap, + ospf_default_information_originate_type_routemap_cmd, + "default-information originate metric-type (1|2) route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + int type = -1; + + /* Get metric type. */ + if (argc >= 1) + if (!str2metric_type (argv[0], &type)) + return CMD_WARNING; + + if (argc == 2) + ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[1]); + else + ospf_routemap_unset (ospf, DEFAULT_ROUTE); + + return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, + type, -1); +} + +DEFUN (ospf_default_information_originate_always_metric_type_routemap, + ospf_default_information_originate_always_metric_type_routemap_cmd, + "default-information originate always metric <0-16777214> metric-type (1|2) route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + int type = -1; + int metric = -1; + + /* Get metric value. */ + if (argc >= 1) + if (!str2metric (argv[0], &metric)) + return CMD_WARNING; + + /* Get metric type. */ + if (argc >= 2) + if (!str2metric_type (argv[1], &type)) + return CMD_WARNING; + + if (argc == 3) + ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[2]); + else + ospf_routemap_unset (ospf, DEFAULT_ROUTE); + + return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, + type, metric); +} + +ALIAS (ospf_default_information_originate_always_metric_type_routemap, + ospf_default_information_originate_always_metric_type_cmd, + "default-information originate always metric <0-16777214> metric-type (1|2)", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n"); + +ALIAS (ospf_default_information_originate_always_metric_type_routemap, + ospf_default_information_originate_always_metric_cmd, + "default-information originate always metric <0-16777214>", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n"); + +ALIAS (ospf_default_information_originate_always_metric_type_routemap, + ospf_default_information_originate_always_cmd, + "default-information originate always", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n"); + +DEFUN (ospf_default_information_originate_always_metric_routemap, + ospf_default_information_originate_always_metric_routemap_cmd, + "default-information originate always metric <0-16777214> route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + int metric = -1; + + /* Get metric value. */ + if (argc >= 1) + if (!str2metric (argv[0], &metric)) + return CMD_WARNING; + + if (argc == 2) + ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[1]); + else + ospf_routemap_unset (ospf, DEFAULT_ROUTE); + + return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, + -1, metric); +} + +DEFUN (ospf_default_information_originate_always_routemap, + ospf_default_information_originate_always_routemap_cmd, + "default-information originate always route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + + if (argc == 1) + ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[0]); + else + ospf_routemap_unset (ospf, DEFAULT_ROUTE); + + return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, -1, -1); +} + +DEFUN (ospf_default_information_originate_always_type_metric_routemap, + ospf_default_information_originate_always_type_metric_routemap_cmd, + "default-information originate always metric-type (1|2) metric <0-16777214> route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "OSPF default metric\n" + "OSPF metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + int type = -1; + int metric = -1; + + /* Get metric type. */ + if (argc >= 1) + if (!str2metric_type (argv[0], &type)) + return CMD_WARNING; + + /* Get metric value. */ + if (argc >= 2) + if (!str2metric (argv[1], &metric)) + return CMD_WARNING; + + if (argc == 3) + ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[2]); + else + ospf_routemap_unset (ospf, DEFAULT_ROUTE); + + return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, + type, metric); +} + +ALIAS (ospf_default_information_originate_always_type_metric_routemap, + ospf_default_information_originate_always_type_metric_cmd, + "default-information originate always metric-type (1|2) metric <0-16777214>", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "OSPF default metric\n" + "OSPF metric\n"); + +ALIAS (ospf_default_information_originate_always_type_metric_routemap, + ospf_default_information_originate_always_type_cmd, + "default-information originate always metric-type (1|2)", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n"); + +DEFUN (ospf_default_information_originate_always_type_routemap, + ospf_default_information_originate_always_type_routemap_cmd, + "default-information originate always metric-type (1|2) route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf *ospf = vty->index; + int type = -1; + + /* Get metric type. */ + if (argc >= 1) + if (!str2metric_type (argv[0], &type)) + return CMD_WARNING; + + if (argc == 2) + ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[1]); + else + ospf_routemap_unset (ospf, DEFAULT_ROUTE); + + return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, + type, -1); +} + +DEFUN (no_ospf_default_information_originate, + no_ospf_default_information_originate_cmd, + "no default-information originate", + NO_STR + "Control distribution of default information\n" + "Distribute a default route\n") +{ + struct ospf *ospf = vty->index; + struct prefix_ipv4 p; + struct in_addr nexthop; + + p.family = AF_INET; + p.prefix.s_addr = 0; + p.prefixlen = 0; + + ospf_external_lsa_flush (ospf, DEFAULT_ROUTE, &p, 0, nexthop); + + if (EXTERNAL_INFO (DEFAULT_ROUTE)) { + ospf_external_info_delete (DEFAULT_ROUTE, p); + route_table_finish (EXTERNAL_INFO (DEFAULT_ROUTE)); + EXTERNAL_INFO (DEFAULT_ROUTE) = NULL; + } + + ospf_routemap_unset (ospf, DEFAULT_ROUTE); + return ospf_redistribute_default_unset (ospf); +} + +DEFUN (ospf_default_metric, + ospf_default_metric_cmd, + "default-metric <0-16777214>", + "Set metric of redistributed routes\n" + "Default metric\n") +{ + struct ospf *ospf = vty->index; + int metric = -1; + + if (!str2metric (argv[0], &metric)) + return CMD_WARNING; + + ospf->default_metric = metric; + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_default_metric, + no_ospf_default_metric_cmd, + "no default-metric", + NO_STR + "Set metric of redistributed routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->default_metric = -1; + + return CMD_SUCCESS; +} + +ALIAS (no_ospf_default_metric, + no_ospf_default_metric_val_cmd, + "no default-metric <0-16777214>", + NO_STR + "Set metric of redistributed routes\n" + "Default metric\n"); + +DEFUN (ospf_distance, + ospf_distance_cmd, + "distance <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_all = atoi (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_distance, + no_ospf_distance_cmd, + "no distance <1-255>", + NO_STR + "Define an administrative distance\n" + "OSPF Administrative distance\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_all = 0; + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_distance_ospf, + no_ospf_distance_ospf_cmd, + "no distance ospf", + NO_STR + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "OSPF Distance\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_intra = 0; + ospf->distance_inter = 0; + ospf->distance_external = 0; + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_intra, + ospf_distance_ospf_intra_cmd, + "distance ospf intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_intra = atoi (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_intra_inter, + ospf_distance_ospf_intra_inter_cmd, + "distance ospf intra-area <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_intra = atoi (argv[0]); + ospf->distance_inter = atoi (argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_intra_external, + ospf_distance_ospf_intra_external_cmd, + "distance ospf intra-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_intra = atoi (argv[0]); + ospf->distance_external = atoi (argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_intra_inter_external, + ospf_distance_ospf_intra_inter_external_cmd, + "distance ospf intra-area <1-255> inter-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_intra = atoi (argv[0]); + ospf->distance_inter = atoi (argv[1]); + ospf->distance_external = atoi (argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_intra_external_inter, + ospf_distance_ospf_intra_external_inter_cmd, + "distance ospf intra-area <1-255> external <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "External routes\n" + "Distance for external routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_intra = atoi (argv[0]); + ospf->distance_external = atoi (argv[1]); + ospf->distance_inter = atoi (argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_inter, + ospf_distance_ospf_inter_cmd, + "distance ospf inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_inter = atoi (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_inter_intra, + ospf_distance_ospf_inter_intra_cmd, + "distance ospf inter-area <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_inter = atoi (argv[0]); + ospf->distance_intra = atoi (argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_inter_external, + ospf_distance_ospf_inter_external_cmd, + "distance ospf inter-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_inter = atoi (argv[0]); + ospf->distance_external = atoi (argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_inter_intra_external, + ospf_distance_ospf_inter_intra_external_cmd, + "distance ospf inter-area <1-255> intra-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_inter = atoi (argv[0]); + ospf->distance_intra = atoi (argv[1]); + ospf->distance_external = atoi (argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_inter_external_intra, + ospf_distance_ospf_inter_external_intra_cmd, + "distance ospf inter-area <1-255> external <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_inter = atoi (argv[0]); + ospf->distance_external = atoi (argv[1]); + ospf->distance_intra = atoi (argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_external, + ospf_distance_ospf_external_cmd, + "distance ospf external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_external = atoi (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_external_intra, + ospf_distance_ospf_external_intra_cmd, + "distance ospf external <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_external = atoi (argv[0]); + ospf->distance_intra = atoi (argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_external_inter, + ospf_distance_ospf_external_inter_cmd, + "distance ospf external <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_external = atoi (argv[0]); + ospf->distance_inter = atoi (argv[1]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_external_intra_inter, + ospf_distance_ospf_external_intra_inter_cmd, + "distance ospf external <1-255> intra-area <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_external = atoi (argv[0]); + ospf->distance_intra = atoi (argv[1]); + ospf->distance_inter = atoi (argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_ospf_external_inter_intra, + ospf_distance_ospf_external_inter_intra_cmd, + "distance ospf external <1-255> inter-area <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") +{ + struct ospf *ospf = vty->index; + + ospf->distance_external = atoi (argv[0]); + ospf->distance_inter = atoi (argv[1]); + ospf->distance_intra = atoi (argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_source, + ospf_distance_source_cmd, + "distance <1-255> A.B.C.D/M", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") +{ + struct ospf *ospf = vty->index; + + ospf_distance_set (vty, ospf, argv[0], argv[1], NULL); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_distance_source, + no_ospf_distance_source_cmd, + "no distance <1-255> A.B.C.D/M", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") +{ + struct ospf *ospf = vty->index; + + ospf_distance_unset (vty, ospf, argv[0], argv[1], NULL); + + return CMD_SUCCESS; +} + +DEFUN (ospf_distance_source_access_list, + ospf_distance_source_access_list_cmd, + "distance <1-255> A.B.C.D/M WORD", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + struct ospf *ospf = vty->index; + + ospf_distance_set (vty, ospf, argv[0], argv[1], argv[2]); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf_distance_source_access_list, + no_ospf_distance_source_access_list_cmd, + "no distance <1-255> A.B.C.D/M WORD", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + struct ospf *ospf = vty->index; + + ospf_distance_unset (vty, ospf, argv[0], argv[1], argv[2]); + + return CMD_SUCCESS; +} + +void +show_ip_ospf_route_network (struct vty *vty, struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *or; + listnode pnode; + struct ospf_path *path; + + vty_out (vty, "============ OSPF network routing table ============%s", + VTY_NEWLINE); + + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((or = rn->info) != NULL) + { + char buf1[19]; + snprintf (buf1, 19, "%s/%d", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); + + switch (or->path_type) + { + case OSPF_PATH_INTER_AREA: + if (or->type == OSPF_DESTINATION_NETWORK) + vty_out (vty, "N IA %-18s [%d] area: %s%s", buf1, or->cost, + inet_ntoa (or->u.std.area_id), VTY_NEWLINE); + else if (or->type == OSPF_DESTINATION_DISCARD) + vty_out (vty, "D IA %-18s Discard entry%s", buf1, VTY_NEWLINE); + break; + case OSPF_PATH_INTRA_AREA: + vty_out (vty, "N %-18s [%d] area: %s%s", buf1, or->cost, + inet_ntoa (or->u.std.area_id), VTY_NEWLINE); + break; + default: + break; + } + + if (or->type == OSPF_DESTINATION_NETWORK) + for (pnode = listhead (or->path); pnode; nextnode (pnode)) + { + path = getdata (pnode); + if (path->oi != NULL) + { + if (path->nexthop.s_addr == 0) + vty_out (vty, "%24s directly attached to %s%s", + "", path->oi->ifp->name, VTY_NEWLINE); + else + vty_out (vty, "%24s via %s, %s%s", "", + inet_ntoa (path->nexthop), path->oi->ifp->name, + VTY_NEWLINE); + } + } + } + vty_out (vty, "%s", VTY_NEWLINE); +} + +void +show_ip_ospf_route_router (struct vty *vty, struct route_table *rtrs) +{ + struct route_node *rn; + struct ospf_route *or; + listnode pn, nn; + struct ospf_path *path; + + vty_out (vty, "============ OSPF router routing table =============%s", + VTY_NEWLINE); + for (rn = route_top (rtrs); rn; rn = route_next (rn)) + if (rn->info) + { + int flag = 0; + + vty_out (vty, "R %-15s ", inet_ntoa (rn->p.u.prefix4)); + + for (nn = listhead ((list) rn->info); nn; nextnode (nn)) + if ((or = getdata (nn)) != NULL) + { + if (flag++) + vty_out(vty," " ); + + /* Show path. */ + vty_out (vty, "%s [%d] area: %s", + (or->path_type == OSPF_PATH_INTER_AREA ? "IA" : " "), + or->cost, inet_ntoa (or->u.std.area_id)); + /* Show flags. */ + vty_out (vty, "%s%s%s", + (or->u.std.flags & ROUTER_LSA_BORDER ? ", ABR" : ""), + (or->u.std.flags & ROUTER_LSA_EXTERNAL ? ", ASBR" : ""), + VTY_NEWLINE); + + for (pn = listhead (or->path); pn; nextnode (pn)) + { + path = getdata (pn); + if (path->nexthop.s_addr == 0) + vty_out (vty, "%24s directly attached to %s%s", + "", path->oi->ifp->name, VTY_NEWLINE); + else + vty_out (vty, "%24s via %s, %s%s", "", + inet_ntoa (path->nexthop), path->oi->ifp->name, + VTY_NEWLINE); + } + } + } + vty_out (vty, "%s", VTY_NEWLINE); +} + +void +show_ip_ospf_route_external (struct vty *vty, struct route_table *rt) +{ + struct route_node *rn; + struct ospf_route *er; + listnode pnode; + struct ospf_path *path; + + vty_out (vty, "============ OSPF external routing table ===========%s", + VTY_NEWLINE); + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((er = rn->info) != NULL) + { + char buf1[19]; + snprintf (buf1, 19, "%s/%d", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); + + switch (er->path_type) + { + case OSPF_PATH_TYPE1_EXTERNAL: + vty_out (vty, "N E1 %-18s [%d] tag: %u%s", buf1, + er->cost, er->u.ext.tag, VTY_NEWLINE); + break; + case OSPF_PATH_TYPE2_EXTERNAL: + vty_out (vty, "N E2 %-18s [%d/%d] tag: %u%s", buf1, er->cost, + er->u.ext.type2_cost, er->u.ext.tag, VTY_NEWLINE); + break; + } + + for (pnode = listhead (er->path); pnode; nextnode (pnode)) + { + path = getdata (pnode); + if (path->oi != NULL) + { + if (path->nexthop.s_addr == 0) + vty_out (vty, "%24s directly attached to %s%s", + "", path->oi->ifp->name, VTY_NEWLINE); + else + vty_out (vty, "%24s via %s, %s%s", "", + inet_ntoa (path->nexthop), path->oi->ifp->name, + VTY_NEWLINE); + } + } + } + vty_out (vty, "%s", VTY_NEWLINE); +} + +#ifdef HAVE_NSSA +DEFUN (show_ip_ospf_border_routers, + show_ip_ospf_border_routers_cmd, + "show ip ospf border-routers", + SHOW_STR + IP_STR + "show all the ABR's and ASBR's\n" + "for this area\n") +{ + struct ospf *ospf; + + ospf = ospf_lookup (); + if (ospf == NULL) + { + vty_out (vty, "OSPF is not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + if (ospf->new_table == NULL) + { + vty_out (vty, "No OSPF routing information exist%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* Show Network routes. + show_ip_ospf_route_network (vty, ospf->new_table); */ + + /* Show Router routes. */ + show_ip_ospf_route_router (vty, ospf->new_rtrs); + + return CMD_SUCCESS; +} +#endif /* HAVE_NSSA */ + +DEFUN (show_ip_ospf_route, + show_ip_ospf_route_cmd, + "show ip ospf route", + SHOW_STR + IP_STR + "OSPF information\n" + "OSPF routing table\n") +{ + struct ospf *ospf; + + ospf = ospf_lookup (); + if (ospf == NULL) + { + vty_out (vty, "OSPF is not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + if (ospf->new_table == NULL) + { + vty_out (vty, "No OSPF routing information exist%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* Show Network routes. */ + show_ip_ospf_route_network (vty, ospf->new_table); + + /* Show Router routes. */ + show_ip_ospf_route_router (vty, ospf->new_rtrs); + + /* Show AS External routes. */ + show_ip_ospf_route_external (vty, ospf->old_external_route); + + return CMD_SUCCESS; +} + + +char *ospf_abr_type_str[] = + { + "unknown", + "standard", + "ibm", + "cisco", + "shortcut" + }; + +char *ospf_shortcut_mode_str[] = + { + "default", + "enable", + "disable" + }; + + +void +area_id2str (char *buf, int length, struct ospf_area *area) +{ + memset (buf, 0, length); + + if (area->format == OSPF_AREA_ID_FORMAT_ADDRESS) + strncpy (buf, inet_ntoa (area->area_id), length); + else + sprintf (buf, "%lu", (unsigned long) ntohl (area->area_id.s_addr)); +} + + +char *ospf_int_type_str[] = + { + "unknown", /* should never be used. */ + "point-to-point", + "broadcast", + "non-broadcast", + "point-to-multipoint", + "virtual-link", /* should never be used. */ + "loopback" + }; + +/* Configuration write function for ospfd. */ +int +config_write_interface (struct vty *vty) +{ + listnode n1, n2; + struct interface *ifp; + struct crypt_key *ck; + int write = 0; + struct route_node *rn = NULL; + struct ospf_if_params *params; + + for (n1 = listhead (iflist); n1; nextnode (n1)) + { + ifp = getdata (n1); + + if (memcmp (ifp->name, "VLINK", 5) == 0) + continue; + + vty_out (vty, "!%s", VTY_NEWLINE); + vty_out (vty, "interface %s%s", ifp->name, + VTY_NEWLINE); + if (ifp->desc) + vty_out (vty, " description %s%s", ifp->desc, + VTY_NEWLINE); + + write++; + + params = IF_DEF_PARAMS (ifp); + + do { + /* Interface Network print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, type) && + params->type != OSPF_IFTYPE_BROADCAST && + params->type != OSPF_IFTYPE_LOOPBACK) + { + vty_out (vty, " ip ospf network %s", + ospf_int_type_str[params->type]); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* OSPF interface authentication print */ + if (OSPF_IF_PARAM_CONFIGURED (params, auth_type) && + params->auth_type != OSPF_AUTH_NOTSET) + { + char *auth_str; + + /* Translation tables are not that much help here due to syntax + of the simple option */ + switch (params->auth_type) + { + + case OSPF_AUTH_NULL: + auth_str = " null"; + break; + + case OSPF_AUTH_SIMPLE: + auth_str = ""; + break; + + case OSPF_AUTH_CRYPTOGRAPHIC: + auth_str = " message-digest"; + break; + + default: + auth_str = ""; + break; + } + + vty_out (vty, " ip ospf authentication%s", auth_str); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Simple Authentication Password print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, auth_simple) && + params->auth_simple[0] != '\0') + { + vty_out (vty, " ip ospf authentication-key %s", + params->auth_simple); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Cryptographic Authentication Key print. */ + for (n2 = listhead (params->auth_crypt); n2; nextnode (n2)) + { + ck = getdata (n2); + vty_out (vty, " ip ospf message-digest-key %d md5 %s", + ck->key_id, ck->auth_key); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Interface Output Cost print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, output_cost_cmd)) + { + vty_out (vty, " ip ospf cost %u", params->output_cost_cmd); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Hello Interval print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, v_hello) && + params->v_hello != OSPF_HELLO_INTERVAL_DEFAULT) + { + vty_out (vty, " ip ospf hello-interval %u", params->v_hello); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + + /* Router Dead Interval print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, v_wait) && + params->v_wait != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT) + { + vty_out (vty, " ip ospf dead-interval %u", params->v_wait); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Router Priority print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, priority) && + params->priority != OSPF_ROUTER_PRIORITY_DEFAULT) + { + vty_out (vty, " ip ospf priority %u", params->priority); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Retransmit Interval print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, retransmit_interval) && + params->retransmit_interval != OSPF_RETRANSMIT_INTERVAL_DEFAULT) + { + vty_out (vty, " ip ospf retransmit-interval %u", + params->retransmit_interval); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + /* Transmit Delay print. */ + if (OSPF_IF_PARAM_CONFIGURED (params, transmit_delay) && + params->transmit_delay != OSPF_TRANSMIT_DELAY_DEFAULT) + { + vty_out (vty, " ip ospf transmit-delay %u", params->transmit_delay); + if (params != IF_DEF_PARAMS (ifp)) + vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + while (1) + { + if (rn == NULL) + rn = route_top (IF_OIFS_PARAMS (ifp)); + else + rn = route_next (rn); + + if (rn == NULL) + break; + params = rn->info; + if (params != NULL) + break; + } + } while (rn); + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_config_write_if (vty, ifp); +#endif /* HAVE_OPAQUE_LSA */ + } + + return write; +} + +int +config_write_network_area (struct vty *vty, struct ospf *ospf) +{ + struct route_node *rn; + u_char buf[INET_ADDRSTRLEN]; + + /* `network area' print. */ + for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) + if (rn->info) + { + struct ospf_network *n = rn->info; + + memset (buf, 0, INET_ADDRSTRLEN); + + /* Create Area ID string by specified Area ID format. */ + if (n->format == OSPF_AREA_ID_FORMAT_ADDRESS) + strncpy (buf, inet_ntoa (n->area_id), INET_ADDRSTRLEN); + else + sprintf (buf, "%lu", + (unsigned long int) ntohl (n->area_id.s_addr)); + + /* Network print. */ + vty_out (vty, " network %s/%d area %s%s", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + buf, VTY_NEWLINE); + } + + return 0; +} + +int +config_write_ospf_area (struct vty *vty, struct ospf *ospf) +{ + listnode node; + u_char buf[INET_ADDRSTRLEN]; + + /* Area configuration print. */ + for (node = listhead (ospf->areas); node; nextnode (node)) + { + struct ospf_area *area = getdata (node); + struct route_node *rn1; + + area_id2str (buf, INET_ADDRSTRLEN, area); + + if (area->auth_type != OSPF_AUTH_NULL) + { + if (area->auth_type == OSPF_AUTH_SIMPLE) + vty_out (vty, " area %s authentication%s", buf, VTY_NEWLINE); + else + vty_out (vty, " area %s authentication message-digest%s", + buf, VTY_NEWLINE); + } + + if (area->shortcut_configured != OSPF_SHORTCUT_DEFAULT) + vty_out (vty, " area %s shortcut %s%s", buf, + ospf_shortcut_mode_str[area->shortcut_configured], + VTY_NEWLINE); + + if ((area->external_routing == OSPF_AREA_STUB) +#ifdef HAVE_NSSA + || (area->external_routing == OSPF_AREA_NSSA) +#endif /* HAVE_NSSA */ + ) + { +#ifdef HAVE_NSSA + if (area->external_routing == OSPF_AREA_NSSA) + vty_out (vty, " area %s nssa", buf); + else +#endif /* HAVE_NSSA */ + vty_out (vty, " area %s stub", buf); + + if (area->no_summary) + vty_out (vty, " no-summary"); + + vty_out (vty, "%s", VTY_NEWLINE); + + if (area->default_cost != 1) + vty_out (vty, " area %s default-cost %d%s", buf, + area->default_cost, VTY_NEWLINE); + } + + for (rn1 = route_top (area->ranges); rn1; rn1 = route_next (rn1)) + if (rn1->info) + { + struct ospf_area_range *range = rn1->info; + + vty_out (vty, " area %s range %s/%d", buf, + inet_ntoa (rn1->p.u.prefix4), rn1->p.prefixlen); + + if (range->cost_config != -1) + vty_out (vty, " cost %d", range->cost_config); + + if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) + vty_out (vty, " not-advertise"); + + if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) + vty_out (vty, " substitute %s/%d", + inet_ntoa (range->subst_addr), range->subst_masklen); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + if (EXPORT_NAME (area)) + vty_out (vty, " area %s export-list %s%s", buf, + EXPORT_NAME (area), VTY_NEWLINE); + + if (IMPORT_NAME (area)) + vty_out (vty, " area %s import-list %s%s", buf, + IMPORT_NAME (area), VTY_NEWLINE); + + if (PREFIX_NAME_IN (area)) + vty_out (vty, " area %s filter-list prefix %s in%s", buf, + PREFIX_NAME_IN (area), VTY_NEWLINE); + + if (PREFIX_NAME_OUT (area)) + vty_out (vty, " area %s filter-list prefix %s out%s", buf, + PREFIX_NAME_OUT (area), VTY_NEWLINE); + } + + return 0; +} + +int +config_write_ospf_nbr_nbma (struct vty *vty, struct ospf *ospf) +{ + struct ospf_nbr_nbma *nbr_nbma; + struct route_node *rn; + + /* Static Neighbor configuration print. */ + for (rn = route_top (ospf->nbr_nbma); rn; rn = route_next (rn)) + if ((nbr_nbma = rn->info)) + { + vty_out (vty, " neighbor %s", inet_ntoa (nbr_nbma->addr)); + + if (nbr_nbma->priority != OSPF_NEIGHBOR_PRIORITY_DEFAULT) + vty_out (vty, " priority %d", nbr_nbma->priority); + + if (nbr_nbma->v_poll != OSPF_POLL_INTERVAL_DEFAULT) + vty_out (vty, " poll-interval %d", nbr_nbma->v_poll); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + return 0; +} + +int +config_write_virtual_link (struct vty *vty, struct ospf *ospf) +{ + listnode node; + u_char buf[INET_ADDRSTRLEN]; + + /* Virtual-Link print */ + for (node = listhead (ospf->vlinks); node; nextnode (node)) + { + listnode n2; + struct crypt_key *ck; + struct ospf_vl_data *vl_data = getdata (node); + struct ospf_interface *oi; + + if (vl_data != NULL) + { + memset (buf, 0, INET_ADDRSTRLEN); + + if (vl_data->format == OSPF_AREA_ID_FORMAT_ADDRESS) + strncpy (buf, inet_ntoa (vl_data->vl_area_id), INET_ADDRSTRLEN); + else + sprintf (buf, "%lu", + (unsigned long int) ntohl (vl_data->vl_area_id.s_addr)); + oi = vl_data->vl_oi; + + /* timers */ + if (OSPF_IF_PARAM (oi, v_hello) != OSPF_HELLO_INTERVAL_DEFAULT || + OSPF_IF_PARAM (oi, v_wait) != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT || + OSPF_IF_PARAM (oi, retransmit_interval) != OSPF_RETRANSMIT_INTERVAL_DEFAULT || + OSPF_IF_PARAM (oi, transmit_delay) != OSPF_TRANSMIT_DELAY_DEFAULT) + vty_out (vty, " area %s virtual-link %s hello-interval %d retransmit-interval %d transmit-delay %d dead-interval %d%s", + buf, + inet_ntoa (vl_data->vl_peer), + OSPF_IF_PARAM (oi, v_hello), + OSPF_IF_PARAM (oi, retransmit_interval), + OSPF_IF_PARAM (oi, transmit_delay), + OSPF_IF_PARAM (oi, v_wait), + VTY_NEWLINE); + else + vty_out (vty, " area %s virtual-link %s%s", buf, + inet_ntoa (vl_data->vl_peer), VTY_NEWLINE); + /* Auth key */ + if (IF_DEF_PARAMS (vl_data->vl_oi->ifp)->auth_simple[0] != '\0') + vty_out (vty, " area %s virtual-link %s authentication-key %s%s", + buf, + inet_ntoa (vl_data->vl_peer), + IF_DEF_PARAMS (vl_data->vl_oi->ifp)->auth_simple, + VTY_NEWLINE); + /* md5 keys */ + for (n2 = listhead (IF_DEF_PARAMS (vl_data->vl_oi->ifp)->auth_crypt); n2; nextnode (n2)) + { + ck = getdata (n2); + vty_out (vty, " area %s virtual-link %s message-digest-key %d md5 %s%s", + buf, + inet_ntoa (vl_data->vl_peer), + ck->key_id, ck->auth_key, VTY_NEWLINE); + } + + } + } + + return 0; +} + + +char *distribute_str[] = { "system", "kernel", "connected", "static", "rip", + "ripng", "ospf", "ospf6", "bgp"}; +int +config_write_ospf_redistribute (struct vty *vty, struct ospf *ospf) +{ + int type; + + /* redistribute print. */ + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + if (type != zclient->redist_default && zclient->redist[type]) + { + vty_out (vty, " redistribute %s", distribute_str[type]); + if (ospf->dmetric[type].value >= 0) + vty_out (vty, " metric %d", ospf->dmetric[type].value); + + if (ospf->dmetric[type].type == EXTERNAL_METRIC_TYPE_1) + vty_out (vty, " metric-type 1"); + + if (ROUTEMAP_NAME (ospf, type)) + vty_out (vty, " route-map %s", ROUTEMAP_NAME (ospf, type)); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + return 0; +} + +int +config_write_ospf_default_metric (struct vty *vty, struct ospf *ospf) +{ + if (ospf->default_metric != -1) + vty_out (vty, " default-metric %d%s", ospf->default_metric, + VTY_NEWLINE); + return 0; +} + +int +config_write_ospf_distribute (struct vty *vty, struct ospf *ospf) +{ + int type; + + if (ospf) + { + /* distribute-list print. */ + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + if (ospf->dlist[type].name) + vty_out (vty, " distribute-list %s out %s%s", + ospf->dlist[type].name, + distribute_str[type], VTY_NEWLINE); + + /* default-information print. */ + if (ospf->default_originate != DEFAULT_ORIGINATE_NONE) + { + if (ospf->default_originate == DEFAULT_ORIGINATE_ZEBRA) + vty_out (vty, " default-information originate"); + else + vty_out (vty, " default-information originate always"); + + if (ospf->dmetric[DEFAULT_ROUTE].value >= 0) + vty_out (vty, " metric %d", + ospf->dmetric[DEFAULT_ROUTE].value); + if (ospf->dmetric[DEFAULT_ROUTE].type == EXTERNAL_METRIC_TYPE_1) + vty_out (vty, " metric-type 1"); + + if (ROUTEMAP_NAME (ospf, DEFAULT_ROUTE)) + vty_out (vty, " route-map %s", + ROUTEMAP_NAME (ospf, DEFAULT_ROUTE)); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + } + + return 0; +} + +int +config_write_ospf_distance (struct vty *vty, struct ospf *ospf) +{ + struct route_node *rn; + struct ospf_distance *odistance; + + if (ospf->distance_all) + vty_out (vty, " distance %d%s", ospf->distance_all, VTY_NEWLINE); + + if (ospf->distance_intra + || ospf->distance_inter + || ospf->distance_external) + { + vty_out (vty, " distance ospf"); + + if (ospf->distance_intra) + vty_out (vty, " intra-area %d", ospf->distance_intra); + if (ospf->distance_inter) + vty_out (vty, " inter-area %d", ospf->distance_inter); + if (ospf->distance_external) + vty_out (vty, " external %d", ospf->distance_external); + + vty_out (vty, "%s", VTY_NEWLINE); + } + + for (rn = route_top (ospf->distance_table); rn; rn = route_next (rn)) + if ((odistance = rn->info) != NULL) + { + vty_out (vty, " distance %d %s/%d %s%s", odistance->distance, + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + odistance->access_list ? odistance->access_list : "", + VTY_NEWLINE); + } + return 0; +} + +/* OSPF configuration write function. */ +int +ospf_config_write (struct vty *vty) +{ + struct ospf *ospf; + listnode node; + int write = 0; + + ospf = ospf_lookup (); + if (ospf != NULL) + { + /* `router ospf' print. */ + vty_out (vty, "router ospf%s", VTY_NEWLINE); + + write++; + + if (!ospf->networks) + return write; + + /* Router ID print. */ + if (ospf->router_id_static.s_addr != 0) + vty_out (vty, " ospf router-id %s%s", + inet_ntoa (ospf->router_id_static), VTY_NEWLINE); + + /* ABR type print. */ + if (ospf->abr_type != OSPF_ABR_STAND) + vty_out (vty, " ospf abr-type %s%s", + ospf_abr_type_str[ospf->abr_type], VTY_NEWLINE); + + /* RFC1583 compatibility flag print -- Compatible with CISCO 12.1. */ + if (CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) + vty_out (vty, " compatible rfc1583%s", VTY_NEWLINE); + + /* auto-cost reference-bandwidth configuration. */ + if (ospf->ref_bandwidth != OSPF_DEFAULT_REF_BANDWIDTH) + vty_out (vty, " auto-cost reference-bandwidth %d%s", + ospf->ref_bandwidth / 1000, VTY_NEWLINE); + + /* SPF timers print. */ + if (ospf->spf_delay != OSPF_SPF_DELAY_DEFAULT || + ospf->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT) + vty_out (vty, " timers spf %d %d%s", + ospf->spf_delay, ospf->spf_holdtime, VTY_NEWLINE); + + /* SPF refresh parameters print. */ + if (ospf->lsa_refresh_interval != OSPF_LSA_REFRESH_INTERVAL_DEFAULT) + vty_out (vty, " refresh timer %d%s", + ospf->lsa_refresh_interval, VTY_NEWLINE); + + /* Redistribute information print. */ + config_write_ospf_redistribute (vty, ospf); + + /* passive-interface print. */ + for (node = listhead (om->iflist); node; nextnode (node)) + { + struct interface *ifp = getdata (node); + + if (!ifp) + continue; + if (IF_DEF_PARAMS (ifp)->passive_interface == OSPF_IF_PASSIVE) + vty_out (vty, " passive-interface %s%s", + ifp->name, VTY_NEWLINE); + } + + for (node = listhead (ospf->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + + if (OSPF_IF_PARAM_CONFIGURED (oi->params, passive_interface) && + oi->params->passive_interface == OSPF_IF_PASSIVE) + vty_out (vty, " passive-interface %s%s", + inet_ntoa (oi->address->u.prefix4), VTY_NEWLINE); + } + + + /* Network area print. */ + config_write_network_area (vty, ospf); + + /* Area config print. */ + config_write_ospf_area (vty, ospf); + + /* static neighbor print. */ + config_write_ospf_nbr_nbma (vty, ospf); + + /* Virtual-Link print. */ + config_write_virtual_link (vty, ospf); + + /* Default metric configuration. */ + config_write_ospf_default_metric (vty, ospf); + + /* Distribute-list and default-information print. */ + config_write_ospf_distribute (vty, ospf); + + /* Distance configuration. */ + config_write_ospf_distance (vty, ospf); + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_config_write_router (vty, ospf); +#endif /* HAVE_OPAQUE_LSA */ + } + + return write; +} + +void +ospf_vty_show_init () +{ + /* "show ip ospf" commands. */ + install_element (VIEW_NODE, &show_ip_ospf_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_cmd); + + /* "show ip ospf database" commands. */ + install_element (VIEW_NODE, &show_ip_ospf_database_type_cmd); + install_element (VIEW_NODE, &show_ip_ospf_database_type_id_cmd); + install_element (VIEW_NODE, &show_ip_ospf_database_type_id_adv_router_cmd); + install_element (VIEW_NODE, &show_ip_ospf_database_type_adv_router_cmd); + install_element (VIEW_NODE, &show_ip_ospf_database_type_id_self_cmd); + install_element (VIEW_NODE, &show_ip_ospf_database_type_self_cmd); + install_element (VIEW_NODE, &show_ip_ospf_database_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_adv_router_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_adv_router_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_self_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_self_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_database_cmd); + + /* "show ip ospf interface" commands. */ + install_element (VIEW_NODE, &show_ip_ospf_interface_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_interface_cmd); + + /* "show ip ospf neighbor" commands. */ + install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_detail_cmd); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_cmd); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_id_cmd); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_all_cmd); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_cmd); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_cmd); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_all_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_detail_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_id_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_all_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_all_cmd); + + /* "show ip ospf route" commands. */ + install_element (VIEW_NODE, &show_ip_ospf_route_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_route_cmd); +#ifdef HAVE_NSSA + install_element (VIEW_NODE, &show_ip_ospf_border_routers_cmd); + install_element (ENABLE_NODE, &show_ip_ospf_border_routers_cmd); +#endif /* HAVE_NSSA */ +} + + +/* ospfd's interface node. */ +struct cmd_node interface_node = + { + INTERFACE_NODE, + "%s(config-if)# ", + 1 + }; + +/* Initialization of OSPF interface. */ +void +ospf_vty_if_init () +{ + /* Install interface node. */ + install_node (&interface_node, config_write_interface); + + install_element (CONFIG_NODE, &interface_cmd); + install_default (INTERFACE_NODE); + + /* "description" commands. */ + install_element (INTERFACE_NODE, &interface_desc_cmd); + install_element (INTERFACE_NODE, &no_interface_desc_cmd); + + /* "ip ospf authentication" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_authentication_args_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_authentication_args_cmd); + install_element (INTERFACE_NODE, &ip_ospf_authentication_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_authentication_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_authentication_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_authentication_cmd); + install_element (INTERFACE_NODE, &ip_ospf_authentication_key_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_authentication_key_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_cmd); + + /* "ip ospf message-digest-key" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_cmd); + + /* "ip ospf cost" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_cost_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_cost_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_cost_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_cost_cmd); + + /* "ip ospf dead-interval" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_dead_interval_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_dead_interval_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_cmd); + + /* "ip ospf hello-interval" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_hello_interval_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_hello_interval_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd); + + /* "ip ospf network" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_network_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_network_cmd); + + /* "ip ospf priority" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_priority_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_priority_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_priority_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_priority_cmd); + + /* "ip ospf retransmit-interval" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_cmd); + + /* "ip ospf transmit-delay" commands. */ + install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd); + install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd); + install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd); + + /* These commands are compatibitliy for previous version. */ + install_element (INTERFACE_NODE, &ospf_authentication_key_cmd); + install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd); + install_element (INTERFACE_NODE, &ospf_message_digest_key_cmd); + install_element (INTERFACE_NODE, &no_ospf_message_digest_key_cmd); + install_element (INTERFACE_NODE, &ospf_cost_cmd); + install_element (INTERFACE_NODE, &no_ospf_cost_cmd); + install_element (INTERFACE_NODE, &ospf_dead_interval_cmd); + install_element (INTERFACE_NODE, &no_ospf_dead_interval_cmd); + install_element (INTERFACE_NODE, &ospf_hello_interval_cmd); + install_element (INTERFACE_NODE, &no_ospf_hello_interval_cmd); + install_element (INTERFACE_NODE, &ospf_network_cmd); + install_element (INTERFACE_NODE, &no_ospf_network_cmd); + install_element (INTERFACE_NODE, &ospf_priority_cmd); + install_element (INTERFACE_NODE, &no_ospf_priority_cmd); + install_element (INTERFACE_NODE, &ospf_retransmit_interval_cmd); + install_element (INTERFACE_NODE, &no_ospf_retransmit_interval_cmd); + install_element (INTERFACE_NODE, &ospf_transmit_delay_cmd); + install_element (INTERFACE_NODE, &no_ospf_transmit_delay_cmd); +} + +/* Zebra node structure. */ +struct cmd_node zebra_node = + { + ZEBRA_NODE, + "%s(config-router)#", + }; + +void +ospf_vty_zebra_init () +{ + install_element (OSPF_NODE, &ospf_redistribute_source_type_metric_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_metric_type_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_type_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_metric_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_cmd); + install_element (OSPF_NODE, + &ospf_redistribute_source_metric_type_routemap_cmd); + install_element (OSPF_NODE, + &ospf_redistribute_source_type_metric_routemap_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_metric_routemap_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_type_routemap_cmd); + install_element (OSPF_NODE, &ospf_redistribute_source_routemap_cmd); + + install_element (OSPF_NODE, &no_ospf_redistribute_source_cmd); + + install_element (OSPF_NODE, &ospf_distribute_list_out_cmd); + install_element (OSPF_NODE, &no_ospf_distribute_list_out_cmd); + + install_element (OSPF_NODE, + &ospf_default_information_originate_metric_type_cmd); + install_element (OSPF_NODE, &ospf_default_information_originate_metric_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_type_metric_cmd); + install_element (OSPF_NODE, &ospf_default_information_originate_type_cmd); + install_element (OSPF_NODE, &ospf_default_information_originate_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_metric_type_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_metric_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_type_metric_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_type_cmd); + + install_element (OSPF_NODE, + &ospf_default_information_originate_metric_type_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_metric_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_type_metric_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_type_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_metric_type_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_metric_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_type_metric_routemap_cmd); + install_element (OSPF_NODE, + &ospf_default_information_originate_always_type_routemap_cmd); + + install_element (OSPF_NODE, &no_ospf_default_information_originate_cmd); + + install_element (OSPF_NODE, &ospf_default_metric_cmd); + install_element (OSPF_NODE, &no_ospf_default_metric_cmd); + install_element (OSPF_NODE, &no_ospf_default_metric_val_cmd); + + install_element (OSPF_NODE, &ospf_distance_cmd); + install_element (OSPF_NODE, &no_ospf_distance_cmd); + install_element (OSPF_NODE, &no_ospf_distance_ospf_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_external_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_inter_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_external_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_intra_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_external_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_inter_cmd); + install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_intra_cmd); + install_element (OSPF_NODE, &ospf_distance_source_cmd); + install_element (OSPF_NODE, &no_ospf_distance_source_cmd); + install_element (OSPF_NODE, &ospf_distance_source_access_list_cmd); + install_element (OSPF_NODE, &no_ospf_distance_source_access_list_cmd); +} + +struct cmd_node ospf_node = + { + OSPF_NODE, + "%s(config-router)# ", + 1 + }; + + +/* Install OSPF related vty commands. */ +void +ospf_vty_init () +{ + /* Install ospf top node. */ + install_node (&ospf_node, ospf_config_write); + + /* "router ospf" commands. */ + install_element (CONFIG_NODE, &router_ospf_cmd); + install_element (CONFIG_NODE, &no_router_ospf_cmd); + + install_default (OSPF_NODE); + + /* "ospf router-id" commands. */ + install_element (OSPF_NODE, &ospf_router_id_cmd); + install_element (OSPF_NODE, &no_ospf_router_id_cmd); + install_element (OSPF_NODE, &router_ospf_id_cmd); + install_element (OSPF_NODE, &no_router_ospf_id_cmd); + + /* "passive-interface" commands. */ + install_element (OSPF_NODE, &ospf_passive_interface_addr_cmd); + install_element (OSPF_NODE, &ospf_passive_interface_cmd); + install_element (OSPF_NODE, &no_ospf_passive_interface_addr_cmd); + install_element (OSPF_NODE, &no_ospf_passive_interface_cmd); + + /* "ospf abr-type" commands. */ + install_element (OSPF_NODE, &ospf_abr_type_cmd); + install_element (OSPF_NODE, &no_ospf_abr_type_cmd); + + /* "ospf rfc1583-compatible" commands. */ + install_element (OSPF_NODE, &ospf_rfc1583_flag_cmd); + install_element (OSPF_NODE, &no_ospf_rfc1583_flag_cmd); + install_element (OSPF_NODE, &ospf_compatible_rfc1583_cmd); + install_element (OSPF_NODE, &no_ospf_compatible_rfc1583_cmd); + + /* "network area" commands. */ + install_element (OSPF_NODE, &ospf_network_area_cmd); + install_element (OSPF_NODE, &no_ospf_network_area_cmd); + + /* "area authentication" commands. */ + install_element (OSPF_NODE, &ospf_area_authentication_message_digest_cmd); + install_element (OSPF_NODE, &ospf_area_authentication_cmd); + install_element (OSPF_NODE, &no_ospf_area_authentication_cmd); + + /* "area range" commands. */ + install_element (OSPF_NODE, &ospf_area_range_cmd); + install_element (OSPF_NODE, &ospf_area_range_advertise_cmd); + install_element (OSPF_NODE, &ospf_area_range_cost_cmd); + install_element (OSPF_NODE, &ospf_area_range_advertise_cost_cmd); + install_element (OSPF_NODE, &ospf_area_range_not_advertise_cmd); + install_element (OSPF_NODE, &no_ospf_area_range_cmd); + install_element (OSPF_NODE, &no_ospf_area_range_advertise_cmd); + install_element (OSPF_NODE, &no_ospf_area_range_cost_cmd); + install_element (OSPF_NODE, &no_ospf_area_range_advertise_cost_cmd); + install_element (OSPF_NODE, &ospf_area_range_substitute_cmd); + install_element (OSPF_NODE, &no_ospf_area_range_substitute_cmd); + + /* "area virtual-link" commands. */ + install_element (OSPF_NODE, &ospf_area_vlink_cmd); + install_element (OSPF_NODE, &no_ospf_area_vlink_cmd); + + install_element (OSPF_NODE, &ospf_area_vlink_param1_cmd); + install_element (OSPF_NODE, &no_ospf_area_vlink_param1_cmd); + + install_element (OSPF_NODE, &ospf_area_vlink_param2_cmd); + install_element (OSPF_NODE, &no_ospf_area_vlink_param2_cmd); + + install_element (OSPF_NODE, &ospf_area_vlink_param3_cmd); + install_element (OSPF_NODE, &no_ospf_area_vlink_param3_cmd); + + install_element (OSPF_NODE, &ospf_area_vlink_param4_cmd); + install_element (OSPF_NODE, &no_ospf_area_vlink_param4_cmd); + + install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_cmd); + install_element (OSPF_NODE, &ospf_area_vlink_authtype_cmd); + install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_cmd); + + install_element (OSPF_NODE, &ospf_area_vlink_md5_cmd); + install_element (OSPF_NODE, &no_ospf_area_vlink_md5_cmd); + + install_element (OSPF_NODE, &ospf_area_vlink_authkey_cmd); + install_element (OSPF_NODE, &no_ospf_area_vlink_authkey_cmd); + + install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_authkey_cmd); + install_element (OSPF_NODE, &ospf_area_vlink_authtype_authkey_cmd); + install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_authkey_cmd); + + install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_md5_cmd); + install_element (OSPF_NODE, &ospf_area_vlink_authtype_md5_cmd); + install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_md5_cmd); + + /* "area stub" commands. */ + install_element (OSPF_NODE, &ospf_area_stub_no_summary_cmd); + install_element (OSPF_NODE, &ospf_area_stub_cmd); + install_element (OSPF_NODE, &no_ospf_area_stub_no_summary_cmd); + install_element (OSPF_NODE, &no_ospf_area_stub_cmd); + +#ifdef HAVE_NSSA + /* "area nssa" commands. */ + install_element (OSPF_NODE, &ospf_area_nssa_cmd); + install_element (OSPF_NODE, &ospf_area_nssa_translate_no_summary_cmd); + install_element (OSPF_NODE, &ospf_area_nssa_translate_cmd); + install_element (OSPF_NODE, &ospf_area_nssa_no_summary_cmd); + install_element (OSPF_NODE, &no_ospf_area_nssa_cmd); + install_element (OSPF_NODE, &no_ospf_area_nssa_no_summary_cmd); +#endif /* HAVE_NSSA */ + + install_element (OSPF_NODE, &ospf_area_default_cost_cmd); + install_element (OSPF_NODE, &no_ospf_area_default_cost_cmd); + + install_element (OSPF_NODE, &ospf_area_shortcut_cmd); + install_element (OSPF_NODE, &no_ospf_area_shortcut_cmd); + + install_element (OSPF_NODE, &ospf_area_export_list_cmd); + install_element (OSPF_NODE, &no_ospf_area_export_list_cmd); + + install_element (OSPF_NODE, &ospf_area_filter_list_cmd); + install_element (OSPF_NODE, &no_ospf_area_filter_list_cmd); + + install_element (OSPF_NODE, &ospf_area_import_list_cmd); + install_element (OSPF_NODE, &no_ospf_area_import_list_cmd); + + install_element (OSPF_NODE, &ospf_timers_spf_cmd); + install_element (OSPF_NODE, &no_ospf_timers_spf_cmd); + + install_element (OSPF_NODE, &ospf_refresh_timer_cmd); + install_element (OSPF_NODE, &no_ospf_refresh_timer_val_cmd); + install_element (OSPF_NODE, &no_ospf_refresh_timer_cmd); + + install_element (OSPF_NODE, &ospf_auto_cost_reference_bandwidth_cmd); + install_element (OSPF_NODE, &no_ospf_auto_cost_reference_bandwidth_cmd); + + /* "neighbor" commands. */ + install_element (OSPF_NODE, &ospf_neighbor_cmd); + install_element (OSPF_NODE, &ospf_neighbor_priority_poll_interval_cmd); + install_element (OSPF_NODE, &ospf_neighbor_priority_cmd); + install_element (OSPF_NODE, &ospf_neighbor_poll_interval_cmd); + install_element (OSPF_NODE, &ospf_neighbor_poll_interval_priority_cmd); + install_element (OSPF_NODE, &no_ospf_neighbor_cmd); + install_element (OSPF_NODE, &no_ospf_neighbor_priority_cmd); + install_element (OSPF_NODE, &no_ospf_neighbor_poll_interval_cmd); + + /* Init interface related vty commands. */ + ospf_vty_if_init (); + + /* Init zebra related vty commands. */ + ospf_vty_zebra_init (); +} diff --git a/ospfd/ospf_vty.h b/ospfd/ospf_vty.h new file mode 100644 index 0000000..9f30e20 --- /dev/null +++ b/ospfd/ospf_vty.h @@ -0,0 +1,85 @@ +/* OSPF VTY interface. + * Copyright (C) 2000 Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* Macros. */ +#define VTY_GET_UINT32(NAME,V,STR) \ +{ \ + char *endptr = NULL; \ + (V) = strtoul ((STR), &endptr, 10); \ + if (*endptr != '\0' || ((V) == ULONG_MAX && errno == ERANGE)) \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_IPV4_ADDRESS(NAME,V,STR) \ +{ \ + int retv; \ + retv = inet_aton ((STR), &(V)); \ + if (!retv) \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_IPV4_PREFIX(NAME,V,STR) \ +{ \ + int retv; \ + retv = str2prefix_ipv4 ((STR), &(V)); \ + if (retv <= 0) \ + { \ + vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_OSPF_AREA_ID(V,F,STR) \ +{ \ + int retv; \ + retv = ospf_str2area_id ((STR), &(V), &(F)); \ + if (retv < 0) \ + { \ + vty_out (vty, "%% Invalid OSPF area ID%s", VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ +} + +#define VTY_GET_OSPF_AREA_ID_NO_BB(NAME,V,F,STR) \ +{ \ + int retv; \ + retv = ospf_str2area_id ((STR), &(V), &(F)); \ + if (retv < 0) \ + { \ + vty_out (vty, "%% Invalid OSPF area ID%s", VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ + if (OSPF_IS_AREA_ID_BACKBONE ((V))) \ + { \ + vty_out (vty, "%% You can't configure %s to backbone%s", \ + NAME, VTY_NEWLINE); \ + } \ +} + +/* Prototypes. */ +void ospf_vty_init (); +void ospf_vty_show_init (); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c new file mode 100644 index 0000000..26f3d71 --- /dev/null +++ b/ospfd/ospf_zebra.c @@ -0,0 +1,1138 @@ +/* + * Zebra connect library for OSPFd + * Copyright (C) 1997, 98, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "thread.h" +#include "command.h" +#include "network.h" +#include "prefix.h" +#include "routemap.h" +#include "table.h" +#include "stream.h" +#include "memory.h" +#include "zclient.h" +#include "filter.h" +#include "log.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" +#ifdef HAVE_SNMP +#include "ospfd/ospf_snmp.h" +#endif /* HAVE_SNMP */ + +/* Zebra structure to hold current status. */ +struct zclient *zclient = NULL; + +/* For registering threads. */ +extern struct thread_master *master; + +/* Inteface addition message from zebra. */ +int +ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + struct ospf *ospf; + + ifp = zebra_interface_add_read (zclient->ibuf); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: interface add %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + if (!OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), type)) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), type); + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST; + + if (if_is_broadcast (ifp)) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST; + else if (if_is_pointopoint (ifp)) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOPOINT; + else if (if_is_loopback (ifp)) + IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_LOOPBACK; + } + + ospf = ospf_lookup (); + if (ospf != NULL) + ospf_if_update (ospf); + +#ifdef HAVE_SNMP + ospf_snmp_if_update (ifp); +#endif /* HAVE_SNMP */ + + return 0; +} + +int +ospf_interface_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + struct stream *s; + struct route_node *rn; + + s = zclient->ibuf; + /* zebra_interface_state_read() updates interface structure in iflist */ + ifp = zebra_interface_state_read (s); + + if (ifp == NULL) + return 0; + + if (if_is_up (ifp)) + zlog_warn ("Zebra: got delete of %s, but interface is still up", + ifp->name); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: interface delete %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + +#ifdef HAVE_SNMP + ospf_snmp_if_delete (ifp); +#endif /* HAVE_SNMP */ + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + if (rn->info) + ospf_if_free ((struct ospf_interface *) rn->info); + + for (rn = route_top (IF_OIFS_PARAMS (ifp)); rn; rn = route_next (rn)) + if (rn->info) + ospf_del_if_params (rn->info); + + if_delete (ifp); + + return 0; +} + +struct interface * +zebra_interface_if_lookup (struct stream *s) +{ + struct interface *ifp; + u_char ifname_tmp[INTERFACE_NAMSIZ]; + + /* Read interface name. */ + stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); + + /* Lookup this by interface index. */ + ifp = if_lookup_by_name (ifname_tmp); + + /* If such interface does not exist, indicate an error */ + if (!ifp) + return NULL; + + return ifp; +} + +void +zebra_interface_if_set_value (struct stream *s, struct interface *ifp) +{ + /* Read interface's index. */ + ifp->ifindex = stream_getl (s); + + /* Read interface's value. */ + ifp->flags = stream_getl (s); + ifp->metric = stream_getl (s); + ifp->mtu = stream_getl (s); + ifp->bandwidth = stream_getl (s); +} + +int +ospf_interface_state_up (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + struct interface if_tmp; + struct ospf_interface *oi; + struct route_node *rn; + + ifp = zebra_interface_if_lookup (zclient->ibuf); + + if (ifp == NULL) + return 0; + + /* Interface is already up. */ + if (if_is_up (ifp)) + { + /* Temporarily keep ifp values. */ + memcpy (&if_tmp, ifp, sizeof (struct interface)); + + zebra_interface_if_set_value (zclient->ibuf, ifp); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: Interface[%s] state update.", ifp->name); + + if (if_tmp.bandwidth != ifp->bandwidth) + { + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: Interface[%s] bandwidth change %d -> %d.", + ifp->name, if_tmp.bandwidth, ifp->bandwidth); + + ospf_if_recalculate_output_cost (ifp); + } + return 0; + } + + zebra_interface_if_set_value (zclient->ibuf, ifp); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: Interface[%s] state change to up.", ifp->name); + + for (rn = route_top (IF_OIFS (ifp));rn; rn = route_next (rn)) + { + if ( (oi = rn->info) == NULL) + continue; + + ospf_if_up (oi); + } + + return 0; +} + +int +ospf_interface_state_down (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + struct ospf_interface *oi; + struct route_node *node; + + ifp = zebra_interface_state_read (zclient->ibuf); + + if (ifp == NULL) + return 0; + + if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + zlog_info ("Zebra: Interface[%s] state change to down.", ifp->name); + + for (node = route_top (IF_OIFS (ifp));node; node = route_next (node)) + { + if ( (oi = node->info) == NULL) + continue; + ospf_if_down (oi); + } + + return 0; +} + +int +ospf_interface_address_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct ospf *ospf; + struct connected *c; + + c = zebra_interface_address_add_read (zclient->ibuf); + + if (c == NULL) + return 0; + + ospf = ospf_lookup (); + if (ospf != NULL) + ospf_if_update (ospf); + +#ifdef HAVE_SNMP + ospf_snmp_if_update (c->ifp); +#endif /* HAVE_SNMP */ + + return 0; +} + +int +ospf_interface_address_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct ospf *ospf; + struct connected *c; + struct interface *ifp; + struct ospf_interface *oi; + struct route_node *rn; + struct prefix p; + + c = zebra_interface_address_delete_read (zclient->ibuf); + + if (c == NULL) + return 0; + + ifp = c->ifp; + p = *c->address; + p.prefixlen = IPV4_MAX_PREFIXLEN; + + rn = route_node_lookup (IF_OIFS (ifp), &p); + if (! rn) + return 0; + + assert (rn->info); + oi = rn->info; + + /* Call interface hook functions to clean up */ + ospf_if_free (oi); + +#ifdef HAVE_SNMP + ospf_snmp_if_update (c->ifp); +#endif /* HAVE_SNMP */ + + connected_free (c); + + ospf = ospf_lookup (); + if (ospf != NULL) + ospf_if_update (ospf); + + return 0; +} + +void +ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) +{ + u_char message; + u_char distance; + u_char flags; + int psize; + struct stream *s; + struct ospf_path *path; + listnode node; + + if (zclient->redist[ZEBRA_ROUTE_OSPF]) + { + message = 0; + flags = 0; + + /* OSPF pass nexthop and metric */ + SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP); + SET_FLAG (message, ZAPI_MESSAGE_METRIC); + + /* Distance value. */ + distance = ospf_distance_apply (p, or); + if (distance) + SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); + + /* Make packet. */ + s = zclient->obuf; + stream_reset (s); + + /* Length place holder. */ + stream_putw (s, 0); + + /* Put command, type, flags, message. */ + stream_putc (s, ZEBRA_IPV4_ROUTE_ADD); + stream_putc (s, ZEBRA_ROUTE_OSPF); + stream_putc (s, flags); + stream_putc (s, message); + + /* Put prefix information. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop count. */ + stream_putc (s, or->path->count); + + /* Nexthop, ifindex, distance and metric information. */ + for (node = listhead (or->path); node; nextnode (node)) + { + path = getdata (node); + + if (path->nexthop.s_addr != INADDR_ANY) + { + stream_putc (s, ZEBRA_NEXTHOP_IPV4); + stream_put_in_addr (s, &path->nexthop); + } + else + { + stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); + if (path->oi) + stream_putl (s, path->oi->ifp->ifindex); + else + stream_putl (s, 0); + } + } + + if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) + stream_putc (s, distance); + if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) + { + if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL) + stream_putl (s, or->cost + or->u.ext.type2_cost); + else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL) + stream_putl (s, or->u.ext.type2_cost); + else + stream_putl (s, or->cost); + } + + stream_putw_at (s, 0, stream_get_endp (s)); + + writen (zclient->sock, s->data, stream_get_endp (s)); + } +} + +void +ospf_zebra_delete (struct prefix_ipv4 *p, struct ospf_route *or) +{ + struct zapi_ipv4 api; + + if (zclient->redist[ZEBRA_ROUTE_OSPF]) + { + api.type = ZEBRA_ROUTE_OSPF; + api.flags = 0; + api.message = 0; + zapi_ipv4_delete (zclient, p, &api); + } +} + +void +ospf_zebra_add_discard (struct prefix_ipv4 *p) +{ + struct zapi_ipv4 api; + + if (zclient->redist[ZEBRA_ROUTE_OSPF]) + { + api.type = ZEBRA_ROUTE_OSPF; + api.flags = ZEBRA_FLAG_BLACKHOLE; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 0; + api.ifindex_num = 0; + + zapi_ipv4_add (zclient, p, &api); + } +} + +void +ospf_zebra_delete_discard (struct prefix_ipv4 *p) +{ + struct zapi_ipv4 api; + + if (zclient->redist[ZEBRA_ROUTE_OSPF]) + { + api.type = ZEBRA_ROUTE_OSPF; + api.flags = ZEBRA_FLAG_BLACKHOLE; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 0; + api.ifindex_num = 0; + + zapi_ipv4_delete (zclient, p, &api); + } +} + +int +ospf_is_type_redistributed (int type) +{ + return (DEFAULT_ROUTE_TYPE (type)) ? + zclient->default_information : zclient->redist[type]; +} + +int +ospf_redistribute_set (struct ospf *ospf, int type, int mtype, int mvalue) +{ + int force = 0; + + if (ospf_is_type_redistributed (type)) + { + if (mtype != ospf->dmetric[type].type) + { + ospf->dmetric[type].type = mtype; + force = LSA_REFRESH_FORCE; + } + if (mvalue != ospf->dmetric[type].value) + { + ospf->dmetric[type].value = mvalue; + force = LSA_REFRESH_FORCE; + } + + ospf_external_lsa_refresh_type (ospf, type, force); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: Refresh Type[%d], Metric[%d]", + LOOKUP (ospf_redistributed_proto, type), + metric_type (ospf, type), metric_value (ospf, type)); + + return CMD_SUCCESS; + } + + ospf->dmetric[type].type = mtype; + ospf->dmetric[type].value = mvalue; + + zclient_redistribute_set (zclient, type); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: Start Type[%d], Metric[%d]", + LOOKUP (ospf_redistributed_proto, type), + metric_type (ospf, type), metric_value (ospf, type)); + + ospf_asbr_status_update (ospf, ++ospf->redistribute); + + return CMD_SUCCESS; +} + +int +ospf_redistribute_unset (struct ospf *ospf, int type) +{ + if (type == zclient->redist_default) + return CMD_SUCCESS; + + if (! ospf_is_type_redistributed (type)) + return CMD_SUCCESS; + + zclient_redistribute_unset (zclient, type); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: Stop", + LOOKUP (ospf_redistributed_proto, type)); + + ospf->dmetric[type].type = -1; + ospf->dmetric[type].value = -1; + + /* Remove the routes from OSPF table. */ + ospf_redistribute_withdraw (type); + + ospf_asbr_status_update (ospf, --ospf->redistribute); + + return CMD_SUCCESS; +} + +int +ospf_redistribute_default_set (struct ospf *ospf, int originate, + int mtype, int mvalue) +{ + int force = 0; + + if (ospf_is_type_redistributed (DEFAULT_ROUTE)) + { + if (mtype != ospf->dmetric[DEFAULT_ROUTE].type) + { + ospf->dmetric[DEFAULT_ROUTE].type = mtype; + force = 1; + } + if (mvalue != ospf->dmetric[DEFAULT_ROUTE].value) + { + force = 1; + ospf->dmetric[DEFAULT_ROUTE].value = mvalue; + } + + ospf_external_lsa_refresh_default (ospf); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: Refresh Type[%d], Metric[%d]", + LOOKUP (ospf_redistributed_proto, DEFAULT_ROUTE), + metric_type (ospf, DEFAULT_ROUTE), + metric_value (ospf, DEFAULT_ROUTE)); + return CMD_SUCCESS; + } + + ospf->default_originate = originate; + ospf->dmetric[DEFAULT_ROUTE].type = mtype; + ospf->dmetric[DEFAULT_ROUTE].value = mvalue; + + zclient_redistribute_default_set (zclient); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[DEFAULT]: Start Type[%d], Metric[%d]", + metric_type (ospf, DEFAULT_ROUTE), + metric_value (ospf, DEFAULT_ROUTE)); + + if (ospf->router_id.s_addr == 0) + ospf->external_origin |= (1 << DEFAULT_ROUTE); + else + thread_add_timer (master, ospf_default_originate_timer, + &ospf->default_originate, 1); + + ospf_asbr_status_update (ospf, ++ospf->redistribute); + + return CMD_SUCCESS; +} + +int +ospf_redistribute_default_unset (struct ospf *ospf) +{ + if (!ospf_is_type_redistributed (DEFAULT_ROUTE)) + return CMD_SUCCESS; + + ospf->default_originate = DEFAULT_ORIGINATE_NONE; + ospf->dmetric[DEFAULT_ROUTE].type = -1; + ospf->dmetric[DEFAULT_ROUTE].value = -1; + + zclient_redistribute_default_unset (zclient); + + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[DEFAULT]: Stop"); + + ospf_asbr_status_update (ospf, --ospf->redistribute); + + return CMD_SUCCESS; +} + +int +ospf_external_lsa_originate_check (struct ospf *ospf, + struct external_info *ei) +{ + /* If prefix is multicast, then do not originate LSA. */ + if (IN_MULTICAST (htonl (ei->p.prefix.s_addr))) + { + zlog_info ("LSA[Type5:%s]: Not originate AS-external-LSA, " + "Prefix belongs multicast", inet_ntoa (ei->p.prefix)); + return 0; + } + + /* Take care of default-originate. */ + if (is_prefix_default (&ei->p)) + if (ospf->default_originate == DEFAULT_ORIGINATE_NONE) + { + zlog_info ("LSA[Type5:0.0.0.0]: Not originate AS-exntenal-LSA " + "for default"); + return 0; + } + + return 1; +} + +/* If connected prefix is OSPF enable interface, then do not announce. */ +int +ospf_distribute_check_connected (struct ospf *ospf, + struct external_info *ei) +{ + struct route_node *rn; + + for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) + if (rn->info != NULL) + if (prefix_match (&rn->p, (struct prefix *)&ei->p)) + { + route_unlock_node (rn); + return 0; + } + + return 1; +} + +/* return 1 if external LSA must be originated, 0 otherwise */ +int +ospf_redistribute_check (struct ospf *ospf, + struct external_info *ei, int *changed) +{ + struct route_map_set_values save_values; + struct prefix_ipv4 *p = &ei->p; + u_char type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type; + + if (changed) + *changed = 0; + + if (!ospf_external_lsa_originate_check (ospf, ei)) + return 0; + + /* Take care connected route. */ + if (type == ZEBRA_ROUTE_CONNECT && + !ospf_distribute_check_connected (ospf, ei)) + return 0; + + if (!DEFAULT_ROUTE_TYPE (type) && DISTRIBUTE_NAME (ospf, type)) + /* distirbute-list exists, but access-list may not? */ + if (DISTRIBUTE_LIST (ospf, type)) + if (access_list_apply (DISTRIBUTE_LIST (ospf, type), p) == FILTER_DENY) + { + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: %s/%d filtered by ditribute-list.", + LOOKUP (ospf_redistributed_proto, type), + inet_ntoa (p->prefix), p->prefixlen); + return 0; + } + + save_values = ei->route_map_set; + ospf_reset_route_map_set_values (&ei->route_map_set); + + /* apply route-map if needed */ + if (ROUTEMAP_NAME (ospf, type)) + { + int ret; + + ret = route_map_apply (ROUTEMAP (ospf, type), (struct prefix *)p, + RMAP_OSPF, ei); + + if (ret == RMAP_DENYMATCH) + { + ei->route_map_set = save_values; + if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + zlog_info ("Redistribute[%s]: %s/%d filtered by route-map.", + LOOKUP (ospf_redistributed_proto, type), + inet_ntoa (p->prefix), p->prefixlen); + return 0; + } + + /* check if 'route-map set' changed something */ + if (changed) + *changed = !ospf_route_map_set_compare (&ei->route_map_set, + &save_values); + } + + return 1; +} + +/* OSPF route-map set for redistribution */ +void +ospf_routemap_set (struct ospf *ospf, int type, char *name) +{ + if (ROUTEMAP_NAME (ospf, type)) + free (ROUTEMAP_NAME (ospf, type)); + + ROUTEMAP_NAME (ospf, type) = strdup (name); + ROUTEMAP (ospf, type) = route_map_lookup_by_name (name); +} + +void +ospf_routemap_unset (struct ospf *ospf, int type) +{ + if (ROUTEMAP_NAME (ospf, type)) + free (ROUTEMAP_NAME (ospf, type)); + + ROUTEMAP_NAME (ospf, type) = NULL; + ROUTEMAP (ospf, type) = NULL; +} + +/* Zebra route add and delete treatment. */ +int +ospf_zebra_read_ipv4 (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv4 api; + unsigned long ifindex; + struct in_addr nexthop; + struct prefix_ipv4 p; + struct external_info *ei; + struct ospf *ospf; + + s = zclient->ibuf; + ifindex = 0; + nexthop.s_addr = 0; + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv4 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + nexthop.s_addr = stream_get_ipv4 (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + + ospf = ospf_lookup (); + if (ospf == NULL) + return 0; + + if (command == ZEBRA_IPV4_ROUTE_ADD) + { + ei = ospf_external_info_add (api.type, p, ifindex, nexthop); + + if (ospf->router_id.s_addr == 0) + /* Set flags to generate AS-external-LSA originate event + for each redistributed protocols later. */ + ospf->external_origin |= (1 << api.type); + else + { + if (ei) + { + if (is_prefix_default (&p)) + ospf_external_lsa_refresh_default (ospf); + else + { + struct ospf_lsa *current; + + current = ospf_external_info_find_lsa (ospf, &ei->p); + if (!current) + ospf_external_lsa_originate (ospf, ei); + else if (IS_LSA_MAXAGE (current)) + ospf_external_lsa_refresh (ospf, current, + ei, LSA_REFRESH_FORCE); + else + zlog_warn ("ospf_zebra_read_ipv4() : %s already exists", + inet_ntoa (p.prefix)); + } + } + } + } + else /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */ + { + ospf_external_info_delete (api.type, p); + if ( !is_prefix_default (&p)) + ospf_external_lsa_flush (ospf, api.type, &p, ifindex, nexthop); + else + ospf_external_lsa_refresh_default (ospf); + } + + return 0; +} + + +int +ospf_distribute_list_out_set (struct ospf *ospf, int type, char *name) +{ + /* Lookup access-list for distribute-list. */ + DISTRIBUTE_LIST (ospf, type) = access_list_lookup (AFI_IP, name); + + /* Clear previous distribute-name. */ + if (DISTRIBUTE_NAME (ospf, type)) + free (DISTRIBUTE_NAME (ospf, type)); + + /* Set distribute-name. */ + DISTRIBUTE_NAME (ospf, type) = strdup (name); + + /* If access-list have been set, schedule update timer. */ + if (DISTRIBUTE_LIST (ospf, type)) + ospf_distribute_list_update (ospf, type); + + return CMD_SUCCESS; +} + +int +ospf_distribute_list_out_unset (struct ospf *ospf, int type, char *name) +{ + /* Schedule update timer. */ + if (DISTRIBUTE_LIST (ospf, type)) + ospf_distribute_list_update (ospf, type); + + /* Unset distribute-list. */ + DISTRIBUTE_LIST (ospf, type) = NULL; + + /* Clear distribute-name. */ + if (DISTRIBUTE_NAME (ospf, type)) + free (DISTRIBUTE_NAME (ospf, type)); + + DISTRIBUTE_NAME (ospf, type) = NULL; + + return CMD_SUCCESS; +} + +/* distribute-list update timer. */ +int +ospf_distribute_list_update_timer (struct thread *thread) +{ + struct route_node *rn; + struct external_info *ei; + struct route_table *rt; + struct ospf_lsa *lsa; + u_char type; + struct ospf *ospf; + + type = (int) THREAD_ARG (thread); + rt = EXTERNAL_INFO (type); + + ospf = ospf_lookup (); + if (ospf == NULL) + return 0; + + ospf->t_distribute_update = NULL; + + zlog_info ("Zebra[Redistribute]: distribute-list update timer fired!"); + + /* foreach all external info. */ + if (rt) + for (rn = route_top (rt); rn; rn = route_next (rn)) + if ((ei = rn->info) != NULL) + { + if (is_prefix_default (&ei->p)) + ospf_external_lsa_refresh_default (ospf); + else if ((lsa = ospf_external_info_find_lsa (ospf, &ei->p))) + ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_IF_CHANGED); + else + ospf_external_lsa_originate (ospf, ei); + } + return 0; +} + +#define OSPF_DISTRIBUTE_UPDATE_DELAY 5 + +/* Update distribute-list and set timer to apply access-list. */ +void +ospf_distribute_list_update (struct ospf *ospf, int type) +{ + struct route_table *rt; + + /* External info does not exist. */ + if (!(rt = EXTERNAL_INFO (type))) + return; + + /* If exists previously invoked thread, then cancel it. */ + if (ospf->t_distribute_update) + OSPF_TIMER_OFF (ospf->t_distribute_update); + + /* Set timer. */ + ospf->t_distribute_update = + thread_add_timer (master, ospf_distribute_list_update_timer, + (void *) type, OSPF_DISTRIBUTE_UPDATE_DELAY); +} + +/* If access-list is updated, apply some check. */ +void +ospf_filter_update (struct access_list *access) +{ + struct ospf *ospf; + int type; + int abr_inv = 0; + struct ospf_area *area; + listnode node; + + /* If OSPF instatnce does not exist, return right now. */ + ospf = ospf_lookup (); + if (ospf == NULL) + return; + + /* Update distribute-list, and apply filter. */ + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + { + if (ROUTEMAP (ospf, type) != NULL) + { + /* if route-map is not NULL it may be using this access list */ + ospf_distribute_list_update (ospf, type); + continue; + } + + + if (DISTRIBUTE_NAME (ospf, type)) + { + /* Keep old access-list for distribute-list. */ + struct access_list *old = DISTRIBUTE_LIST (ospf, type); + + /* Update access-list for distribute-list. */ + DISTRIBUTE_LIST (ospf, type) = + access_list_lookup (AFI_IP, DISTRIBUTE_NAME (ospf, type)); + + /* No update for this distribute type. */ + if (old == NULL && DISTRIBUTE_LIST (ospf, type) == NULL) + continue; + + /* Schedule distribute-list update timer. */ + if (DISTRIBUTE_LIST (ospf, type) == NULL || + strcmp (DISTRIBUTE_NAME (ospf, type), access->name) == 0) + ospf_distribute_list_update (ospf, type); + } + } + + /* Update Area access-list. */ + for (node = listhead (ospf->areas); node; nextnode (node)) + if ((area = getdata (node)) != NULL) + { + if (EXPORT_NAME (area)) + { + EXPORT_LIST (area) = NULL; + abr_inv++; + } + + if (IMPORT_NAME (area)) + { + IMPORT_LIST (area) = NULL; + abr_inv++; + } + } + + /* Schedule ABR tasks -- this will be changed -- takada. */ + if (IS_OSPF_ABR (ospf) && abr_inv) + ospf_schedule_abr_task (ospf); +} + + +struct ospf_distance * +ospf_distance_new () +{ + struct ospf_distance *new; + new = XMALLOC (MTYPE_OSPF_DISTANCE, sizeof (struct ospf_distance)); + memset (new, 0, sizeof (struct ospf_distance)); + return new; +} + +void +ospf_distance_free (struct ospf_distance *odistance) +{ + XFREE (MTYPE_OSPF_DISTANCE, odistance); +} + +int +ospf_distance_set (struct vty *vty, struct ospf *ospf, char *distance_str, + char *ip_str, char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct route_node *rn; + struct ospf_distance *odistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + /* Get OSPF distance node. */ + rn = route_node_get (ospf->distance_table, (struct prefix *) &p); + if (rn->info) + { + odistance = rn->info; + route_unlock_node (rn); + } + else + { + odistance = ospf_distance_new (); + rn->info = odistance; + } + + /* Set distance value. */ + odistance->distance = distance; + + /* Reset access-list configuration. */ + if (odistance->access_list) + { + free (odistance->access_list); + odistance->access_list = NULL; + } + if (access_list_str) + odistance->access_list = strdup (access_list_str); + + return CMD_SUCCESS; +} + +int +ospf_distance_unset (struct vty *vty, struct ospf *ospf, char *distance_str, + char *ip_str, char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct route_node *rn; + struct ospf_distance *odistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + rn = route_node_lookup (ospf->distance_table, (struct prefix *)&p); + if (! rn) + { + vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + odistance = rn->info; + + if (odistance->access_list) + free (odistance->access_list); + ospf_distance_free (odistance); + + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + + return CMD_SUCCESS; +} + +void +ospf_distance_reset (struct ospf *ospf) +{ + struct route_node *rn; + struct ospf_distance *odistance; + + for (rn = route_top (ospf->distance_table); rn; rn = route_next (rn)) + if ((odistance = rn->info) != NULL) + { + if (odistance->access_list) + free (odistance->access_list); + ospf_distance_free (odistance); + rn->info = NULL; + route_unlock_node (rn); + } +} + +u_char +ospf_distance_apply (struct prefix_ipv4 *p, struct ospf_route *or) +{ + struct ospf *ospf; + + ospf = ospf_lookup (); + if (ospf == NULL) + return 0; + + if (ospf->distance_intra) + if (or->path_type == OSPF_PATH_INTRA_AREA) + return ospf->distance_intra; + + if (ospf->distance_inter) + if (or->path_type == OSPF_PATH_INTER_AREA) + return ospf->distance_inter; + + if (ospf->distance_external) + if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL + || or->path_type == OSPF_PATH_TYPE2_EXTERNAL) + return ospf->distance_external; + + if (ospf->distance_all) + return ospf->distance_all; + + return 0; +} + +void +ospf_zebra_init () +{ + /* Allocate zebra structure. */ + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_OSPF); + zclient->interface_add = ospf_interface_add; + zclient->interface_delete = ospf_interface_delete; + zclient->interface_up = ospf_interface_state_up; + zclient->interface_down = ospf_interface_state_down; + zclient->interface_address_add = ospf_interface_address_add; + zclient->interface_address_delete = ospf_interface_address_delete; + zclient->ipv4_route_add = ospf_zebra_read_ipv4; + zclient->ipv4_route_delete = ospf_zebra_read_ipv4; + + access_list_add_hook (ospf_filter_update); + access_list_delete_hook (ospf_filter_update); +} diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h new file mode 100644 index 0000000..6e91f04 --- /dev/null +++ b/ospfd/ospf_zebra.h @@ -0,0 +1,76 @@ +/* + * Zebra connect library for OSPFd + * Copyright (C) 1997, 98, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPF_ZEBRA_H +#define _ZEBRA_OSPF_ZEBRA_H + +#define EXTERNAL_METRIC_TYPE_1 0 +#define EXTERNAL_METRIC_TYPE_2 1 + +#define DEFAULT_ROUTE ZEBRA_ROUTE_MAX +#define DEFAULT_ROUTE_TYPE(T) ((T) == DEFAULT_ROUTE) + +/* OSPF distance. */ +struct ospf_distance +{ + /* Distance value for the IP source prefix. */ + u_char distance; + + /* Name of the access-list to be matched. */ + char *access_list; +}; + +/* Prototypes */ +void ospf_zclient_start (); + +void ospf_zebra_add (struct prefix_ipv4 *, struct ospf_route *); +void ospf_zebra_delete (struct prefix_ipv4 *, struct ospf_route *); + +void ospf_zebra_add_discard (struct prefix_ipv4 *); +void ospf_zebra_delete_discard (struct prefix_ipv4 *); + +int ospf_default_originate_timer (struct thread *); + +int ospf_redistribute_check (struct ospf *, struct external_info *, int *); +int ospf_distribute_check_connected (struct ospf *, struct external_info *); +void ospf_distribute_list_update (struct ospf *, int); + +int ospf_is_type_redistributed (int); +void ospf_distance_reset (struct ospf *); +u_char ospf_distance_apply (struct prefix_ipv4 *, struct ospf_route *); + +struct vty; + +int ospf_redistribute_set (struct ospf *, int, int, int); +int ospf_redistribute_unset (struct ospf *, int); +int ospf_redistribute_default_set (struct ospf *, int, int, int); +int ospf_redistribute_default_unset (struct ospf *); +int ospf_distribute_list_out_set (struct ospf *, int, char *); +int ospf_distribute_list_out_unset (struct ospf *, int, char *); +void ospf_routemap_set (struct ospf *, int, char *); +void ospf_routemap_unset (struct ospf *, int); +int ospf_distance_set (struct vty *, struct ospf *, char *, char *, char *); +int ospf_distance_unset (struct vty *, struct ospf *, char *, char *, char *); +void ospf_zebra_init (); + +#endif /* _ZEBRA_OSPF_ZEBRA_H */ + diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c new file mode 100644 index 0000000..9e8da68 --- /dev/null +++ b/ospfd/ospfd.c @@ -0,0 +1,1622 @@ +/* OSPF version 2 daemon program. + Copyright (C) 1999, 2000 Toshiaki Takada + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "thread.h" +#include "vty.h" +#include "command.h" +#include "linklist.h" +#include "prefix.h" +#include "table.h" +#include "if.h" +#include "memory.h" +#include "stream.h" +#include "log.h" +#include "sockunion.h" /* for inet_aton () */ +#include "zclient.h" +#include "plist.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_network.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_abr.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_ase.h" + + +/* OSPF process wide configuration. */ +static struct ospf_master ospf_master; + +/* OSPF process wide configuration pointer to export. */ +struct ospf_master *om; + +extern struct zclient *zclient; + + +void ospf_remove_vls_through_area (struct ospf *, struct ospf_area *); +void ospf_network_free (struct ospf *, struct ospf_network *); +void ospf_area_free (struct ospf_area *); +void ospf_network_run (struct ospf *, struct prefix *, struct ospf_area *); + +/* Get Router ID from ospf interface list. */ +struct in_addr +ospf_router_id_get (list if_list) +{ + listnode node; + struct in_addr router_id; + + memset (&router_id, 0, sizeof (struct in_addr)); + + for (node = listhead (if_list); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + + if (!if_is_up (oi->ifp) || + OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE) + continue; + + /* Ignore virtual link interface. */ + if (oi->type != OSPF_IFTYPE_VIRTUALLINK && + oi->type != OSPF_IFTYPE_LOOPBACK) + if (IPV4_ADDR_CMP (&router_id, &oi->address->u.prefix4) < 0) + router_id = oi->address->u.prefix4; + } + + return router_id; +} + +#define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1 + +void +ospf_router_id_update (struct ospf *ospf) +{ + struct in_addr router_id, router_id_old; + listnode node; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Router-ID[OLD:%s]: Update", inet_ntoa (ospf->router_id)); + + router_id_old = ospf->router_id; + + if (ospf->router_id_static.s_addr != 0) + router_id = ospf->router_id_static; + else + router_id = ospf_router_id_get (ospf->oiflist); + + ospf->router_id = router_id; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Router-ID[NEW:%s]: Update", inet_ntoa (ospf->router_id)); + + if (!IPV4_ADDR_SAME (&router_id_old, &router_id)) + { + for (node = listhead (ospf->oiflist); node; nextnode (node)) + { + struct ospf_interface *oi = getdata (node); + + /* Update self-neighbor's router_id. */ + oi->nbr_self->router_id = router_id; + } + + /* If AS-external-LSA is queued, then flush those LSAs. */ + if (router_id_old.s_addr == 0 && ospf->external_origin) + { + int type; + /* Originate each redistributed external route. */ + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) + if (ospf->external_origin & (1 << type)) + thread_add_event (master, ospf_external_lsa_originate_timer, + ospf, type); + /* Originate Deafult. */ + if (ospf->external_origin & (1 << ZEBRA_ROUTE_MAX)) + thread_add_event (master, ospf_default_originate_timer, + &ospf->default_originate, 0); + + ospf->external_origin = 0; + } + + OSPF_TIMER_ON (ospf->t_router_lsa_update, + ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY); + } +} + +int +ospf_router_id_update_timer (struct thread *thread) +{ + struct ospf *ospf = THREAD_ARG (thread); + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Router-ID: Update timer fired!"); + + ospf->t_router_id_update = NULL; + ospf_router_id_update (ospf); + + return 0; +} + +/* For OSPF area sort by area id. */ +int +ospf_area_id_cmp (struct ospf_area *a1, struct ospf_area *a2) +{ + if (ntohl (a1->area_id.s_addr) > ntohl (a2->area_id.s_addr)) + return 1; + if (ntohl (a1->area_id.s_addr) < ntohl (a2->area_id.s_addr)) + return -1; + return 0; +} + +/* Allocate new ospf structure. */ +struct ospf * +ospf_new () +{ + int i; + + struct ospf *new = XCALLOC (MTYPE_OSPF_TOP, sizeof (struct ospf)); + + new->router_id.s_addr = htonl (0); + new->router_id_static.s_addr = htonl (0); + + new->abr_type = OSPF_ABR_STAND; + new->oiflist = list_new (); + new->vlinks = list_new (); + new->areas = list_new (); + new->areas->cmp = (int (*)(void *, void *)) ospf_area_id_cmp; + new->networks = route_table_init (); + new->nbr_nbma = route_table_init (); + + new->lsdb = ospf_lsdb_new (); + + new->default_originate = DEFAULT_ORIGINATE_NONE; + + new->new_external_route = route_table_init (); + new->old_external_route = route_table_init (); + new->external_lsas = route_table_init (); + + /* Distribute parameter init. */ + for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) + { + new->dmetric[i].type = -1; + new->dmetric[i].value = -1; + } + new->default_metric = -1; + new->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH; + + /* SPF timer value init. */ + new->spf_delay = OSPF_SPF_DELAY_DEFAULT; + new->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; + + /* MaxAge init. */ + new->maxage_lsa = list_new (); + new->t_maxage_walker = + thread_add_timer (master, ospf_lsa_maxage_walker, + new, OSPF_LSA_MAXAGE_CHECK_INTERVAL); + + /* Distance table init. */ + new->distance_table = route_table_init (); + + new->lsa_refresh_queue.index = 0; + new->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT; + new->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, + new, new->lsa_refresh_interval); + new->lsa_refresher_started = time (NULL); + + new->fd = ospf_sock_init (); + if (new->fd >= 0) + new->t_read = thread_add_read (master, ospf_read, new, new->fd); + new->oi_write_q = list_new (); + + return new; +} + +struct ospf * +ospf_lookup () +{ + if (listcount (om->ospf) == 0) + return NULL; + + return getdata (listhead (om->ospf)); +} + +void +ospf_add (struct ospf *ospf) +{ + listnode_add (om->ospf, ospf); +} + +void +ospf_delete (struct ospf *ospf) +{ + listnode_delete (om->ospf, ospf); +} + +struct ospf * +ospf_get () +{ + struct ospf *ospf; + + ospf = ospf_lookup (); + if (ospf == NULL) + { + ospf = ospf_new (); + ospf_add (ospf); + + if (ospf->router_id_static.s_addr == 0) + ospf_router_id_update (ospf); + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_type11_lsa_init (ospf); +#endif /* HAVE_OPAQUE_LSA */ + } + + return ospf; +} + +void +ospf_finish (struct ospf *ospf) +{ + struct route_node *rn; + struct ospf_nbr_nbma *nbr_nbma; + struct ospf_lsa *lsa; + listnode node; + int i; + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_type11_lsa_term (ospf); +#endif /* HAVE_OPAQUE_LSA */ + + /* Unredister redistribution */ + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + ospf_redistribute_unset (ospf, i); + + for (node = listhead (ospf->areas); node;) + { + struct ospf_area *area = getdata (node); + nextnode (node); + + ospf_remove_vls_through_area (ospf, area); + } + + for (node = listhead (ospf->vlinks); node; ) + { + struct ospf_vl_data *vl_data = node->data; + nextnode (node); + + ospf_vl_delete (ospf, vl_data); + } + + list_delete (ospf->vlinks); + + /* Reset interface. */ + for (node = listhead (ospf->oiflist); node;) + { + struct ospf_interface *oi = getdata (node); + nextnode (node); + + if (oi) + ospf_if_free (oi); + } + + /* Clear static neighbors */ + for (rn = route_top (ospf->nbr_nbma); rn; rn = route_next (rn)) + if ((nbr_nbma = rn->info)) + { + OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll); + + if (nbr_nbma->nbr) + { + nbr_nbma->nbr->nbr_nbma = NULL; + nbr_nbma->nbr = NULL; + } + + if (nbr_nbma->oi) + { + listnode_delete (nbr_nbma->oi->nbr_nbma, nbr_nbma); + nbr_nbma->oi = NULL; + } + + XFREE (MTYPE_OSPF_NEIGHBOR_STATIC, nbr_nbma); + } + + route_table_finish (ospf->nbr_nbma); + + /* Clear networks and Areas. */ + for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) + { + struct ospf_network *network; + + if ((network = rn->info) != NULL) + { + ospf_network_free (ospf, network); + rn->info = NULL; + route_unlock_node (rn); + } + } + + for (node = listhead (ospf->areas); node;) + { + struct ospf_area *area = getdata (node); + nextnode (node); + + listnode_delete (ospf->areas, area); + ospf_area_free (area); + } + + /* Cancel all timers. */ + OSPF_TIMER_OFF (ospf->t_external_lsa); + OSPF_TIMER_OFF (ospf->t_router_id_update); + OSPF_TIMER_OFF (ospf->t_router_lsa_update); + OSPF_TIMER_OFF (ospf->t_spf_calc); + OSPF_TIMER_OFF (ospf->t_ase_calc); + OSPF_TIMER_OFF (ospf->t_maxage); + OSPF_TIMER_OFF (ospf->t_maxage_walker); + OSPF_TIMER_OFF (ospf->t_abr_task); + OSPF_TIMER_OFF (ospf->t_distribute_update); + OSPF_TIMER_OFF (ospf->t_lsa_refresher); + OSPF_TIMER_OFF (ospf->t_read); + OSPF_TIMER_OFF (ospf->t_write); + + close (ospf->fd); + +#ifdef HAVE_OPAQUE_LSA + LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) + ospf_discard_from_db (ospf, ospf->lsdb, lsa); +#endif /* HAVE_OPAQUE_LSA */ + LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) + ospf_discard_from_db (ospf, ospf->lsdb, lsa); + + ospf_lsdb_delete_all (ospf->lsdb); + ospf_lsdb_free (ospf->lsdb); + + for (node = listhead (ospf->maxage_lsa); node; nextnode (node)) + ospf_lsa_unlock (getdata (node)); + + list_delete (ospf->maxage_lsa); + + if (ospf->old_table) + ospf_route_table_free (ospf->old_table); + if (ospf->new_table) + { + ospf_route_delete (ospf->new_table); + ospf_route_table_free (ospf->new_table); + } + if (ospf->old_rtrs) + ospf_rtrs_free (ospf->old_rtrs); + if (ospf->new_rtrs) + ospf_rtrs_free (ospf->new_rtrs); + if (ospf->new_external_route) + { + ospf_route_delete (ospf->new_external_route); + ospf_route_table_free (ospf->new_external_route); + } + if (ospf->old_external_route) + { + ospf_route_delete (ospf->old_external_route); + ospf_route_table_free (ospf->old_external_route); + } + if (ospf->external_lsas) + { + ospf_ase_external_lsas_finish (ospf->external_lsas); + } + + list_delete (ospf->areas); + + for (i = ZEBRA_ROUTE_SYSTEM; i <= ZEBRA_ROUTE_MAX; i++) + if (EXTERNAL_INFO (i) != NULL) + for (rn = route_top (EXTERNAL_INFO (i)); rn; rn = route_next (rn)) + { + if (rn->info == NULL) + continue; + + XFREE (MTYPE_OSPF_EXTERNAL_INFO, rn->info); + rn->info = NULL; + route_unlock_node (rn); + } + + ospf_distance_reset (ospf); + route_table_finish (ospf->distance_table); + + ospf_delete (ospf); + + XFREE (MTYPE_OSPF_TOP, ospf); +} + + +/* allocate new OSPF Area object */ +struct ospf_area * +ospf_area_new (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *new; + + /* Allocate new config_network. */ + new = XCALLOC (MTYPE_OSPF_AREA, sizeof (struct ospf_area)); + + new->ospf = ospf; + + new->area_id = area_id; + + new->external_routing = OSPF_AREA_DEFAULT; + new->default_cost = 1; + new->auth_type = OSPF_AUTH_NULL; + + /* New LSDB init. */ + new->lsdb = ospf_lsdb_new (); + + /* Self-originated LSAs initialize. */ + new->router_lsa_self = NULL; + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_type10_lsa_init (new); +#endif /* HAVE_OPAQUE_LSA */ + + new->oiflist = list_new (); + new->ranges = route_table_init (); + + if (area_id.s_addr == OSPF_AREA_BACKBONE) + ospf->backbone = new; + + return new; +} + +void +ospf_area_free (struct ospf_area *area) +{ + struct route_node *rn; + struct ospf_lsa *lsa; + + /* Free LSDBs. */ + LSDB_LOOP (ROUTER_LSDB (area), rn, lsa) + ospf_discard_from_db (area->ospf, area->lsdb, lsa); + LSDB_LOOP (NETWORK_LSDB (area), rn, lsa) + ospf_discard_from_db (area->ospf, area->lsdb, lsa); + LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) + ospf_discard_from_db (area->ospf, area->lsdb, lsa); + LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) + ospf_discard_from_db (area->ospf, area->lsdb, lsa); + +#ifdef HAVE_NSSA + LSDB_LOOP (NSSA_LSDB (area), rn, lsa) + ospf_discard_from_db (area->ospf, area->lsdb, lsa); +#endif /* HAVE_NSSA */ +#ifdef HAVE_OPAQUE_LSA + LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) + ospf_discard_from_db (area->ospf, area->lsdb, lsa); + LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) + ospf_discard_from_db (area->ospf, area->lsdb, lsa); +#endif /* HAVE_OPAQUE_LSA */ + + ospf_lsdb_delete_all (area->lsdb); + ospf_lsdb_free (area->lsdb); + +#ifdef HAVE_OPAQUE_LSA + ospf_opaque_type10_lsa_term (area); +#endif /* HAVE_OPAQUE_LSA */ + ospf_lsa_unlock (area->router_lsa_self); + + route_table_finish (area->ranges); + list_delete (area->oiflist); + + if (EXPORT_NAME (area)) + free (EXPORT_NAME (area)); + + if (IMPORT_NAME (area)) + free (IMPORT_NAME (area)); + + /* Cancel timer. */ + OSPF_TIMER_OFF (area->t_router_lsa_self); + + if (OSPF_IS_AREA_BACKBONE (area)) + area->ospf->backbone = NULL; + + XFREE (MTYPE_OSPF_AREA, area); +} + +void +ospf_area_check_free (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (area && + listcount (area->oiflist) == 0 && + area->ranges->top == NULL && + area->shortcut_configured == OSPF_SHORTCUT_DEFAULT && + area->external_routing == OSPF_AREA_DEFAULT && + area->no_summary == 0 && + area->default_cost == 1 && + EXPORT_NAME (area) == NULL && + IMPORT_NAME (area) == NULL && + area->auth_type == OSPF_AUTH_NULL) + { + listnode_delete (ospf->areas, area); + ospf_area_free (area); + } +} + +struct ospf_area * +ospf_area_get (struct ospf *ospf, struct in_addr area_id, int format) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (!area) + { + area = ospf_area_new (ospf, area_id); + area->format = format; + listnode_add_sort (ospf->areas, area); + ospf_check_abr_status (ospf); + } + + return area; +} + +struct ospf_area * +ospf_area_lookup_by_area_id (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + listnode node; + + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + + if (IPV4_ADDR_SAME (&area->area_id, &area_id)) + return area; + } + + return NULL; +} + +void +ospf_area_add_if (struct ospf_area *area, struct ospf_interface *oi) +{ + listnode_add (area->oiflist, oi); +} + +void +ospf_area_del_if (struct ospf_area *area, struct ospf_interface *oi) +{ + listnode_delete (area->oiflist, oi); +} + + +/* Config network statement related functions. */ +struct ospf_network * +ospf_network_new (struct in_addr area_id, int format) +{ + struct ospf_network *new; + new = XCALLOC (MTYPE_OSPF_NETWORK, sizeof (struct ospf_network)); + + new->area_id = area_id; + new->format = format; + + return new; +} + +void +ospf_network_free (struct ospf *ospf, struct ospf_network *network) +{ + ospf_area_check_free (ospf, network->area_id); + ospf_schedule_abr_task (ospf); + XFREE (MTYPE_OSPF_NETWORK, network); +} + +int +ospf_network_set (struct ospf *ospf, struct prefix_ipv4 *p, + struct in_addr area_id) +{ + struct ospf_network *network; + struct ospf_area *area; + struct route_node *rn; + struct external_info *ei; + int ret = OSPF_AREA_ID_FORMAT_ADDRESS; + + rn = route_node_get (ospf->networks, (struct prefix *)p); + if (rn->info) + { + /* There is already same network statement. */ + route_unlock_node (rn); + return 0; + } + + rn->info = network = ospf_network_new (area_id, ret); + area = ospf_area_get (ospf, area_id, ret); + + /* Run network config now. */ + ospf_network_run (ospf, (struct prefix *)p, area); + + /* Update connected redistribute. */ + if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) + if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) + for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); + rn; rn = route_next (rn)) + if ((ei = rn->info) != NULL) + if (ospf_external_info_find_lsa (ospf, &ei->p)) + if (!ospf_distribute_check_connected (ospf, ei)) + ospf_external_lsa_flush (ospf, ei->type, &ei->p, + ei->ifindex, ei->nexthop); + + ospf_area_check_free (ospf, area_id); + + return 1; +} + +int +ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p, + struct in_addr area_id) +{ + struct route_node *rn; + struct ospf_network *network; + struct external_info *ei; + + rn = route_node_lookup (ospf->networks, (struct prefix *)p); + if (rn == NULL) + return 0; + + network = rn->info; + if (!IPV4_ADDR_SAME (&area_id, &network->area_id)) + return 0; + + ospf_network_free (ospf, rn->info); + rn->info = NULL; + route_unlock_node (rn); + + ospf_if_update (ospf); + + /* Update connected redistribute. */ + if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) + if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) + for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); + rn; rn = route_next (rn)) + if ((ei = rn->info) != NULL) + if (!ospf_external_info_find_lsa (ospf, &ei->p)) + if (ospf_distribute_check_connected (ospf, ei)) + ospf_external_lsa_originate (ospf, ei); + + return 1; +} + + +void +ospf_network_run (struct ospf *ospf, struct prefix *p, struct ospf_area *area) +{ + struct interface *ifp; + listnode node; + + /* Schedule Router ID Update. */ + if (ospf->router_id_static.s_addr == 0) + if (ospf->t_router_id_update == NULL) + { + OSPF_TIMER_ON (ospf->t_router_id_update, ospf_router_id_update_timer, + OSPF_ROUTER_ID_UPDATE_DELAY); + } + + /* Get target interface. */ + for (node = listhead (om->iflist); node; nextnode (node)) + { + listnode cn; + + if ((ifp = getdata (node)) == NULL) + continue; + + if (memcmp (ifp->name, "VLINK", 5) == 0) + continue; + + /* if interface prefix is match specified prefix, + then create socket and join multicast group. */ + for (cn = listhead (ifp->connected); cn; nextnode (cn)) + { + struct connected *co = getdata (cn); + struct prefix *addr; + + if (if_is_pointopoint (ifp)) + addr = co->destination; + else + addr = co->address; + + if (p->family == co->address->family && + ! ospf_if_is_configured (ospf, &(addr->u.prefix4))) + if ((if_is_pointopoint (ifp) && + IPV4_ADDR_SAME (&(addr->u.prefix4), &(p->u.prefix4))) || + prefix_match (p, addr)) + { + struct ospf_interface *oi; + + oi = ospf_if_new (ospf, ifp, co->address); + oi->connected = co; + + oi->nbr_self->address = *oi->address; + + area->act_ints++; + oi->area = area; + + oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4); + oi->output_cost = ospf_if_get_output_cost (oi); + + if (area->external_routing != OSPF_AREA_DEFAULT) + UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + oi->nbr_self->priority = OSPF_IF_PARAM (oi, priority); + + /* Add pseudo neighbor. */ + ospf_nbr_add_self (oi); + + /* Make sure pseudo neighbor's router_id. */ + oi->nbr_self->router_id = ospf->router_id; + oi->nbr_self->src = oi->address->u.prefix4; + + /* Relate ospf interface to ospf instance. */ + oi->ospf = ospf; + + /* update network type as interface flag */ + /* If network type is specified previously, + skip network type setting. */ + oi->type = IF_DEF_PARAMS (ifp)->type; + + /* Set area flag. */ + switch (area->external_routing) + { + case OSPF_AREA_DEFAULT: + SET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + break; + case OSPF_AREA_STUB: + UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + break; +#ifdef HAVE_NSSA + case OSPF_AREA_NSSA: + UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + SET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP); + break; +#endif /* HAVE_NSSA */ + } + + ospf_area_add_if (oi->area, oi); + + if (if_is_up (ifp)) + ospf_if_up (oi); + + break; + } + } + } +} + +void +ospf_ls_upd_queue_empty (struct ospf_interface *oi) +{ + struct route_node *rn; + listnode node; + list lst; + struct ospf_lsa *lsa; + + /* empty ls update queue */ + for (rn = route_top (oi->ls_upd_queue); rn; + rn = route_next (rn)) + if ((lst = (list) rn->info)) + { + for (node = listhead (lst); node; nextnode (node)) + if ((lsa = getdata (node))) + ospf_lsa_unlock (lsa); + list_free (lst); + rn->info = NULL; + } + + /* remove update event */ + if (oi->t_ls_upd_event) + { + thread_cancel (oi->t_ls_upd_event); + oi->t_ls_upd_event = NULL; + } +} + +void +ospf_if_update (struct ospf *ospf) +{ + struct route_node *rn; + listnode node; + listnode next; + struct ospf_network *network; + struct ospf_area *area; + + if (ospf != NULL) + { + /* Update Router ID scheduled. */ + if (ospf->router_id_static.s_addr == 0) + if (ospf->t_router_id_update == NULL) + { + OSPF_TIMER_ON (ospf->t_router_id_update, + ospf_router_id_update_timer, + OSPF_ROUTER_ID_UPDATE_DELAY); + } + + /* Find interfaces that not configured already. */ + for (node = listhead (ospf->oiflist); node; node = next) + { + int found = 0; + struct ospf_interface *oi = getdata (node); + struct connected *co = oi->connected; + + next = nextnode (node); + + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + continue; + + for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) + { + if (rn->info == NULL) + continue; + + if ((oi->type == OSPF_IFTYPE_POINTOPOINT + && IPV4_ADDR_SAME (&(co->destination->u.prefix4), + &(rn->p.u.prefix4))) + || prefix_match (&(rn->p), co->address)) + { + found = 1; + route_unlock_node (rn); + break; + } + } + + if (found == 0) + ospf_if_free (oi); + } + + /* Run each interface. */ + for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) + if (rn->info != NULL) + { + network = (struct ospf_network *) rn->info; + area = ospf_area_get (ospf, network->area_id, network->format); + ospf_network_run (ospf, &rn->p, area); + } + } +} + +void +ospf_remove_vls_through_area (struct ospf *ospf, struct ospf_area *area) +{ + listnode node, next; + struct ospf_vl_data *vl_data; + + for (node = listhead (ospf->vlinks); node; node = next) + { + next = node->next; + if ((vl_data = getdata (node)) != NULL) + if (IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) + ospf_vl_delete (ospf, vl_data); + } +} + + +struct message ospf_area_type_msg[] = +{ + { OSPF_AREA_DEFAULT, "Default" }, + { OSPF_AREA_STUB, "Stub" }, + { OSPF_AREA_NSSA, "NSSA" }, +}; +int ospf_area_type_msg_max = OSPF_AREA_TYPE_MAX; + +void +ospf_area_type_set (struct ospf_area *area, int type) +{ + listnode node; + struct ospf_interface *oi; + + if (area->external_routing == type) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Area[%s]: Types are the same, ignored.", + inet_ntoa (area->area_id)); + return; + } + + area->external_routing = type; + + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("Area[%s]: Configured as %s", inet_ntoa (area->area_id), + LOOKUP (ospf_area_type_msg, type)); + + switch (area->external_routing) + { + case OSPF_AREA_DEFAULT: + for (node = listhead (area->oiflist); node; nextnode (node)) + if ((oi = getdata (node)) != NULL) + if (oi->nbr_self != NULL) + SET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + break; + case OSPF_AREA_STUB: + for (node = listhead (area->oiflist); node; nextnode (node)) + if ((oi = getdata (node)) != NULL) + if (oi->nbr_self != NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("setting options on %s accordingly", IF_NAME (oi)); + UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + if (IS_DEBUG_OSPF_EVENT) + zlog_info ("options set on %s: %x", + IF_NAME (oi), OPTIONS (oi)); + } + break; + case OSPF_AREA_NSSA: +#ifdef HAVE_NSSA + for (node = listhead (area->oiflist); node; nextnode (node)) + if ((oi = getdata (node)) != NULL) + if (oi->nbr_self != NULL) + { + zlog_info ("setting nssa options on %s accordingly", IF_NAME (oi)); + UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); + SET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP); + zlog_info ("options set on %s: %x", IF_NAME (oi), OPTIONS (oi)); + } +#endif /* HAVE_NSSA */ + break; + default: + break; + } + + ospf_router_lsa_timer_add (area); + ospf_schedule_abr_task (area->ospf); +} + +int +ospf_area_shortcut_set (struct ospf *ospf, struct ospf_area *area, int mode) +{ + if (area->shortcut_configured == mode) + return 0; + + area->shortcut_configured = mode; + ospf_router_lsa_timer_add (area); + ospf_schedule_abr_task (ospf); + + ospf_area_check_free (ospf, area->area_id); + + return 1; +} + +int +ospf_area_shortcut_unset (struct ospf *ospf, struct ospf_area *area) +{ + area->shortcut_configured = OSPF_SHORTCUT_DEFAULT; + ospf_router_lsa_timer_add (area); + ospf_area_check_free (ospf, area->area_id); + ospf_schedule_abr_task (ospf); + + return 1; +} + +int +ospf_area_vlink_count (struct ospf *ospf, struct ospf_area *area) +{ + struct ospf_vl_data *vl; + listnode node; + int count = 0; + + for (node = listhead (ospf->vlinks); node; nextnode (node)) + { + vl = getdata (node); + if (IPV4_ADDR_SAME (&vl->vl_area_id, &area->area_id)) + count++; + } + + return count; +} + +int +ospf_area_stub_set (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + int format = OSPF_AREA_ID_FORMAT_ADDRESS; + + area = ospf_area_get (ospf, area_id, format); + if (ospf_area_vlink_count (ospf, area)) + return 0; + + if (area->external_routing != OSPF_AREA_STUB) + ospf_area_type_set (area, OSPF_AREA_STUB); + + return 1; +} + +int +ospf_area_stub_unset (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (area == NULL) + return 1; + + if (area->external_routing == OSPF_AREA_STUB) + ospf_area_type_set (area, OSPF_AREA_DEFAULT); + + ospf_area_check_free (ospf, area_id); + + return 1; +} + +int +ospf_area_no_summary_set (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + int format = OSPF_AREA_ID_FORMAT_ADDRESS; + + area = ospf_area_get (ospf, area_id, format); + area->no_summary = 1; + + return 1; +} + +int +ospf_area_no_summary_unset (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (area == NULL) + return 0; + + area->no_summary = 0; + ospf_area_check_free (ospf, area_id); + + return 1; +} + +int +ospf_area_nssa_set (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + int format = OSPF_AREA_ID_FORMAT_ADDRESS; + + area = ospf_area_get (ospf, area_id, format); + if (ospf_area_vlink_count (ospf, area)) + return 0; + + if (area->external_routing != OSPF_AREA_NSSA) + { + ospf_area_type_set (area, OSPF_AREA_NSSA); + ospf->anyNSSA++; + } + + return 1; +} + +int +ospf_area_nssa_unset (struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (area == NULL) + return 0; + + if (area->external_routing == OSPF_AREA_NSSA) + { + ospf->anyNSSA--; + ospf_area_type_set (area, OSPF_AREA_DEFAULT); + } + + ospf_area_check_free (ospf, area_id); + + return 1; +} + +int +ospf_area_nssa_translator_role_set (struct ospf *ospf, struct in_addr area_id, + int role) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (area == NULL) + return 0; + + area->NSSATranslator = role; + + return 1; +} + +int +ospf_area_nssa_translator_role_unset (struct ospf *ospf, + struct in_addr area_id) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id (ospf, area_id); + if (area == NULL) + return 0; + + area->NSSATranslator = OSPF_NSSA_ROLE_CANDIDATE; + + ospf_area_check_free (ospf, area_id); + + return 1; +} + +int +ospf_area_export_list_set (struct ospf *ospf, + struct ospf_area *area, char *list_name) +{ + struct access_list *list; + list = access_list_lookup (AFI_IP, list_name); + + EXPORT_LIST (area) = list; + + if (EXPORT_NAME (area)) + free (EXPORT_NAME (area)); + + EXPORT_NAME (area) = strdup (list_name); + ospf_schedule_abr_task (ospf); + + return 1; +} + +int +ospf_area_export_list_unset (struct ospf *ospf, struct ospf_area * area) +{ + + EXPORT_LIST (area) = 0; + + if (EXPORT_NAME (area)) + free (EXPORT_NAME (area)); + + EXPORT_NAME (area) = NULL; + + ospf_area_check_free (ospf, area->area_id); + + ospf_schedule_abr_task (ospf); + + return 1; +} + +int +ospf_area_import_list_set (struct ospf *ospf, + struct ospf_area *area, char *name) +{ + struct access_list *list; + list = access_list_lookup (AFI_IP, name); + + IMPORT_LIST (area) = list; + + if (IMPORT_NAME (area)) + free (IMPORT_NAME (area)); + + IMPORT_NAME (area) = strdup (name); + ospf_schedule_abr_task (ospf); + + return 1; +} + +int +ospf_area_import_list_unset (struct ospf *ospf, struct ospf_area * area) +{ + IMPORT_LIST (area) = 0; + + if (IMPORT_NAME (area)) + free (IMPORT_NAME (area)); + + IMPORT_NAME (area) = NULL; + ospf_area_check_free (ospf, area->area_id); + + ospf_schedule_abr_task (ospf); + + return 1; +} + +int +ospf_timers_spf_set (struct ospf *ospf, u_int32_t delay, u_int32_t hold) +{ + ospf->spf_delay = delay; + ospf->spf_holdtime = hold; + + return 1; +} + +int +ospf_timers_spf_unset (struct ospf *ospf) +{ + ospf->spf_delay = OSPF_SPF_DELAY_DEFAULT; + ospf->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; + + return 1; +} + +int +ospf_timers_refresh_set (struct ospf *ospf, int interval) +{ + int time_left; + + if (ospf->lsa_refresh_interval == interval) + return 1; + + time_left = ospf->lsa_refresh_interval - + (time (NULL) - ospf->lsa_refresher_started); + + if (time_left > interval) + { + OSPF_TIMER_OFF (ospf->t_lsa_refresher); + ospf->t_lsa_refresher = + thread_add_timer (master, ospf_lsa_refresh_walker, ospf, interval); + } + ospf->lsa_refresh_interval = interval; + + return 1; +} + +int +ospf_timers_refresh_unset (struct ospf *ospf) +{ + int time_left; + + time_left = ospf->lsa_refresh_interval - + (time (NULL) - ospf->lsa_refresher_started); + + if (time_left > OSPF_LSA_REFRESH_INTERVAL_DEFAULT) + { + OSPF_TIMER_OFF (ospf->t_lsa_refresher); + ospf->t_lsa_refresher = + thread_add_timer (master, ospf_lsa_refresh_walker, ospf, + OSPF_LSA_REFRESH_INTERVAL_DEFAULT); + } + + ospf->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT; + + return 1; +} + + +struct ospf_nbr_nbma * +ospf_nbr_nbma_new () +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = XMALLOC (MTYPE_OSPF_NEIGHBOR_STATIC, + sizeof (struct ospf_nbr_nbma)); + memset (nbr_nbma, 0, sizeof (struct ospf_nbr_nbma)); + + nbr_nbma->priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; + nbr_nbma->v_poll = OSPF_POLL_INTERVAL_DEFAULT; + + return nbr_nbma; +} + +void +ospf_nbr_nbma_free (struct ospf_nbr_nbma *nbr_nbma) +{ + XFREE (MTYPE_OSPF_NEIGHBOR_STATIC, nbr_nbma); +} + +void +ospf_nbr_nbma_delete (struct ospf *ospf, struct ospf_nbr_nbma *nbr_nbma) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefix = nbr_nbma->addr; + p.prefixlen = IPV4_MAX_BITLEN; + + rn = route_node_lookup (ospf->nbr_nbma, (struct prefix *)&p); + if (rn) + { + ospf_nbr_nbma_free (rn->info); + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + } +} + +void +ospf_nbr_nbma_down (struct ospf_nbr_nbma *nbr_nbma) +{ + OSPF_TIMER_OFF (nbr_nbma->t_poll); + + if (nbr_nbma->nbr) + { + nbr_nbma->nbr->nbr_nbma = NULL; + OSPF_NSM_EVENT_EXECUTE (nbr_nbma->nbr, NSM_KillNbr); + } + + if (nbr_nbma->oi) + listnode_delete (nbr_nbma->oi->nbr_nbma, nbr_nbma); +} + +void +ospf_nbr_nbma_add (struct ospf_nbr_nbma *nbr_nbma, + struct ospf_interface *oi) +{ + struct ospf_neighbor *nbr; + struct route_node *rn; + struct prefix p; + + if (oi->type != OSPF_IFTYPE_NBMA) + return; + + if (nbr_nbma->nbr != NULL) + return; + + if (IPV4_ADDR_SAME (&oi->nbr_self->address.u.prefix4, &nbr_nbma->addr)) + return; + + nbr_nbma->oi = oi; + listnode_add (oi->nbr_nbma, nbr_nbma); + + /* Get neighbor information from table. */ + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = nbr_nbma->addr; + + rn = route_node_get (oi->nbrs, (struct prefix *)&p); + if (rn->info) + { + nbr = rn->info; + nbr->nbr_nbma = nbr_nbma; + nbr_nbma->nbr = nbr; + + route_unlock_node (rn); + } + else + { + nbr = rn->info = ospf_nbr_new (oi); + nbr->state = NSM_Down; + nbr->src = nbr_nbma->addr; + nbr->nbr_nbma = nbr_nbma; + nbr->priority = nbr_nbma->priority; + nbr->address = p; + + nbr_nbma->nbr = nbr; + + OSPF_NSM_EVENT_EXECUTE (nbr, NSM_Start); + } +} + +void +ospf_nbr_nbma_if_update (struct ospf *ospf, struct ospf_interface *oi) +{ + struct ospf_nbr_nbma *nbr_nbma; + struct route_node *rn; + struct prefix_ipv4 p; + + if (oi->type != OSPF_IFTYPE_NBMA) + return; + + for (rn = route_top (ospf->nbr_nbma); rn; rn = route_next (rn)) + if ((nbr_nbma = rn->info)) + if (nbr_nbma->oi == NULL && nbr_nbma->nbr == NULL) + { + p.family = AF_INET; + p.prefix = nbr_nbma->addr; + p.prefixlen = IPV4_MAX_BITLEN; + + if (prefix_match (oi->address, (struct prefix *)&p)) + ospf_nbr_nbma_add (nbr_nbma, oi); + } +} + +struct ospf_nbr_nbma * +ospf_nbr_nbma_lookup (struct ospf *ospf, struct in_addr nbr_addr) +{ + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefix = nbr_addr; + p.prefixlen = IPV4_MAX_BITLEN; + + rn = route_node_lookup (ospf->nbr_nbma, (struct prefix *)&p); + if (rn) + { + route_unlock_node (rn); + return rn->info; + } + return NULL; +} + +int +ospf_nbr_nbma_set (struct ospf *ospf, struct in_addr nbr_addr) +{ + struct ospf_nbr_nbma *nbr_nbma; + struct ospf_interface *oi; + struct prefix_ipv4 p; + struct route_node *rn; + listnode node; + + nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); + if (nbr_nbma) + return 0; + + nbr_nbma = ospf_nbr_nbma_new (); + nbr_nbma->addr = nbr_addr; + + p.family = AF_INET; + p.prefix = nbr_addr; + p.prefixlen = IPV4_MAX_BITLEN; + + rn = route_node_get (ospf->nbr_nbma, (struct prefix *)&p); + rn->info = nbr_nbma; + + for (node = listhead (ospf->oiflist); node; nextnode (node)) + { + oi = getdata (node); + if (oi->type == OSPF_IFTYPE_NBMA) + if (prefix_match (oi->address, (struct prefix *)&p)) + { + ospf_nbr_nbma_add (nbr_nbma, oi); + break; + } + } + + return 1; +} + +int +ospf_nbr_nbma_unset (struct ospf *ospf, struct in_addr nbr_addr) +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); + if (nbr_nbma == NULL) + return 0; + + ospf_nbr_nbma_down (nbr_nbma); + ospf_nbr_nbma_delete (ospf, nbr_nbma); + + return 1; +} + +int +ospf_nbr_nbma_priority_set (struct ospf *ospf, struct in_addr nbr_addr, + u_char priority) +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); + if (nbr_nbma == NULL) + return 0; + + if (nbr_nbma->priority != priority) + nbr_nbma->priority = priority; + + return 1; +} + +int +ospf_nbr_nbma_priority_unset (struct ospf *ospf, struct in_addr nbr_addr) +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); + if (nbr_nbma == NULL) + return 0; + + if (nbr_nbma != OSPF_NEIGHBOR_PRIORITY_DEFAULT) + nbr_nbma->priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; + + return 1; +} + +int +ospf_nbr_nbma_poll_interval_set (struct ospf *ospf, struct in_addr nbr_addr, + int interval) +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); + if (nbr_nbma == NULL) + return 0; + + if (nbr_nbma->v_poll != interval) + { + nbr_nbma->v_poll = interval; + if (nbr_nbma->oi && ospf_if_is_up (nbr_nbma->oi)) + { + OSPF_TIMER_OFF (nbr_nbma->t_poll); + OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer, + nbr_nbma->v_poll); + } + } + + return 1; +} + +int +ospf_nbr_nbma_poll_interval_unset (struct ospf *ospf, struct in_addr addr) +{ + struct ospf_nbr_nbma *nbr_nbma; + + nbr_nbma = ospf_nbr_nbma_lookup (ospf, addr); + if (nbr_nbma == NULL) + return 0; + + if (nbr_nbma->v_poll != OSPF_POLL_INTERVAL_DEFAULT) + nbr_nbma->v_poll = OSPF_POLL_INTERVAL_DEFAULT; + + return 1; +} + + +void +ospf_prefix_list_update (struct prefix_list *plist) +{ + struct ospf *ospf; + struct ospf_area *area; + listnode node; + int abr_inv = 0; + + /* If OSPF instatnce does not exist, return right now. */ + ospf = ospf_lookup (); + if (ospf == NULL) + return; + + /* Update Area prefix-list. */ + for (node = listhead (ospf->areas); node; nextnode (node)) + { + area = getdata (node); + + /* Update filter-list in. */ + if (PREFIX_NAME_IN (area)) + if (strcmp (PREFIX_NAME_IN (area), plist->name) == 0) + { + PREFIX_LIST_IN (area) = + prefix_list_lookup (AFI_IP, PREFIX_NAME_IN (area)); + abr_inv++; + } + + /* Update filter-list out. */ + if (PREFIX_NAME_OUT (area)) + if (strcmp (PREFIX_NAME_OUT (area), plist->name) == 0) + { + PREFIX_LIST_IN (area) = + prefix_list_lookup (AFI_IP, PREFIX_NAME_OUT (area)); + abr_inv++; + } + } + + /* Schedule ABR tasks. */ + if (IS_OSPF_ABR (ospf) && abr_inv) + ospf_schedule_abr_task (ospf); +} + +void +ospf_master_init () +{ + memset (&ospf_master, 0, sizeof (struct ospf_master)); + + om = &ospf_master; + om->ospf = list_new (); + om->master = thread_master_create (); + om->start_time = time (NULL); +} + +void +ospf_init () +{ + prefix_list_add_hook (ospf_prefix_list_update); + prefix_list_delete_hook (ospf_prefix_list_update); +} diff --git a/ospfd/ospfd.conf.sample b/ospfd/ospfd.conf.sample new file mode 100644 index 0000000..80bdf2e --- /dev/null +++ b/ospfd/ospfd.conf.sample @@ -0,0 +1,12 @@ +! -*- ospf -*- +! +! OSPFd sample configuration file +! +hostname ospfd +password zebra +!enable password please-set-at-here +! +!router ospf +! network 192.168.1.0/24 area 0 +! +log stdout diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h new file mode 100644 index 0000000..e960b83 --- /dev/null +++ b/ospfd/ospfd.h @@ -0,0 +1,579 @@ +/* + * OSPFd main header. + * Copyright (C) 1998, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_OSPFD_H +#define _ZEBRA_OSPFD_H + +#include "filter.h" + +#define OSPF_VERSION 2 + +/* Default protocol, port number. */ +#ifndef IPPROTO_OSPFIGP +#define IPPROTO_OSPFIGP 89 +#endif /* IPPROTO_OSPFIGP */ + +/* IP precedence. */ +#ifndef IPTOS_PREC_INTERNETCONTROL +#define IPTOS_PREC_INTERNETCONTROL 0xC0 +#endif /* IPTOS_PREC_INTERNETCONTROL */ + +/* VTY port number. */ +#define OSPF_VTY_PORT 2604 +#define OSPF_VTYSH_PATH "/tmp/.ospfd" + +/* IP TTL for OSPF protocol. */ +#define OSPF_IP_TTL 1 +#define OSPF_VL_IP_TTL 100 + +/* Default configuration file name for ospfd. */ +#define OSPF_DEFAULT_CONFIG "ospfd.conf" + +/* Architectual Constants */ +#ifdef DEBUG +#define OSPF_LS_REFRESH_TIME 60 +#else +#define OSPF_LS_REFRESH_TIME 1800 +#endif +#define OSPF_MIN_LS_INTERVAL 5 +#define OSPF_MIN_LS_ARRIVAL 1 +#define OSPF_LSA_MAXAGE 3600 +#define OSPF_CHECK_AGE 300 +#define OSPF_LSA_MAXAGE_DIFF 900 +#define OSPF_LS_INFINITY 0xffffff +#define OSPF_DEFAULT_DESTINATION 0x00000000 /* 0.0.0.0 */ +#define OSPF_INITIAL_SEQUENCE_NUMBER 0x80000001 +#define OSPF_MAX_SEQUENCE_NUMBER 0x7fffffff + +#define OSPF_LSA_MAXAGE_CHECK_INTERVAL 30 + +#define OSPF_ALLSPFROUTERS 0xe0000005 /* 224.0.0.5 */ +#define OSPF_ALLDROUTERS 0xe0000006 /* 224.0.0.6 */ + +#ifdef HAVE_NSSA +#define OSPF_LOOPer 0x7f000000 /* 127.0.0.0 */ +#endif /* HAVE_NSSA */ + +#define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */ + +/* OSPF Authentication Type. */ +#define OSPF_AUTH_NULL 0 +#define OSPF_AUTH_SIMPLE 1 +#define OSPF_AUTH_CRYPTOGRAPHIC 2 +/* For Interface authentication setting default */ +#define OSPF_AUTH_NOTSET -1 +/* For the consumption and sanity of the command handler */ +/* DO NIOT REMOVE!!! Need to detect whether a value has + been given or not in VLink command handlers */ +#define OSPF_AUTH_CMD_NOTSEEN -2 + +/* OSPF SPF timer values. */ +#define OSPF_SPF_DELAY_DEFAULT 5 +#define OSPF_SPF_HOLDTIME_DEFAULT 10 + +/* OSPF interface default values. */ +#define OSPF_OUTPUT_COST_DEFAULT 10 +#define OSPF_ROUTER_DEAD_INTERVAL_DEFAULT 40 +#define OSPF_HELLO_INTERVAL_DEFAULT 10 +#define OSPF_ROUTER_PRIORITY_DEFAULT 1 +#define OSPF_RETRANSMIT_INTERVAL_DEFAULT 5 +#define OSPF_TRANSMIT_DELAY_DEFAULT 1 +#define OSPF_DEFAULT_BANDWIDTH 10000 /* Kbps */ + +#define OSPF_DEFAULT_REF_BANDWIDTH 100000 /* Kbps */ + +#define OSPF_POLL_INTERVAL_DEFAULT 60 +#define OSPF_NEIGHBOR_PRIORITY_DEFAULT 0 + +/* OSPF options. */ +#define OSPF_OPTION_T 0x01 /* TOS. */ +#define OSPF_OPTION_E 0x02 +#define OSPF_OPTION_MC 0x04 +#define OSPF_OPTION_NP 0x08 +#define OSPF_OPTION_EA 0x10 +#define OSPF_OPTION_DC 0x20 +#define OSPF_OPTION_O 0x40 + +/* OSPF Database Description flags. */ +#define OSPF_DD_FLAG_MS 0x01 +#define OSPF_DD_FLAG_M 0x02 +#define OSPF_DD_FLAG_I 0x04 +#define OSPF_DD_FLAG_ALL 0x07 + +/* Timer value. */ +#define OSPF_ROUTER_ID_UPDATE_DELAY 1 + +#define OSPF_LS_REFRESH_SHIFT (60 * 15) +#define OSPF_LS_REFRESH_JITTER 60 + +/* OSPF master for system wide configuration and variables. */ +struct ospf_master +{ + /* OSPF instance. */ + struct list *ospf; + + /* OSPF thread master. */ + struct thread_master *master; + + /* Zebra interface list. */ + struct list *iflist; + + /* Redistributed external information. */ + struct route_table *external_info[ZEBRA_ROUTE_MAX + 1]; +#define EXTERNAL_INFO(T) om->external_info[T] + + /* OSPF start time. */ + time_t start_time; + + /* Various OSPF global configuration. */ + u_char options; +}; + +/* OSPF instance structure. */ +struct ospf +{ + /* OSPF Router ID. */ + struct in_addr router_id; /* Configured automatically. */ + struct in_addr router_id_static; /* Configured manually. */ + + /* ABR/ASBR internal flags. */ + u_char flags; +#define OSPF_FLAG_ABR 0x0001 +#define OSPF_FLAG_ASBR 0x0002 + + /* ABR type. */ + u_char abr_type; +#define OSPF_ABR_UNKNOWN 0 +#define OSPF_ABR_STAND 1 +#define OSPF_ABR_IBM 2 +#define OSPF_ABR_CISCO 3 +#define OSPF_ABR_SHORTCUT 4 + + /* NSSA ABR */ + u_char anyNSSA; /* Bump for every NSSA attached. */ + + /* Configured variables. */ + u_char config; +#define OSPF_RFC1583_COMPATIBLE (1 << 0) +#define OSPF_OPAQUE_CAPABLE (1 << 2) + +#ifdef HAVE_OPAQUE_LSA + /* Opaque-LSA administrative flags. */ + u_char opaque; +#define OPAQUE_OPERATION_READY_BIT (1 << 0) +#define OPAQUE_BLOCK_TYPE_09_LSA_BIT (1 << 1) +#define OPAQUE_BLOCK_TYPE_10_LSA_BIT (1 << 2) +#define OPAQUE_BLOCK_TYPE_11_LSA_BIT (1 << 3) +#endif /* HAVE_OPAQUE_LSA */ + + int spf_delay; /* SPF delay time. */ + int spf_holdtime; /* SPF hold time. */ + int default_originate; /* Default information originate. */ +#define DEFAULT_ORIGINATE_NONE 0 +#define DEFAULT_ORIGINATE_ZEBRA 1 +#define DEFAULT_ORIGINATE_ALWAYS 2 + u_int32_t ref_bandwidth; /* Reference Bandwidth (Kbps). */ + struct route_table *networks; /* OSPF config networks. */ + list vlinks; /* Configured Virtual-Links. */ + list areas; /* OSPF areas. */ + struct route_table *nbr_nbma; + struct ospf_area *backbone; /* Pointer to the Backbone Area. */ + + list oiflist; /* ospf interfaces */ + + /* LSDB of AS-external-LSAs. */ + struct ospf_lsdb *lsdb; + + /* Flags. */ + int external_origin; /* AS-external-LSA origin flag. */ + int ase_calc; /* ASE calculation flag. */ + +#ifdef HAVE_OPAQUE_LSA + list opaque_lsa_self; /* Type-11 Opaque-LSAs */ +#endif /* HAVE_OPAQUE_LSA */ + + /* Routing tables. */ + struct route_table *old_table; /* Old routing table. */ + struct route_table *new_table; /* Current routing table. */ + + struct route_table *old_rtrs; /* Old ABR/ASBR RT. */ + struct route_table *new_rtrs; /* New ABR/ASBR RT. */ + + struct route_table *new_external_route; /* New External Route. */ + struct route_table *old_external_route; /* Old External Route. */ + + struct route_table *external_lsas; /* Database of external LSAs, + prefix is LSA's adv. network*/ + + /* Time stamps. */ + time_t ts_spf; /* SPF calculation time stamp. */ + + list maxage_lsa; /* List of MaxAge LSA for deletion. */ + int redistribute; /* Num of redistributed protocols. */ + + /* Threads. */ + struct thread *t_router_id_update; /* Router ID update timer. */ + struct thread *t_router_lsa_update; /* router-LSA update timer. */ + struct thread *t_abr_task; /* ABR task timer. */ + struct thread *t_asbr_check; /* ASBR check timer. */ + struct thread *t_distribute_update; /* Distirbute list update timer. */ + struct thread *t_spf_calc; /* SPF calculation timer. */ + struct thread *t_ase_calc; /* ASE calculation timer. */ + struct thread *t_external_lsa; /* AS-external-LSA origin timer. */ +#ifdef HAVE_OPAQUE_LSA + struct thread *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */ +#endif /* HAVE_OPAQUE_LSA */ + struct thread *t_maxage; /* MaxAge LSA remover timer. */ + struct thread *t_maxage_walker; /* MaxAge LSA checking timer. */ + + struct thread *t_write; + struct thread *t_read; + int fd; + list oi_write_q; + + /* Distribute lists out of other route sources. */ + struct + { + char *name; + struct access_list *list; + } dlist[ZEBRA_ROUTE_MAX]; +#define DISTRIBUTE_NAME(O,T) (O)->dlist[T].name +#define DISTRIBUTE_LIST(O,T) (O)->dlist[T].list + + /* Redistribute metric info. */ + struct + { + int type; /* External metric type (E1 or E2). */ + int value; /* Value for static metric (24-bit). + -1 means metric value is not set. */ + } dmetric [ZEBRA_ROUTE_MAX + 1]; + + /* For redistribute route map. */ + struct + { + char *name; + struct route_map *map; + } route_map [ZEBRA_ROUTE_MAX + 1]; /* +1 is for default-information */ +#define ROUTEMAP_NAME(O,T) (O)->route_map[T].name +#define ROUTEMAP(O,T) (O)->route_map[T].map + + int default_metric; /* Default metric for redistribute. */ + +#define OSPF_LSA_REFRESHER_GRANULARITY 10 +#define OSPF_LSA_REFRESHER_SLOTS ((OSPF_LS_REFRESH_TIME + \ + OSPF_LS_REFRESH_SHIFT)/10 + 1) + struct + { + u_int16_t index; + list qs[OSPF_LSA_REFRESHER_SLOTS]; + } lsa_refresh_queue; + + struct thread *t_lsa_refresher; + time_t lsa_refresher_started; +#define OSPF_LSA_REFRESH_INTERVAL_DEFAULT 10 + u_int16_t lsa_refresh_interval; + + /* Distance parameter. */ + u_char distance_all; + u_char distance_intra; + u_char distance_inter; + u_char distance_external; + + /* Statistics for LSA origination. */ + u_int32_t lsa_originate_count; + + /* Statistics for LSA used for new instantiation. */ + u_int32_t rx_lsa_count; + + struct route_table *distance_table; +}; + +/* OSPF area structure. */ +struct ospf_area +{ + /* OSPF instance. */ + struct ospf *ospf; + + /* Zebra interface list belonging to the area. */ + list oiflist; + + /* Area ID. */ + struct in_addr area_id; + + /* Area ID format. */ + char format; +#define OSPF_AREA_ID_FORMAT_ADDRESS 1 +#define OSPF_AREA_ID_FORMAT_DECIMAL 2 + + /* Address range. */ + list address_range; + + /* Configured variables. */ + int external_routing; /* ExternalRoutingCapability. */ +#define OSPF_AREA_DEFAULT 0 +#define OSPF_AREA_STUB 1 +#define OSPF_AREA_NSSA 2 +#define OSPF_AREA_TYPE_MAX 3 + int no_summary; /* Don't inject summaries into stub.*/ + int shortcut_configured; /* Area configured as shortcut. */ +#define OSPF_SHORTCUT_DEFAULT 0 +#define OSPF_SHORTCUT_ENABLE 1 +#define OSPF_SHORTCUT_DISABLE 2 + int shortcut_capability; /* Other ABRs agree on S-bit */ + u_int32_t default_cost; /* StubDefaultCost. */ + int auth_type; /* Authentication type. */ + + u_char NSSATranslatorRole; /* NSSA Role during configuration */ +#define OSPF_NSSA_ROLE_NEVER 0 +#define OSPF_NSSA_ROLE_ALWAYS 1 +#define OSPF_NSSA_ROLE_CANDIDATE 2 + u_char NSSATranslator; /* NSSA Role after election process */ + + u_char transit; /* TransitCapability. */ +#define OSPF_TRANSIT_FALSE 0 +#define OSPF_TRANSIT_TRUE 1 + struct route_table *ranges; /* Configured Area Ranges. */ + + /* Area related LSDBs[Type1-4]. */ + struct ospf_lsdb *lsdb; + + /* Self-originated LSAs. */ + struct ospf_lsa *router_lsa_self; +#ifdef HAVE_OPAQUE_LSA + list opaque_lsa_self; /* Type-10 Opaque-LSAs */ +#endif /* HAVE_OPAQUE_LSA */ + + /* Area announce list. */ + struct + { + char *name; + struct access_list *list; + } export; +#define EXPORT_NAME(A) (A)->export.name +#define EXPORT_LIST(A) (A)->export.list + + /* Area acceptance list. */ + struct + { + char *name; + struct access_list *list; + } import; +#define IMPORT_NAME(A) (A)->import.name +#define IMPORT_LIST(A) (A)->import.list + + /* Type 3 LSA Area prefix-list. */ + struct + { + char *name; + struct prefix_list *list; + } plist_in; +#define PREFIX_LIST_IN(A) (A)->plist_in.list +#define PREFIX_NAME_IN(A) (A)->plist_in.name + + struct + { + char *name; + struct prefix_list *list; + } plist_out; +#define PREFIX_LIST_OUT(A) (A)->plist_out.list +#define PREFIX_NAME_OUT(A) (A)->plist_out.name + + /* Shortest Path Tree. */ + struct vertex *spf; + + /* Threads. */ + struct thread *t_router_lsa_self;/* Self-originated router-LSA timer. */ +#ifdef HAVE_OPAQUE_LSA + struct thread *t_opaque_lsa_self; /* Type-10 Opaque-LSAs origin. */ +#endif /* HAVE_OPAQUE_LSA */ + + /* Statistics field. */ + u_int32_t spf_calculation; /* SPF Calculation Count. */ + + /* Router count. */ + u_int32_t abr_count; /* ABR router in this area. */ + u_int32_t asbr_count; /* ASBR router in this area. */ + + /* Counters. */ + u_int32_t act_ints; /* Active interfaces. */ + u_int32_t full_nbrs; /* Fully adjacent neighbors. */ + u_int32_t full_vls; /* Fully adjacent virtual neighbors. */ +}; + +/* OSPF config network structure. */ +struct ospf_network +{ + /* Area ID. */ + struct in_addr area_id; + int format; +}; + +/* OSPF NBMA neighbor structure. */ +struct ospf_nbr_nbma +{ + /* Neighbor IP address. */ + struct in_addr addr; + + /* OSPF interface. */ + struct ospf_interface *oi; + + /* OSPF neighbor structure. */ + struct ospf_neighbor *nbr; + + /* Neighbor priority. */ + u_char priority; + + /* Poll timer value. */ + u_int32_t v_poll; + + /* Poll timer thread. */ + struct thread *t_poll; + + /* State change. */ + u_int32_t state_change; +}; + +/* Macro. */ +#define OSPF_AREA_SAME(X,Y) \ + (memcmp ((X->area_id), (Y->area_id), IPV4_MAX_BYTELEN) == 0) + +#define IS_OSPF_ABR(O) ((O)->flags & OSPF_FLAG_ABR) +#define IS_OSPF_ASBR(O) ((O)->flags & OSPF_FLAG_ASBR) + +#define OSPF_IS_AREA_ID_BACKBONE(I) ((I).s_addr == OSPF_AREA_BACKBONE) +#define OSPF_IS_AREA_BACKBONE(A) OSPF_IS_AREA_ID_BACKBONE ((A)->area_id) + +#ifdef roundup +# define ROUNDUP(val, gran) roundup(val, gran) +#else /* roundup */ +# define ROUNDUP(val, gran) (((val) - 1 | (gran) - 1) + 1) +#endif /* roundup */ + +#define LSA_OPTIONS_GET(area) \ + (((area)->external_routing == OSPF_AREA_DEFAULT) ? OSPF_OPTION_E : 0) +#ifdef HAVE_NSSA +#define LSA_NSSA_GET(area) \ + (((area)->external_routing == OSPF_AREA_NSSA) ? \ + (area)->NSSATranslator : 0) +#endif /* HAVE_NSSA */ + +#define OSPF_TIMER_ON(T,F,V) \ + do { \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), ospf, (V)); \ + } while (0) + +#define OSPF_AREA_TIMER_ON(T,F,V) \ + do { \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), area, (V)); \ + } while (0) + +#define OSPF_POLL_TIMER_ON(T,F,V) \ + do { \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), nbr_nbma, (V)); \ + } while (0) + +#define OSPF_POLL_TIMER_OFF(X) OSPF_TIMER_OFF((X)) + +#define OSPF_TIMER_OFF(X) \ + do { \ + if (X) \ + { \ + thread_cancel (X); \ + (X) = NULL; \ + } \ + } while (0) + +/* Extern variables. */ +extern struct ospf_master *om; +extern struct message ospf_ism_state_msg[]; +extern struct message ospf_nsm_state_msg[]; +extern struct message ospf_lsa_type_msg[]; +extern struct message ospf_link_state_id_type_msg[]; +extern struct message ospf_redistributed_proto[]; +extern struct message ospf_network_type_msg[]; +extern int ospf_ism_state_msg_max; +extern int ospf_nsm_state_msg_max; +extern int ospf_lsa_type_msg_max; +extern int ospf_link_state_id_type_msg_max; +extern int ospf_redistributed_proto_max; +extern int ospf_network_type_msg_max; +extern struct zclient *zclient; +extern struct thread_master *master; +extern int ospf_zlog; + +/* Prototypes. */ +struct ospf *ospf_lookup (); +struct ospf *ospf_get (); +void ospf_finish (struct ospf *); +int ospf_router_id_update_timer (struct thread *); +void ospf_router_id_update (); +int ospf_network_set (struct ospf *, struct prefix_ipv4 *, struct in_addr); +int ospf_network_unset (struct ospf *, struct prefix_ipv4 *, struct in_addr); +int ospf_area_stub_set (struct ospf *, struct in_addr); +int ospf_area_stub_unset (struct ospf *, struct in_addr); +int ospf_area_no_summary_set (struct ospf *, struct in_addr); +int ospf_area_no_summary_unset (struct ospf *, struct in_addr); +int ospf_area_nssa_set (struct ospf *, struct in_addr); +int ospf_area_nssa_unset (struct ospf *, struct in_addr); +int ospf_area_nssa_translator_role_set (struct ospf *, struct in_addr, int); +int ospf_area_export_list_set (struct ospf *, struct ospf_area *, char *); +int ospf_area_export_list_unset (struct ospf *, struct ospf_area *); +int ospf_area_import_list_set (struct ospf *, struct ospf_area *, char *); +int ospf_area_import_list_unset (struct ospf *, struct ospf_area *); +int ospf_area_shortcut_set (struct ospf *, struct ospf_area *, int); +int ospf_area_shortcut_unset (struct ospf *, struct ospf_area *); +int ospf_timers_spf_set (struct ospf *, u_int32_t, u_int32_t); +int ospf_timers_spf_unset (struct ospf *); +int ospf_timers_refresh_set (struct ospf *, int); +int ospf_timers_refresh_unset (struct ospf *); +int ospf_nbr_nbma_set (struct ospf *, struct in_addr); +int ospf_nbr_nbma_unset (struct ospf *, struct in_addr); +int ospf_nbr_nbma_priority_set (struct ospf *, struct in_addr, u_char); +int ospf_nbr_nbma_priority_unset (struct ospf *, struct in_addr); +int ospf_nbr_nbma_poll_interval_set (struct ospf *, struct in_addr, int); +int ospf_nbr_nbma_poll_interval_unset (struct ospf *, struct in_addr); +void ospf_prefix_list_update (struct prefix_list *); +void ospf_init (); +void ospf_if_update (struct ospf *); +void ospf_ls_upd_queue_empty (struct ospf_interface *); +void ospf_terminate (); +void ospf_nbr_nbma_if_update (struct ospf *, struct ospf_interface *); +struct ospf_nbr_nbma *ospf_nbr_nbma_lookup (struct ospf *, struct in_addr); +struct ospf_nbr_nbma *ospf_nbr_nbma_lookup_next (struct ospf *, + struct in_addr *, int); +int ospf_oi_count (struct interface *); + +struct ospf_area *ospf_area_get (struct ospf *, struct in_addr, int); +void ospf_area_check_free (struct ospf *, struct in_addr); +struct ospf_area *ospf_area_lookup_by_area_id (struct ospf *, struct in_addr); +void ospf_area_add_if (struct ospf_area *, struct ospf_interface *); +void ospf_area_del_if (struct ospf_area *, struct ospf_interface *); + +void ospf_route_map_init (); +void ospf_snmp_init (); + +void ospf_master_init (); + +#endif /* _ZEBRA_OSPFD_H */ diff --git a/ripd/ChangeLog b/ripd/ChangeLog new file mode 100644 index 0000000..7bb38d7 --- /dev/null +++ b/ripd/ChangeLog @@ -0,0 +1,763 @@ +2004-05-17 "Michele 'mydecay' Marchetto" + + * ripd.c (rip_rte_process): Fix nexthop and tag reflection bug. + +2004-02-02 Stephan Schweizer + + * Set UDP receive buffer to large size. + +2003-05-18 Kunihiro Ishiguro + + * ripd.h (RIP_PACKET_MAXSIZ): Increase size to 524 to avoid some + implemetation's RIP message size bug. Reported by: Vladimir + Ivaschenko + +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2002-06-30 Kunihiro Ishiguro + + * ripd.c (rip_output_process): When outgoing interface is same as + next hop interface, announce RIPv2 next hop otherwise set next hop + to 0. Revert previous change then take 6WIND way. + +2001-09-14 Akihiro Mizutani + + * ripd.c: RIP enabled interface's route is advertised by default. + +2001-08-28 NOGUCHI Kay + + * rip_snmp.c (rip_ifaddr_delete): Add route_node_lookup() return + value check. + + * rip_interface.c (rip_multicast_leave): Fix bug of multiple IP + address on one interface multicast join/leave bug. + +2001-08-26 NOGUCHI Kay + + * rip_interface.c (no_rip_passive_interface): Add NO_STR. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-06-17 Kunihiro Ishiguro + + * rip_routemap.c (route_match_ip_address_prefix_list): Add match + ip next-hop prefix-list WORD. + +2001-02-18 Kunihiro Ishiguro + + * rip_interface.c (rip_passive_interface_clean): Call + rip_passive_interface_apply_all. + +2001-02-12 Kunihiro Ishiguro + + * ripd.c (rip_response_process): Multicast address nexthop check + is moved from rip_nexthop_check. + +2001-02-08 Matthew Grant + + * rip_interface.c (ipv4_multicast_join): Use + setsockopt_multicast_ipv4. + (ipv4_multicast_leave): Likewise. + (rip_if_ipv4_address_check): Interface which has IPv4 address can + be enabled. + +2001-02-08 Kunihiro Ishiguro + + * rip_interface.c (rip_interface_delete): To support pseudo + interface do not free interface structure. + * ripd.c (rip_output_process): If output interface is in simple + password authentication mode, we need space for authentication + data. + +2001-02-01 Kunihiro Ishiguro + + * ripd.c (rip_nexthop_check): Fix multicast address nexthop check. + + * zebra-0.91 is released. + +2001-01-27 Kunihiro Ishiguro + + * ripd.c (show_ip_rip): Show metric infinity route's timeout. + (rip_rte_process): If current route is metric infinity, route is + replaced with received rte. + (rip_redistribute_delete): When redistribute route is deleted, + perform poisoned reverse. + (rip_redistribute_withdraw): Likewise. + +2001-01-25 Kunihiro Ishiguro + + * ripd.c (rip_response_process): RIPv2 routing table entry with + non directly reachable nexthop was dropped. The code is changed + to treat it as 0.0.0.0 nexthop. + (rip_destination_check): Check net 0 address destination. + (rip_nexthop_check): New function for checking nexthop address + validity. + +2001-01-15 Kunihiro Ishiguro + + * ripd.c (rip_request_process): Triggered update only send changed + route. + + * rip_interface.c: Delete RIP_API part until new implementation + comes out. + + * rip_snmp.: Likewise. + + * rip_zebra.c: Likewise. + + * ripd.c: Likewise. + +2001-01-11 Kunihiro Ishiguro + + * rip_interface.c (rip_if_init): Remove HAVE_IF_PSEUDO part. + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + +2001-01-01 Kunihiro Ishiguro + + * ripd.h (RIP_VTYSH_PATH): Change "/tmp/ripd" to "/tmp/.ripd". + +2000-12-25 David Lipovkov + + * ripd.c (rip_rte_process): When a route is in garbage collection + process (invalid with metric 16) and a router receives the same + route with valid metric then route was not installed into zebra + rib, but only into ripd rib. Moreover , it will never get into + zebra rib, because ripd wrongly assumes it's already there. + (rip_redistribute_add): When doing redistribute into rip other + route (e.g. connected) and the same route exists in ripd rib we + changed it in place - bug. Now we don't forget to remove old route + from zebra. + (rip_timeout): When removing routes from zebra I made sure that we + remove route with the metric we have in zebra and not the new + one. It doesn't make a difference now,but could be significant + when multipath support is done. + +2000-12-25 David Lipovkov + + * rip_zebra.c (rip_metric_unset): Fix bug of metric value unset. + +2000-11-25 Frank van Maarseveen + + * ripd.c (rip_request_process): Check passive flag of the + interface. + +2000-11-23 Frank van Maarseveen + + * rip_interface.c (rip_multicast_join): When IP_ADD_MEMBERSHIP + failed do not set runnning flag to the interface. + +2000-11-16 Kunihiro Ishiguro + + * ripd.c (rip_output_process): Memory leak related classfull + network generation is fixed. + +2000-11-16 Frank van Maarseveen + + * rip_interface.c (if_check_address): Obsolete pointopoint address + check is removed. + +2000-11-02 Frank van Maarseveen + + * rip_interface.c (if_check_address): Add pointopoint address + check. + (rip_interface_up): Add check for passive interface when interface + goes up. + +2000-10-23 Jochen Friedrich + + * rip_snmp.c: rip_oid and ripd_oid are used in smux_open after it + is registered. So those variables must be static. + +2000-10-19 Kunihiro Ishiguro + + * rip_interface.c: Change to "no ip rip (send|receive)" command + accept version number argument. + +2000-10-17 Akihiro Mizutani + + * rip_routemap.c (route_set_ip_nexthop_compile): Change "match ip + next-hop" from IP address to access-list name. + +2000-10-17 Kunihiro Ishiguro + + * rip_peer.c: Change ot use linklist.c instaed of newlist.c. + +2000-10-16 Kunihiro Ishiguro + + * rip_offset.c: Change to use linklist.c instead of newlist.c. + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-09-26 Akihiro Mizutani + + * rip_routemap.c (match_ip_nexthop): Add next-hop format check. + +2000-09-18 David Lipovkov + + * rip_interface.c (ripd_api_get_if_rx_version): Corrects rip SNMP + and rip API functions dealing with rip version. + + * rip_snmp.c (Status_Valid): SNMPv2-TC TEXTUAL-CONVENTION. + +2000-09-10 Kunihiro Ishiguro + + * rip_snmp.c (rip2IfLookup): Use rip_ifaddr_lookup_next() instead + of rip_if_lookup_next(). + + * rip_interface.c (rip_enable_network_lookup): Interface enable + check by interface's address with /32 prefix. + + * ripd.c (rip_read): When RIP is configured with authentication + and no authentication in incoming packet, drop the packet. + + * rip_interface.c (rip_interface_reset): RIP_AUTH_SIMPLE_PASSWORD + is default mode of authentication. + (rip_interface_new): Likewise. + (no_ip_rip_authentication_mode): Likewise. + + * ripd.c (rip_read): Likewise. + +2000-09-10 David Lipovkov + + * rip_snmp.c: Set ASN_INTEGER v->type where it is needed. + +2000-09-08 Kunihiro Ishiguro + + * ripd.c (rip_auth_simple_password): Simple password + authentication using key-chain. + (rip_write_rte): Likewise. + + * rip_interface.c (ip_rip_authentication_key_chain): Add check for + authentication string configuration. + +2000-09-08 Akihiro Mizutani + + * ripd.c (rip_write_rte): Add check for ri->auth_str. + +2000-09-07 Kunihiro Ishiguro + + * ripd_api.h: New file is added. + +2000-08-22 Kunihiro Ishiguro + + * ripd.c (rip_rte_process): rip_route_process() is renamed to + rip_rte_process() to clarify meanings of the function. + rip_route_process() is newly added to process RIP route selection. + +2000-08-18 Kunihiro Ishiguro + + * ripd.c (rip_incoming_filter): Extract incoming filter code to + function from rip_route_process(). Add check for all interface + filter. + (rip_outgoing_filter): Extract incoming filter code to function + from rip_output_process(). Add check for all interface filter. + + * rip_zebra.c (rip_redistribute_clean): Reset redistribute status + when "no router rip" is performed. + + * rip_interface.c (rip_interface_clean): Reset interface's RIP + enable status. + +2000-08-17 Kunihiro Ishiguro + + * ripd.c (rip_route_process): When metric infinity is received the + route is removed from service immediately. + (rip_timeout): Likewise. + (rip_garbage_collect): Do not delete route in garbage collection. + (rip_output_process): Check metric_out exceed metric infinity. + + * zebra-0.88 is released. + +2000-08-15 Kunihiro Ishiguro + + * ripd.c (rip_distance_apply): Unlock node when there is matched + node. + +2000-08-13 Akihiro Mizutani + + * rip_routemap.c (match_ip_nexthop): Add check for IP address + validness. + (no_set_metric): Add new ALIAS. + +2000-08-07 Kunihiro Ishiguro + + * ripd.h (struct rip ): Add distance. + +2000-08-05 Kunihiro Ishiguro + + * rip_zebra.c (rip_zebra_ipv4_add): Use new Zebra api to register + routes. Pass RIP metric value to zebra. + +2000-08-02 Kunihiro Ishiguro + + * rip_main.c (main): Make struct thread thread from global + variable to local variable in main. + +2000-08-06 Kunihiro Ishiguro + + * ripd.c (rip_packet_dump): Add MD5 authentication dump function. + (rip_auth_md5): RIP MD5 authentication packet receive works. + +2000-08-02 David Lipovkov + + * rip_interface.c (rip_if_init): Install interface "pseudo" + commands. + (rip_interface_delete): Do not call if_delete() when interface is + pseudo interface. + +2000-07-31 Kunihiro Ishiguro + + * rip_interface.c (ip_rip_authentication_mode): "ip rip + authentication mode (md5|text)" is added. + (ip_rip_authentication_key_chain): "ip rip authentication + key-chain KEY-CHAIN" is added. + (rip_interface_clean): Clean all interface configuration. + (rip_interface_reset): Reset all interface configuration. + (rip_clean_network): Clean rip_enable_network. + + * ripd.h (struct rip_interface): Add key_chain member. + + * ripd.c: Include md5-gnu.h. + +2000-07-30 Kunihiro Ishiguro + + * ripd.h (RIP_NO_AUTH): Change RIP_NO_AUTH value from 1 to 0. + + * ripd.c (rip_authentication): Use RIP_AUTH_SIMPLE_PASSWORD + instead of raw value 2. + (rip_write_rte): Likewise. + (rip_write_rte): Check ri->auth_type instead of ri->auth_str. + +2000-07-30 David Lipovkov + + * rip_interface.c (rip_if_down): Do not delete ZEBRA_ROUTE_KERNEL + route. + +2000-07-27 Kunihiro Ishiguro + + * ripd.c (rip_update_process): Add "passive-interface" command. + + * ripd.h (struct rip_interface): Add passive member to struct + rip_interface. + +2000-07-24 Kunihiro Ishiguro + + * rip_interface.c (rip_if_init): Multiple RIP routes for one + prefix change. The codes are enclosed by #ifdef NEW_RIP_TABLE. + +2000-07-24 Akihiro Mizutani + + * rip_interface.c (rip_if_init): Use install_default() for + INTERFACE_NODE. + +2000-07-24 Kunihiro Ishiguro + + * ripd.c: First update timer will be invoked in two seconds. + +2000-07-09 Jochen Friedrich + + * rip_snmp.c: Local function definitions to static. Add INTEGER + ASN_INTEGER and TIMETICKS ASN_TIMETICKS definition. + (rip2PeerLookup): Peer with domain lookup implemented. + (rip2PeerTable): Temporary disable RIP2PEERLASTUPDATE value + support due to unknown SNMP agent startup time. + +2000-07-05 Kunihiro Ishiguro + + * ripd.h: Sweep obsolete definitions. + + * rip_interface.c (rip_split_horizon): Add "ip split-horizon" + command. + + * ripd.c (rip_output_process): Remove split_horizon argument. + (rip_update_process): Likewise. + + * ripd.h (struct rip_interface): Add split_horizon flag to struct + rip_interface. + +2000-07-04 Akihiro Mizutani + + * ripd.c (rip_version): Change VERSION to <1-2>. + Add "no version" command. + +2000-07-03 Kunihiro Ishiguro + + * rip_zebra.c (rip_redistribute_type_metric): "redistribute TYPE + metric <0-16>" command is added. + + * rip_routemap.c (route_set_metric): Set metric_set when metric is + modified. + + * ripd.h (struct rip_info): To check route-map set metric or not, + new member metric_set is added to struct rip_info. + + * ripd.c (rip_route_process): Move metric handling code from + rip_response_process() to rip_route_process(). + (rip_output_process): Set output offset-list metric. + +2000-07-02 Kunihiro Ishiguro + + * rip_offset.c (rip_offset_list): New file for offset-list. + +2000-07-02 Akihiro Mizutani + + * ripd.h (struct rip ): Add default_metric. + + * ripd.c (rip_default_metric): "default-metric <1-16>" command is + added. + (config_write_rip): Change configuration order. + + * rip_zebra.c: Fix help strings. + +2000-07-02 David Lipovkov + + * rip_interface.c (rip_if_init): Add IF_DELETE_HOOK. + +2000-07-01 Kunihiro Ishiguro + + * ripd.c (rip_output_process): If specified route-map does not + exist, it treated as deny all. + +2000-06-30 Kunihiro Ishiguro + + * rip_routemap.c (rip_route_map_init): Call rip_route_map_update + when route-map is deleted. + +2000-06-28 Kunihiro Ishiguro + + * rip_routemap.c (set_metric): For consistency with bgpd's set + metric, value range is set to <0-4294967295>. + +2000-06-28 David Lipovkov + + * rip_routemap.c (rip_route_map_update): Add check for rip is + enabled or not for avoid core dump. + + * rip_debug.c (debug_rip_packet_direct): Fix bug of setting + rip_debug_packet flag. + +2000-06-13 David Lipovkov + + * rip_interface.c (rip_interface_delete): All work is done in + rip_if_down(). + +2000-06-06 Kunihiro Ishiguro + + * ripd.c (rip_redistribute_delete): Fix bug of missing + route_unlock_node() when redistribute route is not found. + +2000-06-05 Akihirof Mizutani + + * rip_debug.c (rip_debug_init): Disable show debugging in + VIEW_NODE like other protocol daemon. + + * rip_routemap.c: Change command argument to more comprehensive. + + METRIC -> <0-16> + IFNAME -> WORD + IP_ADDR -> A.B.C.D + ACCSESS_LIST -> WORD + +2000-06-05 David Lipovkov + + * rip_interface.c (rip_interface_delete): Delete all routes + include static and kernel through the interface , because even if + the interface is added again there is no guarantee that it will + get the same ifindex as before. + +2000-05-31 Akihirof Mizutani + + * rip_debug.c: Fix rip debug help string. + +2000-04-27 Mirko Karanovic + + * rip_interface.c (rip_interface_down): Remove interface from + multicast group when interface goes down. + +2000-04-03 David Lipovkov + + * rip_interface.c (rip_interface_down): Implemented rip functions + for interface up/down events: rip_interface_up() and + rip_interface_down() + +2000-03-16 David Lipovkov + + * rip_zebra.c (rip_zclient_init): Added rip functions for + interface up/down events. + +2000-02-15 Hidetoshi Shimokawa + + * ripd.c (rip_write_rte): "set metic" in route-map has no effect + for RIPv1 in ripd. It worked fine for RIPv2. + +2000-01-17 Kunihiro Ishiguro + + * ripd.c (show_ip_protocols_rip): Fix bug of "show ip protocls" + mis-display RIP version. + + * ripd.h (struct rip_peer): Add timeout thread to rip_peer + structure. + +2000-01-16 Kunihiro Ishiguro + + * rip_peer.c: Add new file for supporting RIP peer. + +1999-12-26 David Lipovkov + + * ripd.c (rip_authentication): RIP authantication string is 16 + bytes long. + +1999-12-10 Kunihiro Ishiguro + + * ripd.c (rip_read): Add check for minimum packet length. + Authentication check is moved from rip_process_response() to + rip_read(). Patch from David Lipovkov is + applied then add rte number check by Kunihiro Ishiguro + . + +1999-12-07 Kunihiro Ishiguro + + * ripd.c (rip_response_process): In case of packet is RIPv2 and + network is non zero and netmask is zero, apply netmask rule as + same as RIPv1. + +1999-11-06 Kunihiro Ishiguro + + * ripd.c (rip_timers): Fix bug of timers basic argument format. + +1999-11-03 Kunihiro Ishiguro + + * rip_snmp.c (rip2IfConfAddress): Forgot to include + RIP2IFCONFDOMAIN. + +1999-10-28 Kunihiro Ishiguro + + * ripd.h (struct rip_peer): New structure added. + +1999-10-26 Kunihiro Ishiguro + + * rip_zebra.c (rip_zebra_ipv4_add): Increment + rip_global_route_changes when route change occur. + (rip_zebra_ipv4_delete): Likewise. + + * ripd.c (rip_request_process): Increment rip_global_queries when + reply to the query is sent. + +1999-10-25 Kunihiro Ishiguro + + * rip_debug.c (rip_debug_reset): Reset function added. + + * ripd.c (rip_update_process): Logging bug is fixed. + +1999-10-10 Marc Boucher + + * ripd.c (config_write_rip): Add config_write_distribute() call. + +1999-09-29 Kunihiro Ishiguro + + * ripd.c (rip_distribute_update): Fix bug of access-list + prefix-list updates. + +1999-09-10 VOP + + * rip_zebra.c: Add redistribute route-map feature. + +1999-09-10 Kunihiro Ishiguro + + * ripd.c (rip_response_process): Add check for given prefix is + given mask applied one. + +1999-09-03 VOP + + * rip_interface.c (rip_interface_multicast_set): Bug fix about + setting multicast interface. + +1999-09-02 VOP + + * rip_routemap.c: New file added. + +1999-09-02 Kunihiro Ishiguro + + * ripd.c (show_ip_protocols_rip): Show next update time. + (show_ip_protocols_rip): Show redistribute information. + +1999-08-25 Kunihiro Ishiguro + + * RIPv2-MIB.txt: New file added. + + * rip_snmp.c: New file added. + +1999-08-24 Kunihiro Ishiguro + + * rip_interface.c (ip_rip_authentication_string): RIPv2 + authentication command is added. + +1999-08-23 Kunihiro Ishiguro + + * rip_interface.c (rip_interface_multicast_set): Process of + setting IP_MULTICAST_IF on specific interface. + + * ripd.c (rip_read): Add packet size check. + +1999-08-16 Kunihiro Ishiguro + + * ripd.c (rip_request_process): Fill in RIP_METRIC_INFINITY with + network byte order using htonl (). + (rip_response_process): Pass host byte order address to IN_CLASSC + and IN_CLASSB macro. + +1999-08-08 davidm@nbase.co.il (David Mozes) + + * rip_zebra.c (rip_zebra_read_ipv4): Fix split horizon problem. + +1999-07-03 Kunihiro Ishiguro + + * ripd.c (rip_timer_set): Function added. + +1999-07-01 Kunihiro Ishiguro + + * rip_debug.c: New file added. + rip_debug.h: New file added. + +1999-07-01 Rick Payne + + * rip_zebra.c (zebra_init): Install standard commands to + ZEBRA_NODE. + +1999-06-01 David Luyer + + * ripd.c (rip_process_route): Add support for RIP version 1. + +1999-05-29 Kunihiro Ishiguro + + * rip_zebra.c: Change to use lib/zclient.[ch]. + +1999-05-20 Carlos Alberto Barcenilla + + * ripd.c (rip_add_route): Change the existance route's metric check + to the condition specified by RFC2453. + +1999-05-17 Carlos Alberto Barcenilla + + * ripd.c (rip_process_route): Add the if metric to the route metric. + + * ripd.c (rip_add_route): Deleted add if metric to the route. + +1999-05-16 Carlos Alberto Barcenilla + + * rip_interface.c (if_valid_neighbor): New function. + + * ripd.c (rip_process_route): Added check whether the datagram + is from a valid neighbor. + +1999-05-15 Kunihiro Ishiguro + + * ripd.c (rip_process_route): Set interface pointer to rinfo. + +1999-05-15 Carlos Alberto Barcenilla + + * ripd.c (rip_check_address): Unicast and not net 0 or 127 check + added. + +1999-05-14 Stephen R. van den Berg + + * rip_main.c (signal_init): SIGTERM call sigint. + (sigint): Loggging more better message. + +1999-05-10 Kunihiro Ishiguro + + * ripd.c (rip_add_route): Fix previous route_unlock_node() chenge. + + * rip_main.c (main): Change default zlog output to ZLOG_STDOUT for + debugging. + +1999-05-09 Patrick Koppen + + * rip_interface.c (rip_request): Fix old semantics for fetching + connected address. + + * ripd.c (rip_add_route): Update timer when the route is updated. + +1999-05-09 Carlos Alberto Barcenilla + + * rip_zebra.c (struct zebra): Add ridist_static, ridist_connect, + redist_rip, redist_ripng. + + * rip_zebra.c (zebra_create): Updated for current zebra method. + + * ripd.c (rip_add_route): Add missing route_unlock_node(). + +1999-05-03 Kunihiro Ishiguro + + * ripd.c (rip_add_route): Add metric check. Reported by Carlos + Alberto Barcenilla . + +1999-02-18 Peter Galbavy + + * syslog support added + +1998-12-13 Kunihiro Ishiguro + + * ripd.c (rip_announce_func): Apply new lib functions. + +1998-12-09 Kunihiro Ishiguro + + * ripd.c (config_write_rip): Delete vector v argument. + * rip_zebra.c (config_write_zebra): Likewise. + * rip_interface.c (interface_config_write): Likewise. + +1998-09-07 Kunihiro Ishiguro + + * rip_announce.c (rip_rib_close): When ripd terminates delete all + added route. + +1998-09-01 Kunihiro Ishiguro + + * rip_interface.c: return read packet size. + +1998-05-18 Yamshita TAKAO + + * ripd.h: Modify for compile on Solaris. + +1998-05-07 Kunihiro Ishiguro + + * ripd.c: DEFUN function return CMD_SUCCESS. + change xmalloc to XMALLOC macro. + +1998-05-03 Kunihiro Ishiguro + + * rip_main.c: change CONFDIR to SYSCONFDIR. + +1998-05-01 Kunihiro Ishiguro + + * .cvsignore: added. + +1998-02-04 Kunihiro Ishiguro + + * rip_interface.c (config_write_interface): correct ADVERTISE spell. + + * rip_main.c (main): add usage() and make cleanup. + +1998-01-05 Kunihiro Ishiguro + + * ripd.c (rip_version): add rip version command. + +1998-01-04 Kunihiro Ishiguro + + * rip_interface.c (zebra_get_interface): added to get + interface's information. + + * ChangeLog: create. diff --git a/ripd/Makefile.am b/ripd/Makefile.am new file mode 100644 index 0000000..fd25485 --- /dev/null +++ b/ripd/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +noinst_LIBRARIES = librip.a +sbin_PROGRAMS = ripd + +librip_a_SOURCES = \ + ripd.c rip_zebra.c rip_interface.c rip_debug.c rip_snmp.c \ + rip_routemap.c rip_peer.c rip_offset.c + +noinst_HEADERS = \ + ripd.h rip_debug.h + +ripd_SOURCES = \ + rip_main.c $(librip_a_SOURCES) + +ripd_LDADD = ../lib/libzebra.a + +sysconf_DATA = ripd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) RIPv2-MIB.txt + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done diff --git a/ripd/Makefile.in b/ripd/Makefile.in new file mode 100644 index 0000000..2fe359f --- /dev/null +++ b/ripd/Makefile.in @@ -0,0 +1,418 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CPP = @CPP@ +CURSES = @CURSES@ +DEPDIR = @DEPDIR@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LIBPAM = @LIBPAM@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA = @INSTALL@ -m 600 + +noinst_LIBRARIES = librip.a +sbin_PROGRAMS = ripd + +librip_a_SOURCES = \ + ripd.c rip_zebra.c rip_interface.c rip_debug.c rip_snmp.c \ + rip_routemap.c rip_peer.c rip_offset.c + + +noinst_HEADERS = \ + ripd.h rip_debug.h + + +ripd_SOURCES = \ + rip_main.c $(librip_a_SOURCES) + + +ripd_LDADD = ../lib/libzebra.a + +sysconf_DATA = ripd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) RIPv2-MIB.txt +subdir = ripd +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +librip_a_AR = $(AR) cru +librip_a_LIBADD = +am_librip_a_OBJECTS = ripd.$(OBJEXT) rip_zebra.$(OBJEXT) \ + rip_interface.$(OBJEXT) rip_debug.$(OBJEXT) rip_snmp.$(OBJEXT) \ + rip_routemap.$(OBJEXT) rip_peer.$(OBJEXT) rip_offset.$(OBJEXT) +librip_a_OBJECTS = $(am_librip_a_OBJECTS) +sbin_PROGRAMS = ripd$(EXEEXT) +PROGRAMS = $(sbin_PROGRAMS) + +am__objects_1 = ripd.$(OBJEXT) rip_zebra.$(OBJEXT) \ + rip_interface.$(OBJEXT) rip_debug.$(OBJEXT) rip_snmp.$(OBJEXT) \ + rip_routemap.$(OBJEXT) rip_peer.$(OBJEXT) rip_offset.$(OBJEXT) +am_ripd_OBJECTS = rip_main.$(OBJEXT) $(am__objects_1) +ripd_OBJECTS = $(am_ripd_OBJECTS) +ripd_DEPENDENCIES = ../lib/libzebra.a +ripd_LDFLAGS = +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/rip_debug.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/rip_interface.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/rip_main.Po ./$(DEPDIR)/rip_offset.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/rip_peer.Po ./$(DEPDIR)/rip_routemap.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/rip_snmp.Po ./$(DEPDIR)/rip_zebra.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ripd.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CFLAGS = @CFLAGS@ +DIST_SOURCES = $(librip_a_SOURCES) $(ripd_SOURCES) +DATA = $(sysconf_DATA) + +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in +SOURCES = $(librip_a_SOURCES) $(ripd_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign ripd/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +librip.a: $(librip_a_OBJECTS) $(librip_a_DEPENDENCIES) + -rm -f librip.a + $(librip_a_AR) librip.a $(librip_a_OBJECTS) $(librip_a_LIBADD) + $(RANLIB) librip.a +sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \ + rm -f $(DESTDIR)$(sbindir)/$$f; \ + done + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) +ripd$(EXEEXT): $(ripd_OBJECTS) $(ripd_DEPENDENCIES) + @rm -f ripd$(EXEEXT) + $(LINK) $(ripd_LDFLAGS) $(ripd_OBJECTS) $(ripd_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_debug.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_interface.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_offset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_peer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_routemap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_snmp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_zebra.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripd.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `cygpath -w $<` +CCDEPMODE = @CCDEPMODE@ +uninstall-info-am: +sysconfDATA_INSTALL = $(INSTALL_DATA) + +uninstall-sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(sysconf_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \ + rm -f $(DESTDIR)$(sysconfdir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-sbinPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-sbinPROGRAMS install-sysconfDATA + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \ + uninstall-sysconfDATA + +.PHONY: GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES clean-sbinPROGRAMS distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-sbinPROGRAMS install-strip install-sysconfDATA \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic tags uninstall uninstall-am \ + uninstall-info-am uninstall-sbinPROGRAMS uninstall-sysconfDATA + + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/ripd/RIPv2-MIB.txt b/ripd/RIPv2-MIB.txt new file mode 100644 index 0000000..6c92fb5 --- /dev/null +++ b/ripd/RIPv2-MIB.txt @@ -0,0 +1,530 @@ + RIPv2-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Counter32, + TimeTicks, IpAddress FROM SNMPv2-SMI + TEXTUAL-CONVENTION, RowStatus FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF + mib-2 FROM RFC1213-MIB; + + -- This MIB module uses the extended OBJECT-TYPE macro as + -- defined in [9]. + + rip2 MODULE-IDENTITY + LAST-UPDATED "9407272253Z" -- Wed Jul 27 22:53:04 PDT 1994 + ORGANIZATION "IETF RIP-II Working Group" + CONTACT-INFO + " Fred Baker + Postal: Cisco Systems + 519 Lado Drive + Santa Barbara, California 93111 + Tel: +1 805 681 0115 + E-Mail: fbaker@cisco.com + + Postal: Gary Malkin + Xylogics, Inc. + 53 Third Avenue + Burlington, MA 01803 + + Phone: (617) 272-8140 + EMail: gmalkin@Xylogics.COM" + DESCRIPTION + "The MIB module to describe the RIP2 Version 2 Protocol" + ::= { mib-2 23 } + + -- RIP-2 Management Information Base + + -- the RouteTag type represents the contents of the + -- Route Domain field in the packet header or route entry. + -- The use of the Route Domain is deprecated. + + RouteTag ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "the RouteTag type represents the contents of the Route Domain + field in the packet header or route entry" + SYNTAX OCTET STRING (SIZE (2)) + +--4.1 Global Counters + +-- The RIP-2 Globals Group. +-- Implementation of this group is mandatory for systems +-- which implement RIP-2. + +-- These counters are intended to facilitate debugging quickly +-- changing routes or failing neighbors + +rip2Globals OBJECT IDENTIFIER ::= { rip2 1 } + + rip2GlobalRouteChanges OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of route changes made to the IP Route + Database by RIP. This does not include the refresh + of a route's age." + ::= { rip2Globals 1 } + + rip2GlobalQueries OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of responses sent to RIP queries + from other systems." + ::= { rip2Globals 2 } + +--4.2 RIP Interface Tables + +-- RIP Interfaces Groups +-- Implementation of these Groups is mandatory for systems +-- which implement RIP-2. + +-- The RIP Interface Status Table. + + rip2IfStatTable OBJECT-TYPE + SYNTAX SEQUENCE OF Rip2IfStatEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of subnets which require separate + status monitoring in RIP." + ::= { rip2 2 } + + rip2IfStatEntry OBJECT-TYPE + SYNTAX Rip2IfStatEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A Single Routing Domain in a single Subnet." + INDEX { rip2IfStatAddress } + ::= { rip2IfStatTable 1 } + + Rip2IfStatEntry ::= + SEQUENCE { + rip2IfStatAddress + IpAddress, + rip2IfStatRcvBadPackets + Counter32, + rip2IfStatRcvBadRoutes + Counter32, + rip2IfStatSentUpdates + Counter32, + rip2IfStatStatus + RowStatus + } + + rip2IfStatAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of this system on the indicated + subnet. For unnumbered interfaces, the value 0.0.0.N, + where the least significant 24 bits (N) is the ifIndex + for the IP Interface in network byte order." + ::= { rip2IfStatEntry 1 } + + rip2IfStatRcvBadPackets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of RIP response packets received by + the RIP process which were subsequently discarded + for any reason (e.g. a version 0 packet, or an + unknown command type)." + ::= { rip2IfStatEntry 2 } + + rip2IfStatRcvBadRoutes OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of routes, in valid RIP packets, + which were ignored for any reason (e.g. unknown + address family, or invalid metric)." + ::= { rip2IfStatEntry 3 } + + rip2IfStatSentUpdates OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of triggered RIP updates actually + sent on this interface. This explicitly does + NOT include full updates sent containing new + information." + ::= { rip2IfStatEntry 4 } + + rip2IfStatStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Writing invalid has the effect of deleting + this interface." + ::= { rip2IfStatEntry 5 } + +-- The RIP Interface Configuration Table. + + rip2IfConfTable OBJECT-TYPE + SYNTAX SEQUENCE OF Rip2IfConfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of subnets which require separate + configuration in RIP." + ::= { rip2 3 } + + rip2IfConfEntry OBJECT-TYPE + SYNTAX Rip2IfConfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A Single Routing Domain in a single Subnet." + INDEX { rip2IfConfAddress } + ::= { rip2IfConfTable 1 } + + Rip2IfConfEntry ::= + SEQUENCE { + rip2IfConfAddress + IpAddress, + rip2IfConfDomain + RouteTag, + rip2IfConfAuthType + INTEGER, + rip2IfConfAuthKey + OCTET STRING (SIZE(0..16)), + rip2IfConfSend + INTEGER, + rip2IfConfReceive + INTEGER, + rip2IfConfDefaultMetric + INTEGER, + rip2IfConfStatus + RowStatus, + rip2IfConfSrcAddress + IpAddress + } + + rip2IfConfAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of this system on the indicated + subnet. For unnumbered interfaces, the value 0.0.0.N, + where the least significant 24 bits (N) is the ifIndex + for the IP Interface in network byte order." + ::= { rip2IfConfEntry 1 } + + rip2IfConfDomain OBJECT-TYPE + SYNTAX RouteTag + MAX-ACCESS read-create + STATUS obsolete + DESCRIPTION + "Value inserted into the Routing Domain field + of all RIP packets sent on this interface." + DEFVAL { '0000'h } + ::= { rip2IfConfEntry 2 } + + rip2IfConfAuthType OBJECT-TYPE + SYNTAX INTEGER { + noAuthentication (1), + simplePassword (2), + md5 (3) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The type of Authentication used on this + interface." + DEFVAL { noAuthentication } + ::= { rip2IfConfEntry 3 } + + rip2IfConfAuthKey OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(0..16)) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The value to be used as the Authentication Key + whenever the corresponding instance of + rip2IfConfAuthType has a value other than + noAuthentication. A modification of the corresponding + instance of rip2IfConfAuthType does not modify + the rip2IfConfAuthKey value. If a string shorter + than 16 octets is supplied, it will be left- + justified and padded to 16 octets, on the right, + with nulls (0x00). + + Reading this object always results in an OCTET + STRING of length zero; authentication may not + be bypassed by reading the MIB object." + DEFVAL { ''h } + ::= { rip2IfConfEntry 4 } + + rip2IfConfSend OBJECT-TYPE + SYNTAX INTEGER { + doNotSend (1), + ripVersion1 (2), + rip1Compatible (3), + ripVersion2 (4), + ripV1Demand (5), + ripV2Demand (6) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "What the router sends on this interface. + ripVersion1 implies sending RIP updates compliant + with RFC 1058. rip1Compatible implies + broadcasting RIP-2 updates using RFC 1058 route + subsumption rules. ripVersion2 implies + multicasting RIP-2 updates. ripV1Demand indicates + the use of Demand RIP on a WAN interface under RIP + Version 1 rules. ripV2Demand indicates the use of + Demand RIP on a WAN interface under Version 2 rules." + DEFVAL { rip1Compatible } + ::= { rip2IfConfEntry 5 } + + rip2IfConfReceive OBJECT-TYPE + SYNTAX INTEGER { + rip1 (1), + rip2 (2), + rip1OrRip2 (3), + doNotRecieve (4) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This indicates which version of RIP updates + are to be accepted. Note that rip2 and + rip1OrRip2 implies reception of multicast + packets." + DEFVAL { rip1OrRip2 } + ::= { rip2IfConfEntry 6 } + + rip2IfConfDefaultMetric OBJECT-TYPE + SYNTAX INTEGER ( 0..15 ) + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "This variable indicates the metric that is to + be used for the default route entry in RIP updates + originated on this interface. A value of zero + indicates that no default route should be + originated; in this case, a default route via + another router may be propagated." + ::= { rip2IfConfEntry 7 } + + rip2IfConfStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Writing invalid has the effect of deleting + this interface." + ::= { rip2IfConfEntry 8 } + + rip2IfConfSrcAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The IP Address this system will use as a source + address on this interface. If it is a numbered + interface, this MUST be the same value as + rip2IfConfAddress. On unnumbered interfaces, + it must be the value of rip2IfConfAddress for + some interface on the system." + ::= { rip2IfConfEntry 9 } + +--4.3 Peer Table + +-- Peer Table + +-- The RIP Peer Group +-- Implementation of this Group is Optional + +-- This group provides information about active peer +-- relationships intended to assist in debugging. An +-- active peer is a router from which a valid RIP +-- updated has been heard in the last 180 seconds. + + rip2PeerTable OBJECT-TYPE + SYNTAX SEQUENCE OF Rip2PeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of RIP Peers." + ::= { rip2 4 } + + rip2PeerEntry OBJECT-TYPE + SYNTAX Rip2PeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information regarding a single routing peer." + INDEX { rip2PeerAddress, rip2PeerDomain } + ::= { rip2PeerTable 1 } + + Rip2PeerEntry ::= + SEQUENCE { + rip2PeerAddress + IpAddress, + rip2PeerDomain + RouteTag, + rip2PeerLastUpdate + TimeTicks, + rip2PeerVersion + INTEGER, + rip2PeerRcvBadPackets + Counter32, + rip2PeerRcvBadRoutes + Counter32 + } + + rip2PeerAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address that the peer is using as its source + address. Note that on an unnumbered link, this may + not be a member of any subnet on the system." + ::= { rip2PeerEntry 1 } + + rip2PeerDomain OBJECT-TYPE + SYNTAX RouteTag + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value in the Routing Domain field in RIP + packets received from the peer. As domain suuport + is deprecated, this must be zero." + ::= { rip2PeerEntry 2 } + + rip2PeerLastUpdate OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of sysUpTime when the most recent + RIP update was received from this system." + ::= { rip2PeerEntry 3 } + + rip2PeerVersion OBJECT-TYPE + SYNTAX INTEGER ( 0..255 ) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The RIP version number in the header of the + last RIP packet received." + ::= { rip2PeerEntry 4 } + + rip2PeerRcvBadPackets OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of RIP response packets from this + peer discarded as invalid." + ::= { rip2PeerEntry 5 } + + + rip2PeerRcvBadRoutes OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of routes from this peer that were + ignored because the entry format was invalid." + ::= { rip2PeerEntry 6 } + +-- conformance information + +rip2Conformance OBJECT IDENTIFIER ::= { rip2 5 } + +rip2Groups OBJECT IDENTIFIER ::= { rip2Conformance 1 } +rip2Compliances OBJECT IDENTIFIER ::= { rip2Conformance 2 } + +-- compliance statements +rip2Compliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement " + MODULE -- this module + MANDATORY-GROUPS { + rip2GlobalGroup, + rip2IfStatGroup, + rip2IfConfGroup, + rip2PeerGroup + } + GROUP rip2GlobalGroup + DESCRIPTION + "This group defines global controls for RIP-II systems." + GROUP rip2IfStatGroup + DESCRIPTION + "This group defines interface statistics for RIP-II systems." + GROUP rip2IfConfGroup + DESCRIPTION + "This group defines interface configuration for RIP-II systems." + GROUP rip2PeerGroup + DESCRIPTION + "This group defines peer information for RIP-II systems." + ::= { rip2Compliances 1 } + +-- units of conformance + +rip2GlobalGroup OBJECT-GROUP + OBJECTS { + rip2GlobalRouteChanges, + rip2GlobalQueries + } + STATUS current + DESCRIPTION + "This group defines global controls for RIP-II systems." + ::= { rip2Groups 1 } +rip2IfStatGroup OBJECT-GROUP + OBJECTS { + rip2IfStatAddress, + rip2IfStatRcvBadPackets, + rip2IfStatRcvBadRoutes, + rip2IfStatSentUpdates, + rip2IfStatStatus + } + STATUS current + DESCRIPTION + "This group defines interface statistics for RIP-II systems." + ::= { rip2Groups 2 } +rip2IfConfGroup OBJECT-GROUP + OBJECTS { + rip2IfConfAddress, + rip2IfConfAuthType, + rip2IfConfAuthKey, + rip2IfConfSend, + rip2IfConfReceive, + rip2IfConfDefaultMetric, + rip2IfConfStatus, + rip2IfConfSrcAddress + } + STATUS current + DESCRIPTION + "This group defines interface configuration for RIP-II systems." + ::= { rip2Groups 3 } +rip2PeerGroup OBJECT-GROUP + OBJECTS { + rip2PeerAddress, + rip2PeerDomain, + rip2PeerLastUpdate, + rip2PeerVersion, + rip2PeerRcvBadPackets, + rip2PeerRcvBadRoutes + } + STATUS current + DESCRIPTION + "This group defines peer information for RIP-II systems." + ::= { rip2Groups 4 } +END diff --git a/ripd/rip_debug.c b/ripd/rip_debug.c new file mode 100644 index 0000000..3f4c389 --- /dev/null +++ b/ripd/rip_debug.c @@ -0,0 +1,291 @@ +/* RIP debug routines + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include "command.h" +#include "ripd/rip_debug.h" + +/* For debug statement. */ +unsigned long rip_debug_event = 0; +unsigned long rip_debug_packet = 0; +unsigned long rip_debug_zebra = 0; + +DEFUN (debug_rip_events, + debug_rip_events_cmd, + "debug rip events", + DEBUG_STR + RIP_STR + "RIP events\n") +{ + rip_debug_event = RIP_DEBUG_EVENT; + return CMD_WARNING; +} + +DEFUN (debug_rip_packet, + debug_rip_packet_cmd, + "debug rip packet", + DEBUG_STR + RIP_STR + "RIP packet\n") +{ + rip_debug_packet = RIP_DEBUG_PACKET; + rip_debug_packet |= RIP_DEBUG_SEND; + rip_debug_packet |= RIP_DEBUG_RECV; + return CMD_SUCCESS; +} + +DEFUN (debug_rip_packet_direct, + debug_rip_packet_direct_cmd, + "debug rip packet (recv|send)", + DEBUG_STR + RIP_STR + "RIP packet\n" + "RIP receive packet\n" + "RIP send packet\n") +{ + rip_debug_packet |= RIP_DEBUG_PACKET; + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + rip_debug_packet |= RIP_DEBUG_SEND; + if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + rip_debug_packet |= RIP_DEBUG_RECV; + rip_debug_packet &= ~RIP_DEBUG_DETAIL; + return CMD_SUCCESS; +} + +DEFUN (debug_rip_packet_detail, + debug_rip_packet_detail_cmd, + "debug rip packet (recv|send) detail", + DEBUG_STR + RIP_STR + "RIP packet\n" + "RIP receive packet\n" + "RIP send packet\n" + "Detailed information display\n") +{ + rip_debug_packet |= RIP_DEBUG_PACKET; + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + rip_debug_packet |= RIP_DEBUG_SEND; + if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + rip_debug_packet |= RIP_DEBUG_RECV; + rip_debug_packet |= RIP_DEBUG_DETAIL; + return CMD_SUCCESS; +} + +DEFUN (debug_rip_zebra, + debug_rip_zebra_cmd, + "debug rip zebra", + DEBUG_STR + RIP_STR + "RIP and ZEBRA communication\n") +{ + rip_debug_zebra = RIP_DEBUG_ZEBRA; + return CMD_WARNING; +} + +DEFUN (no_debug_rip_events, + no_debug_rip_events_cmd, + "no debug rip events", + NO_STR + DEBUG_STR + RIP_STR + "RIP events\n") +{ + rip_debug_event = 0; + return CMD_SUCCESS; +} + +DEFUN (no_debug_rip_packet, + no_debug_rip_packet_cmd, + "no debug rip packet", + NO_STR + DEBUG_STR + RIP_STR + "RIP packet\n") +{ + rip_debug_packet = 0; + return CMD_SUCCESS; +} + +DEFUN (no_debug_rip_packet_direct, + no_debug_rip_packet_direct_cmd, + "no debug rip packet (recv|send)", + NO_STR + DEBUG_STR + RIP_STR + "RIP packet\n" + "RIP option set for receive packet\n" + "RIP option set for send packet\n") +{ + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + { + if (IS_RIP_DEBUG_RECV) + rip_debug_packet &= ~RIP_DEBUG_SEND; + else + rip_debug_packet = 0; + } + else if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + { + if (IS_RIP_DEBUG_SEND) + rip_debug_packet &= ~RIP_DEBUG_RECV; + else + rip_debug_packet = 0; + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_rip_zebra, + no_debug_rip_zebra_cmd, + "no debug rip zebra", + NO_STR + DEBUG_STR + RIP_STR + "RIP and ZEBRA communication\n") +{ + rip_debug_zebra = 0; + return CMD_WARNING; +} + +DEFUN (show_debugging_rip, + show_debugging_rip_cmd, + "show debugging rip", + SHOW_STR + DEBUG_STR + RIP_STR) +{ + vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE); + + if (IS_RIP_DEBUG_EVENT) + vty_out (vty, " RIP event debugging is on%s", VTY_NEWLINE); + + if (IS_RIP_DEBUG_PACKET) + { + if (IS_RIP_DEBUG_SEND && IS_RIP_DEBUG_RECV) + { + vty_out (vty, " RIP packet%s debugging is on%s", + IS_RIP_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + } + else + { + if (IS_RIP_DEBUG_SEND) + vty_out (vty, " RIP packet send%s debugging is on%s", + IS_RIP_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + else + vty_out (vty, " RIP packet receive%s debugging is on%s", + IS_RIP_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + } + } + + if (IS_RIP_DEBUG_ZEBRA) + vty_out (vty, " RIP zebra debugging is on%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +/* Debug node. */ +struct cmd_node debug_node = + { + DEBUG_NODE, + "", /* Debug node has no interface. */ + 1 + }; + +int +config_write_debug (struct vty *vty) +{ + int write = 0; + + if (IS_RIP_DEBUG_EVENT) + { + vty_out (vty, "debug rip events%s", VTY_NEWLINE); + write++; + } + if (IS_RIP_DEBUG_PACKET) + { + if (IS_RIP_DEBUG_SEND && IS_RIP_DEBUG_RECV) + { + vty_out (vty, "debug rip packet%s%s", + IS_RIP_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + write++; + } + else + { + if (IS_RIP_DEBUG_SEND) + vty_out (vty, "debug rip packet send%s%s", + IS_RIP_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + else + vty_out (vty, "debug rip packet recv%s%s", + IS_RIP_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + write++; + } + } + if (IS_RIP_DEBUG_ZEBRA) + { + vty_out (vty, "debug rip zebra%s", VTY_NEWLINE); + write++; + } + return write; +} + +void +rip_debug_reset () +{ + rip_debug_event = 0; + rip_debug_packet = 0; + rip_debug_zebra = 0; +} + +void +rip_debug_init () +{ + rip_debug_event = 0; + rip_debug_packet = 0; + rip_debug_zebra = 0; + + install_node (&debug_node, config_write_debug); + + install_element (ENABLE_NODE, &debug_rip_events_cmd); + install_element (ENABLE_NODE, &debug_rip_packet_cmd); + install_element (ENABLE_NODE, &debug_rip_packet_direct_cmd); + install_element (ENABLE_NODE, &debug_rip_packet_detail_cmd); + install_element (ENABLE_NODE, &debug_rip_zebra_cmd); + install_element (ENABLE_NODE, &no_debug_rip_events_cmd); + install_element (ENABLE_NODE, &no_debug_rip_packet_cmd); + install_element (ENABLE_NODE, &no_debug_rip_packet_direct_cmd); + install_element (ENABLE_NODE, &no_debug_rip_zebra_cmd); + + install_element (CONFIG_NODE, &debug_rip_events_cmd); + install_element (CONFIG_NODE, &debug_rip_packet_cmd); + install_element (CONFIG_NODE, &debug_rip_packet_direct_cmd); + install_element (CONFIG_NODE, &debug_rip_packet_detail_cmd); + install_element (CONFIG_NODE, &debug_rip_zebra_cmd); + install_element (CONFIG_NODE, &no_debug_rip_events_cmd); + install_element (CONFIG_NODE, &no_debug_rip_packet_cmd); + install_element (CONFIG_NODE, &no_debug_rip_packet_direct_cmd); + install_element (CONFIG_NODE, &no_debug_rip_zebra_cmd); + + install_element (ENABLE_NODE, &show_debugging_rip_cmd); +} diff --git a/ripd/rip_debug.h b/ripd/rip_debug.h new file mode 100644 index 0000000..3b44d0c --- /dev/null +++ b/ripd/rip_debug.h @@ -0,0 +1,54 @@ +/* RIP debug routines + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RIP_DEBUG_H +#define _ZEBRA_RIP_DEBUG_H + +/* RIP debug event flags. */ +#define RIP_DEBUG_EVENT 0x01 + +/* RIP debug packet flags. */ +#define RIP_DEBUG_PACKET 0x01 +#define RIP_DEBUG_SEND 0x20 +#define RIP_DEBUG_RECV 0x40 +#define RIP_DEBUG_DETAIL 0x80 + +/* RIP debug zebra flags. */ +#define RIP_DEBUG_ZEBRA 0x01 + +/* Debug related macro. */ +#define IS_RIP_DEBUG_EVENT (rip_debug_event & RIP_DEBUG_EVENT) + +#define IS_RIP_DEBUG_PACKET (rip_debug_packet & RIP_DEBUG_PACKET) +#define IS_RIP_DEBUG_SEND (rip_debug_packet & RIP_DEBUG_SEND) +#define IS_RIP_DEBUG_RECV (rip_debug_packet & RIP_DEBUG_RECV) +#define IS_RIP_DEBUG_DETAIL (rip_debug_packet & RIP_DEBUG_DETAIL) + +#define IS_RIP_DEBUG_ZEBRA (rip_debug_zebra & RIP_DEBUG_ZEBRA) + +extern unsigned long rip_debug_event; +extern unsigned long rip_debug_packet; +extern unsigned long rip_debug_zebra; + +void rip_debug_init (); +void rip_debug_reset (); + +#endif /* _ZEBRA_RIP_DEBUG_H */ diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c new file mode 100644 index 0000000..8c2d9d7 --- /dev/null +++ b/ripd/rip_interface.c @@ -0,0 +1,2001 @@ +/* Interface related function for RIP. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "command.h" +#include "if.h" +#include "sockunion.h" +#include "prefix.h" +#include "memory.h" +#include "network.h" +#include "table.h" +#include "log.h" +#include "stream.h" +#include "thread.h" +#include "zclient.h" +#include "filter.h" +#include "sockopt.h" + +#include "zebra/connected.h" + +#include "ripd/ripd.h" +#include "ripd/rip_debug.h" + +void rip_enable_apply (struct interface *); +void rip_passive_interface_apply (struct interface *); +int rip_if_down(struct interface *ifp); + +struct message ri_version_msg[] = +{ + {RI_RIP_VERSION_1, "1"}, + {RI_RIP_VERSION_2, "2"}, + {RI_RIP_VERSION_1_AND_2, "1 2"}, + {0, NULL} +}; + +/* RIP enabled network vector. */ +vector rip_enable_interface; + +/* RIP enabled interface table. */ +struct route_table *rip_enable_network; + +/* Vector to store passive-interface name. */ +vector Vrip_passive_interface; + +/* Join to the RIP version 2 multicast group. */ +int +ipv4_multicast_join (int sock, + struct in_addr group, + struct in_addr ifa, + unsigned int ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (sock, + IP_ADD_MEMBERSHIP, + ifa, + group.s_addr, + ifindex); + + if (ret < 0) + zlog (NULL, LOG_INFO, "can't setsockopt IP_ADD_MEMBERSHIP %s", + strerror (errno)); + + return ret; +} + +/* Leave from the RIP version 2 multicast group. */ +int +ipv4_multicast_leave (int sock, + struct in_addr group, + struct in_addr ifa, + unsigned int ifindex) +{ + int ret; + + ret = setsockopt_multicast_ipv4 (sock, + IP_DROP_MEMBERSHIP, + ifa, + group.s_addr, + ifindex); + + if (ret < 0) + zlog (NULL, LOG_INFO, "can't setsockopt IP_DROP_MEMBERSHIP"); + + return ret; +} + +/* Allocate new RIP's interface configuration. */ +struct rip_interface * +rip_interface_new () +{ + struct rip_interface *ri; + + ri = XMALLOC (MTYPE_RIP_INTERFACE, sizeof (struct rip_interface)); + memset (ri, 0, sizeof (struct rip_interface)); + + /* Default authentication type is simple password for Cisco + compatibility. */ + /* ri->auth_type = RIP_NO_AUTH; */ + ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; + + /* Set default split-horizon behavior. If the interface is Frame + Relay or SMDS is enabled, the default value for split-horizon is + off. But currently Zebra does detect Frame Relay or SMDS + interface. So all interface is set to split horizon. */ + ri->split_horizon_default = 1; + ri->split_horizon = ri->split_horizon_default; + + return ri; +} + +void +rip_interface_multicast_set (int sock, struct interface *ifp) +{ + int ret; + listnode node; + struct servent *sp; + struct sockaddr_in from; + + for (node = listhead (ifp->connected); node; nextnode (node)) + { + struct prefix_ipv4 *p; + struct connected *connected; + struct in_addr addr; + + connected = getdata (node); + p = (struct prefix_ipv4 *) connected->address; + + if (p->family == AF_INET) + { + addr = p->prefix; + + if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF, + addr, 0, ifp->ifindex) < 0) + { + zlog_warn ("Can't setsockopt IP_MULTICAST_IF to fd %d", sock); + return; + } + + /* Bind myself. */ + memset (&from, 0, sizeof (struct sockaddr_in)); + + /* Set RIP port. */ + sp = getservbyname ("router", "udp"); + if (sp) + from.sin_port = sp->s_port; + else + from.sin_port = htons (RIP_PORT_DEFAULT); + + /* Address shoud be any address. */ + from.sin_family = AF_INET; + from.sin_addr = addr; +#ifdef HAVE_SIN_LEN + from.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + + ret = bind (sock, (struct sockaddr *) & from, + sizeof (struct sockaddr_in)); + if (ret < 0) + { + zlog_warn ("Can't bind socket: %s", strerror (errno)); + return; + } + + return; + + } + } +} + +/* Send RIP request packet to specified interface. */ +void +rip_request_interface_send (struct interface *ifp, u_char version) +{ + struct sockaddr_in to; + + /* RIPv2 support multicast. */ + if (version == RIPv2 && if_is_multicast (ifp)) + { + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("multicast request on %s", ifp->name); + + rip_request_send (NULL, ifp, version); + return; + } + + /* RIPv1 and non multicast interface. */ + if (if_is_pointopoint (ifp) || if_is_broadcast (ifp)) + { + listnode cnode; + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("broadcast request to %s", ifp->name); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + struct prefix_ipv4 *p; + struct connected *connected; + + connected = getdata (cnode); + p = (struct prefix_ipv4 *) connected->destination; + + if (p->family == AF_INET) + { + memset (&to, 0, sizeof (struct sockaddr_in)); + to.sin_port = htons (RIP_PORT_DEFAULT); + to.sin_addr = p->prefix; + + rip_request_send (&to, ifp, version); + } + } + } +} + +/* This will be executed when interface goes up. */ +void +rip_request_interface (struct interface *ifp) +{ + struct rip_interface *ri; + + /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */ + if (if_is_loopback (ifp)) + return; + + /* If interface is down, don't send RIP packet. */ + if (! if_is_up (ifp)) + return; + + /* Fetch RIP interface information. */ + ri = ifp->info; + + + /* If there is no version configuration in the interface, + use rip's version setting. */ + if (ri->ri_send == RI_RIP_UNSPEC) + { + if (rip->version == RIPv1) + rip_request_interface_send (ifp, RIPv1); + else + rip_request_interface_send (ifp, RIPv2); + } + /* If interface has RIP version configuration use it. */ + else + { + if (ri->ri_send & RIPv1) + rip_request_interface_send (ifp, RIPv1); + if (ri->ri_send & RIPv2) + rip_request_interface_send (ifp, RIPv2); + } +} + +/* Send RIP request to the neighbor. */ +void +rip_request_neighbor (struct in_addr addr) +{ + struct sockaddr_in to; + + memset (&to, 0, sizeof (struct sockaddr_in)); + to.sin_port = htons (RIP_PORT_DEFAULT); + to.sin_addr = addr; + + rip_request_send (&to, NULL, rip->version); +} + +/* Request routes at all interfaces. */ +void +rip_request_neighbor_all () +{ + struct route_node *rp; + + if (! rip) + return; + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("request to the all neighbor"); + + /* Send request to all neighbor. */ + for (rp = route_top (rip->neighbor); rp; rp = route_next (rp)) + if (rp->info) + rip_request_neighbor (rp->p.u.prefix4); +} + +/* Multicast packet receive socket. */ +int +rip_multicast_join (struct interface *ifp, int sock) +{ + struct rip_interface *ri; + listnode cnode; + + ri = ifp->info; + + if (if_is_up (ifp) && if_is_multicast (ifp)) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("multicast join at %s", ifp->name); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + struct prefix_ipv4 *p; + struct connected *connected; + struct in_addr group; + + connected = getdata (cnode); + p = (struct prefix_ipv4 *) connected->address; + + if (p->family != AF_INET) + continue; + + group.s_addr = htonl (INADDR_RIP_GROUP); + if (ipv4_multicast_join (sock, group, p->prefix, ifp->ifindex) < 0) + return -1; + else + { + ri->joined_multicast = 1; + return 0; + } + } + } + return 0; +} + +/* Leave from multicast group. */ +void +rip_multicast_leave (struct interface *ifp, int sock) +{ + struct rip_interface *ri; + listnode cnode; + + ri = ifp->info; + + if (ri->joined_multicast) + { + ri->joined_multicast = 0; + if (IS_RIP_DEBUG_EVENT) + zlog_info ("multicast leave from %s", ifp->name); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + struct prefix_ipv4 *p; + struct connected *connected; + struct in_addr group; + + connected = getdata (cnode); + p = (struct prefix_ipv4 *) connected->address; + + if (p->family != AF_INET) + continue; + + group.s_addr = htonl (INADDR_RIP_GROUP); + if (ipv4_multicast_leave (sock, group, p->prefix, ifp->ifindex) == 0) + return; + } + } +} + +/* Is there and address on interface that I could use ? */ +int +rip_if_ipv4_address_check (struct interface *ifp) +{ + struct listnode *nn; + struct connected *connected; + int count = 0; + + for (nn = listhead (ifp->connected); nn; nextnode (nn)) + if ((connected = getdata (nn)) != NULL) + { + struct prefix *p; + + p = connected->address; + + if (p->family == AF_INET) + { + count++; + } + } + + return count; +} + + + + +/* Does this address belongs to me ? */ +int +if_check_address (struct in_addr addr) +{ + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + listnode cnode; + struct interface *ifp; + + ifp = getdata (node); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + struct connected *connected; + struct prefix_ipv4 *p; + + connected = getdata (cnode); + p = (struct prefix_ipv4 *) connected->address; + + if (p->family != AF_INET) + continue; + + if (IPV4_ADDR_CMP (&p->prefix, &addr) == 0) + return 1; + } + } + return 0; +} + +/* is this address from a valid neighbor? (RFC2453 - Sec. 3.9.2) */ +int +if_valid_neighbor (struct in_addr addr) +{ + listnode node; + struct connected *connected = NULL; + struct prefix_ipv4 *p; + + for (node = listhead (iflist); node; nextnode (node)) + { + listnode cnode; + struct interface *ifp; + + ifp = getdata (node); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + struct prefix *pxn = NULL; /* Prefix of the neighbor */ + struct prefix *pxc = NULL; /* Prefix of the connected network */ + + connected = getdata (cnode); + + if (if_is_pointopoint (ifp)) + { + p = (struct prefix_ipv4 *) connected->address; + + if (p && p->family == AF_INET) + { + if (IPV4_ADDR_SAME (&p->prefix, &addr)) + return 1; + + p = (struct prefix_ipv4 *) connected->destination; + if (p && IPV4_ADDR_SAME (&p->prefix, &addr)) + return 1; + } + } + else + { + p = (struct prefix_ipv4 *) connected->address; + + if (p->family != AF_INET) + continue; + + pxn = prefix_new(); + pxn->family = AF_INET; + pxn->prefixlen = 32; + pxn->u.prefix4 = addr; + + pxc = prefix_new(); + prefix_copy(pxc, (struct prefix *) p); + apply_mask(pxc); + + if (prefix_match (pxc, pxn)) + { + prefix_free (pxn); + prefix_free (pxc); + return 1; + } + prefix_free(pxc); + prefix_free(pxn); + } + } + } + return 0; +} + +/* Inteface link down message processing. */ +int +rip_interface_down (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + struct stream *s; + + s = zclient->ibuf; + + /* zebra_interface_state_read() updates interface structure in + iflist. */ + ifp = zebra_interface_state_read(s); + + if (ifp == NULL) + return 0; + + rip_if_down(ifp); + + if (IS_RIP_DEBUG_ZEBRA) + zlog_info ("interface %s index %d flags %ld metric %d mtu %d is down", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + return 0; +} + +/* Inteface link up message processing */ +int +rip_interface_up (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + + /* zebra_interface_state_read () updates interface structure in + iflist. */ + ifp = zebra_interface_state_read (zclient->ibuf); + + if (ifp == NULL) + return 0; + + if (IS_RIP_DEBUG_ZEBRA) + zlog_info ("interface %s index %d flags %ld metric %d mtu %d is up", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + /* Check if this interface is RIP enabled or not.*/ + rip_enable_apply (ifp); + + /* Check for a passive interface */ + rip_passive_interface_apply (ifp); + + /* Apply distribute list to the all interface. */ + rip_distribute_update_interface (ifp); + + return 0; +} + +/* Inteface addition message from zebra. */ +int +rip_interface_add (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read (zclient->ibuf); + + if (IS_RIP_DEBUG_ZEBRA) + zlog_info ("interface add %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + /* Check if this interface is RIP enabled or not.*/ + rip_enable_apply (ifp); + + /* Apply distribute list to the all interface. */ + rip_distribute_update_interface (ifp); + + /* rip_request_neighbor_all (); */ + + return 0; +} + +int +rip_interface_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + struct stream *s; + + + s = zclient->ibuf; + /* zebra_interface_state_read() updates interface structure in iflist */ + ifp = zebra_interface_state_read(s); + + if (ifp == NULL) + return 0; + + if (if_is_up (ifp)) { + rip_if_down(ifp); + } + + zlog_info("interface delete %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + /* To support pseudo interface do not free interface structure. */ + /* if_delete(ifp); */ + + return 0; +} + +void +rip_interface_clean () +{ + listnode node; + struct interface *ifp; + struct rip_interface *ri; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ri = ifp->info; + + ri->enable_network = 0; + ri->enable_interface = 0; + ri->running = 0; + + if (ri->t_wakeup) + { + thread_cancel (ri->t_wakeup); + ri->t_wakeup = NULL; + } + } +} + +void +rip_interface_reset () +{ + listnode node; + struct interface *ifp; + struct rip_interface *ri; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ri = ifp->info; + + ri->enable_network = 0; + ri->enable_interface = 0; + ri->running = 0; + + ri->ri_send = RI_RIP_UNSPEC; + ri->ri_receive = RI_RIP_UNSPEC; + + /* ri->auth_type = RIP_NO_AUTH; */ + ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; + + if (ri->auth_str) + { + free (ri->auth_str); + ri->auth_str = NULL; + } + if (ri->key_chain) + { + free (ri->key_chain); + ri->key_chain = NULL; + } + + ri->split_horizon = 0; + ri->split_horizon_default = 0; + + ri->list[RIP_FILTER_IN] = NULL; + ri->list[RIP_FILTER_OUT] = NULL; + + ri->prefix[RIP_FILTER_IN] = NULL; + ri->prefix[RIP_FILTER_OUT] = NULL; + + if (ri->t_wakeup) + { + thread_cancel (ri->t_wakeup); + ri->t_wakeup = NULL; + } + + ri->recv_badpackets = 0; + ri->recv_badroutes = 0; + ri->sent_updates = 0; + + ri->passive = 0; + } +} + +int +rip_if_down(struct interface *ifp) +{ + struct route_node *rp; + struct rip_info *rinfo; + struct rip_interface *ri = NULL; + if (rip) + { + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + { + /* Routes got through this interface. */ + if (rinfo->ifindex == ifp->ifindex && + rinfo->type == ZEBRA_ROUTE_RIP && + rinfo->sub_type == RIP_ROUTE_RTE) + { + rip_zebra_ipv4_delete ((struct prefix_ipv4 *) &rp->p, + &rinfo->nexthop, + rinfo->ifindex); + + rip_redistribute_delete (rinfo->type,rinfo->sub_type, + (struct prefix_ipv4 *)&rp->p, + rinfo->ifindex); + } + else + { + /* All redistributed routes but static and system */ + if ((rinfo->ifindex == ifp->ifindex) && + (rinfo->type != ZEBRA_ROUTE_STATIC) && + (rinfo->type != ZEBRA_ROUTE_SYSTEM)) + rip_redistribute_delete (rinfo->type,rinfo->sub_type, + (struct prefix_ipv4 *)&rp->p, + rinfo->ifindex); + } + } + } + + ri = ifp->info; + + if (ri->running) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("turn off %s", ifp->name); + + /* Leave from multicast group. */ + rip_multicast_leave (ifp, rip->sock); + + ri->running = 0; + } + + return 0; +} + +/* Needed for stop RIP process. */ +void +rip_if_down_all () +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + rip_if_down (ifp); + } +} + +int +rip_interface_address_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *ifc; + struct prefix *p; + + ifc = zebra_interface_address_add_read (zclient->ibuf); + + if (ifc == NULL) + return 0; + + p = ifc->address; + + if (p->family == AF_INET) + { + if (IS_RIP_DEBUG_ZEBRA) + zlog_info ("connected address %s/%d is added", + inet_ntoa (p->u.prefix4), p->prefixlen); + + /* Check is this interface is RIP enabled or not.*/ + rip_enable_apply (ifc->ifp); + +#ifdef HAVE_SNMP + rip_ifaddr_add (ifc->ifp, ifc); +#endif /* HAVE_SNMP */ + } + + return 0; +} + +int +rip_interface_address_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *ifc; + struct prefix *p; + + ifc = zebra_interface_address_delete_read (zclient->ibuf); + + if (ifc) + { + p = ifc->address; + if (p->family == AF_INET) + { + if (IS_RIP_DEBUG_ZEBRA) + + zlog_info ("connected address %s/%d is deleted", + inet_ntoa (p->u.prefix4), p->prefixlen); + +#ifdef HAVE_SNMP + rip_ifaddr_delete (ifc->ifp, ifc); +#endif /* HAVE_SNMP */ + + /* Check if this interface is RIP enabled or not.*/ + rip_enable_apply (ifc->ifp); + } + + connected_free (ifc); + + } + + return 0; +} + +/* Check interface is enabled by network statement. */ +int +rip_enable_network_lookup (struct interface *ifp) +{ + struct listnode *nn; + struct connected *connected; + struct prefix_ipv4 address; + + for (nn = listhead (ifp->connected); nn; nextnode (nn)) + if ((connected = getdata (nn)) != NULL) + { + struct prefix *p; + struct route_node *node; + + p = connected->address; + + if (p->family == AF_INET) + { + address.family = AF_INET; + address.prefix = p->u.prefix4; + address.prefixlen = IPV4_MAX_BITLEN; + + node = route_node_match (rip_enable_network, + (struct prefix *)&address); + if (node) + { + route_unlock_node (node); + return 1; + } + } + } + return -1; +} + +/* Add RIP enable network. */ +int +rip_enable_network_add (struct prefix *p) +{ + struct route_node *node; + + node = route_node_get (rip_enable_network, p); + + if (node->info) + { + route_unlock_node (node); + return -1; + } + else + node->info = "enabled"; + + return 1; +} + +/* Delete RIP enable network. */ +int +rip_enable_network_delete (struct prefix *p) +{ + struct route_node *node; + + node = route_node_lookup (rip_enable_network, p); + if (node) + { + node->info = NULL; + + /* Unlock info lock. */ + route_unlock_node (node); + + /* Unlock lookup lock. */ + route_unlock_node (node); + + return 1; + } + return -1; +} + +/* Check interface is enabled by ifname statement. */ +int +rip_enable_if_lookup (char *ifname) +{ + int i; + char *str; + + for (i = 0; i < vector_max (rip_enable_interface); i++) + if ((str = vector_slot (rip_enable_interface, i)) != NULL) + if (strcmp (str, ifname) == 0) + return i; + return -1; +} + +/* Add interface to rip_enable_if. */ +int +rip_enable_if_add (char *ifname) +{ + int ret; + + ret = rip_enable_if_lookup (ifname); + if (ret >= 0) + return -1; + + vector_set (rip_enable_interface, strdup (ifname)); + + return 1; +} + +/* Delete interface from rip_enable_if. */ +int +rip_enable_if_delete (char *ifname) +{ + int index; + char *str; + + index = rip_enable_if_lookup (ifname); + if (index < 0) + return -1; + + str = vector_slot (rip_enable_interface, index); + free (str); + vector_unset (rip_enable_interface, index); + + return 1; +} + +/* Join to multicast group and send request to the interface. */ +int +rip_interface_wakeup (struct thread *t) +{ + struct interface *ifp; + struct rip_interface *ri; + + /* Get interface. */ + ifp = THREAD_ARG (t); + + ri = ifp->info; + ri->t_wakeup = NULL; + + /* Join to multicast group. */ + if (rip_multicast_join (ifp, rip->sock) < 0) + { + zlog_err ("multicast join failed, interface %s not running", ifp->name); + return 0; + } + + /* Set running flag. */ + ri->running = 1; + + /* Send RIP request to the interface. */ + rip_request_interface (ifp); + + return 0; +} + +int rip_redistribute_check (int); + +void +rip_connect_set (struct interface *ifp, int set) +{ + struct listnode *nn; + struct connected *connected; + struct prefix_ipv4 address; + + for (nn = listhead (ifp->connected); nn; nextnode (nn)) + if ((connected = getdata (nn)) != NULL) + { + struct prefix *p; + p = connected->address; + + if (p->family != AF_INET) + continue; + + address.family = AF_INET; + address.prefix = p->u.prefix4; + address.prefixlen = p->prefixlen; + apply_mask_ipv4 (&address); + + if (set) + rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, + &address, connected->ifp->ifindex, NULL); + else + { + rip_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, + &address, connected->ifp->ifindex); + if (rip_redistribute_check (ZEBRA_ROUTE_CONNECT)) + rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_REDISTRIBUTE, + &address, connected->ifp->ifindex, NULL); + } + } +} + +/* Update interface status. */ +void +rip_enable_apply (struct interface *ifp) +{ + int ret; + struct rip_interface *ri = NULL; + + /* Check interface. */ + if (if_is_loopback (ifp)) + return; + + if (! if_is_up (ifp)) + return; + + ri = ifp->info; + + /* Check network configuration. */ + ret = rip_enable_network_lookup (ifp); + + /* If the interface is matched. */ + if (ret > 0) + ri->enable_network = 1; + else + ri->enable_network = 0; + + /* Check interface name configuration. */ + ret = rip_enable_if_lookup (ifp->name); + if (ret >= 0) + ri->enable_interface = 1; + else + ri->enable_interface = 0; + + /* any interface MUST have an IPv4 address */ + if ( ! rip_if_ipv4_address_check (ifp) ) + { + ri->enable_network = 0; + ri->enable_interface = 0; + } + + /* Update running status of the interface. */ + if (ri->enable_network || ri->enable_interface) + { + if (! ri->running) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("turn on %s", ifp->name); + + /* Add interface wake up thread. */ + if (! ri->t_wakeup) + ri->t_wakeup = thread_add_timer (master, rip_interface_wakeup, + ifp, 1); + rip_connect_set (ifp, 1); + } + } + else + { + if (ri->running) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("turn off %s", ifp->name); + + /* Might as well clean up the route table as well */ + rip_if_down(ifp); + + ri->running = 0; + rip_connect_set (ifp, 0); + } + } +} + +/* Apply network configuration to all interface. */ +void +rip_enable_apply_all () +{ + struct interface *ifp; + listnode node; + + /* Check each interface. */ + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + rip_enable_apply (ifp); + } +} + +int +rip_neighbor_lookup (struct sockaddr_in *from) +{ + struct prefix_ipv4 p; + struct route_node *node; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefix = from->sin_addr; + p.prefixlen = IPV4_MAX_BITLEN; + + node = route_node_lookup (rip->neighbor, (struct prefix *) &p); + if (node) + { + route_unlock_node (node); + return 1; + } + return 0; +} + +/* Add new RIP neighbor to the neighbor tree. */ +int +rip_neighbor_add (struct prefix_ipv4 *p) +{ + struct route_node *node; + + node = route_node_get (rip->neighbor, (struct prefix *) p); + + if (node->info) + return -1; + + node->info = rip->neighbor; + + return 0; +} + +/* Delete RIP neighbor from the neighbor tree. */ +int +rip_neighbor_delete (struct prefix_ipv4 *p) +{ + struct route_node *node; + + /* Lock for look up. */ + node = route_node_lookup (rip->neighbor, (struct prefix *) p); + if (! node) + return -1; + + node->info = NULL; + + /* Unlock lookup lock. */ + route_unlock_node (node); + + /* Unlock real neighbor information lock. */ + route_unlock_node (node); + + return 0; +} + +/* Clear all network and neighbor configuration. */ +void +rip_clean_network () +{ + int i; + char *str; + struct route_node *rn; + + /* rip_enable_network. */ + for (rn = route_top (rip_enable_network); rn; rn = route_next (rn)) + if (rn->info) + { + rn->info = NULL; + route_unlock_node (rn); + } + + /* rip_enable_interface. */ + for (i = 0; i < vector_max (rip_enable_interface); i++) + if ((str = vector_slot (rip_enable_interface, i)) != NULL) + { + free (str); + vector_slot (rip_enable_interface, i) = NULL; + } +} + +/* Utility function for looking up passive interface settings. */ +int +rip_passive_interface_lookup (char *ifname) +{ + int i; + char *str; + + for (i = 0; i < vector_max (Vrip_passive_interface); i++) + if ((str = vector_slot (Vrip_passive_interface, i)) != NULL) + if (strcmp (str, ifname) == 0) + return i; + return -1; +} + +void +rip_passive_interface_apply (struct interface *ifp) +{ + int ret; + struct rip_interface *ri; + + ri = ifp->info; + + ret = rip_passive_interface_lookup (ifp->name); + if (ret < 0) + ri->passive = 0; + else + ri->passive = 1; +} + +void +rip_passive_interface_apply_all () +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + rip_passive_interface_apply (ifp); + } +} + +/* Passive interface. */ +int +rip_passive_interface_set (struct vty *vty, char *ifname) +{ + if (rip_passive_interface_lookup (ifname) >= 0) + return CMD_WARNING; + + vector_set (Vrip_passive_interface, strdup (ifname)); + + rip_passive_interface_apply_all (); + + return CMD_SUCCESS; +} + +int +rip_passive_interface_unset (struct vty *vty, char *ifname) +{ + int i; + char *str; + + i = rip_passive_interface_lookup (ifname); + if (i < 0) + return CMD_WARNING; + + str = vector_slot (Vrip_passive_interface, i); + free (str); + vector_unset (Vrip_passive_interface, i); + + rip_passive_interface_apply_all (); + + return CMD_SUCCESS; +} + +/* Free all configured RIP passive-interface settings. */ +void +rip_passive_interface_clean () +{ + int i; + char *str; + + for (i = 0; i < vector_max (Vrip_passive_interface); i++) + if ((str = vector_slot (Vrip_passive_interface, i)) != NULL) + { + free (str); + vector_slot (Vrip_passive_interface, i) = NULL; + } + rip_passive_interface_apply_all (); +} + +/* RIP enable network or interface configuration. */ +DEFUN (rip_network, + rip_network_cmd, + "network (A.B.C.D/M|WORD)", + "Enable routing on an IP network\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Interface name\n") +{ + int ret; + struct prefix_ipv4 p; + + ret = str2prefix_ipv4 (argv[0], &p); + + if (ret) + ret = rip_enable_network_add ((struct prefix *) &p); + else + ret = rip_enable_if_add (argv[0]); + + if (ret < 0) + { + vty_out (vty, "There is a same network configuration %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + rip_enable_apply_all (); + + return CMD_SUCCESS; +} + +/* RIP enable network or interface configuration. */ +DEFUN (no_rip_network, + no_rip_network_cmd, + "no network (A.B.C.D/M|WORD)", + NO_STR + "Enable routing on an IP network\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Interface name\n") +{ + int ret; + struct prefix_ipv4 p; + + ret = str2prefix_ipv4 (argv[0], &p); + + if (ret) + ret = rip_enable_network_delete ((struct prefix *) &p); + else + ret = rip_enable_if_delete (argv[0]); + + if (ret < 0) + { + vty_out (vty, "Can't find network configuration %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + rip_enable_apply_all (); + + return CMD_SUCCESS; +} + +/* RIP neighbor configuration set. */ +DEFUN (rip_neighbor, + rip_neighbor_cmd, + "neighbor A.B.C.D", + "Specify a neighbor router\n" + "Neighbor address\n") +{ + int ret; + struct prefix_ipv4 p; + + ret = str2prefix_ipv4 (argv[0], &p); + + if (ret <= 0) + { + vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rip_neighbor_add (&p); + + return CMD_SUCCESS; +} + +/* RIP neighbor configuration unset. */ +DEFUN (no_rip_neighbor, + no_rip_neighbor_cmd, + "no neighbor A.B.C.D", + NO_STR + "Specify a neighbor router\n" + "Neighbor address\n") +{ + int ret; + struct prefix_ipv4 p; + + ret = str2prefix_ipv4 (argv[0], &p); + + if (ret <= 0) + { + vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rip_neighbor_delete (&p); + + return CMD_SUCCESS; +} + +DEFUN (ip_rip_receive_version, + ip_rip_receive_version_cmd, + "ip rip receive version (1|2)", + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1. */ + if (atoi (argv[0]) == 1) + { + ri->ri_receive = RI_RIP_VERSION_1; + return CMD_SUCCESS; + } + if (atoi (argv[0]) == 2) + { + ri->ri_receive = RI_RIP_VERSION_2; + return CMD_SUCCESS; + } + return CMD_WARNING; +} + +DEFUN (ip_rip_receive_version_1, + ip_rip_receive_version_1_cmd, + "ip rip receive version 1 2", + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1 and 2. */ + ri->ri_receive = RI_RIP_VERSION_1_AND_2; + return CMD_SUCCESS; +} + +DEFUN (ip_rip_receive_version_2, + ip_rip_receive_version_2_cmd, + "ip rip receive version 2 1", + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "RIP version 2\n" + "RIP version 1\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1 and 2. */ + ri->ri_receive = RI_RIP_VERSION_1_AND_2; + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_receive_version, + no_ip_rip_receive_version_cmd, + "no ip rip receive version", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + ri->ri_receive = RI_RIP_UNSPEC; + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_receive_version, + no_ip_rip_receive_version_num_cmd, + "no ip rip receive version (1|2)", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "Version 1\n" + "Version 2\n"); + +DEFUN (ip_rip_send_version, + ip_rip_send_version_cmd, + "ip rip send version (1|2)", + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1. */ + if (atoi (argv[0]) == 1) + { + ri->ri_send = RI_RIP_VERSION_1; + return CMD_SUCCESS; + } + if (atoi (argv[0]) == 2) + { + ri->ri_send = RI_RIP_VERSION_2; + return CMD_SUCCESS; + } + return CMD_WARNING; +} + +DEFUN (ip_rip_send_version_1, + ip_rip_send_version_1_cmd, + "ip rip send version 1 2", + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1 and 2. */ + ri->ri_send = RI_RIP_VERSION_1_AND_2; + return CMD_SUCCESS; +} + +DEFUN (ip_rip_send_version_2, + ip_rip_send_version_2_cmd, + "ip rip send version 2 1", + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "RIP version 2\n" + "RIP version 1\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* Version 1 and 2. */ + ri->ri_send = RI_RIP_VERSION_1_AND_2; + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_send_version, + no_ip_rip_send_version_cmd, + "no ip rip send version", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + ri->ri_send = RI_RIP_UNSPEC; + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_send_version, + no_ip_rip_send_version_num_cmd, + "no ip rip send version (1|2)", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "Version 1\n" + "Version 2\n"); + +DEFUN (ip_rip_authentication_mode, + ip_rip_authentication_mode_cmd, + "ip rip authentication mode (md5|text)", + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication mode\n" + "Keyed message digest\n" + "Clear text authentication\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + if (strncmp ("md5", argv[0], strlen (argv[0])) == 0) + ri->auth_type = RIP_AUTH_MD5; + else if (strncmp ("text", argv[0], strlen (argv[0])) == 0) + ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; + else + { + vty_out (vty, "mode should be md5 or text%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_authentication_mode, + no_ip_rip_authentication_mode_cmd, + "no ip rip authentication mode", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication mode\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + /* ri->auth_type = RIP_NO_AUTH; */ + ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; + + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_authentication_mode, + no_ip_rip_authentication_mode_type_cmd, + "no ip rip authentication mode (md5|text)", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication mode\n" + "Keyed message digest\n" + "Clear text authentication\n"); + +DEFUN (ip_rip_authentication_string, + ip_rip_authentication_string_cmd, + "ip rip authentication string LINE", + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication string\n" + "Authentication string\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + if (strlen (argv[0]) > 16) + { + vty_out (vty, "%% RIPv2 authentication string must be shorter than 16%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (ri->key_chain) + { + vty_out (vty, "%% key-chain configuration exists%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (ri->auth_str) + free (ri->auth_str); + + ri->auth_str = strdup (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_authentication_string, + no_ip_rip_authentication_string_cmd, + "no ip rip authentication string", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication string\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *)vty->index; + ri = ifp->info; + + if (ri->auth_str) + free (ri->auth_str); + + ri->auth_str = NULL; + + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_authentication_string, + no_ip_rip_authentication_string2_cmd, + "no ip rip authentication string LINE", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication string\n" + "Authentication string\n"); + +DEFUN (ip_rip_authentication_key_chain, + ip_rip_authentication_key_chain_cmd, + "ip rip authentication key-chain LINE", + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication key-chain\n" + "name of key-chain\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *) vty->index; + ri = ifp->info; + + if (ri->auth_str) + { + vty_out (vty, "%% authentication string configuration exists%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (ri->key_chain) + free (ri->key_chain); + + ri->key_chain = strdup (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_rip_authentication_key_chain, + no_ip_rip_authentication_key_chain_cmd, + "no ip rip authentication key-chain", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication key-chain\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = (struct interface *) vty->index; + ri = ifp->info; + + if (ri->key_chain) + free (ri->key_chain); + + ri->key_chain = NULL; + + return CMD_SUCCESS; +} + +ALIAS (no_ip_rip_authentication_key_chain, + no_ip_rip_authentication_key_chain2_cmd, + "no ip rip authentication key-chain LINE", + NO_STR + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication key-chain\n" + "name of key-chain\n"); + +DEFUN (rip_split_horizon, + rip_split_horizon_cmd, + "ip split-horizon", + IP_STR + "Perform split horizon\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = vty->index; + ri = ifp->info; + + ri->split_horizon = 1; + return CMD_SUCCESS; +} + +DEFUN (no_rip_split_horizon, + no_rip_split_horizon_cmd, + "no ip split-horizon", + NO_STR + IP_STR + "Perform split horizon\n") +{ + struct interface *ifp; + struct rip_interface *ri; + + ifp = vty->index; + ri = ifp->info; + + ri->split_horizon = 0; + return CMD_SUCCESS; +} + +DEFUN (rip_passive_interface, + rip_passive_interface_cmd, + "passive-interface IFNAME", + "Suppress routing updates on an interface\n" + "Interface name\n") +{ + return rip_passive_interface_set (vty, argv[0]); +} + +DEFUN (no_rip_passive_interface, + no_rip_passive_interface_cmd, + "no passive-interface IFNAME", + NO_STR + "Suppress routing updates on an interface\n" + "Interface name\n") +{ + return rip_passive_interface_unset (vty, argv[0]); +} + +/* Write rip configuration of each interface. */ +int +rip_interface_config_write (struct vty *vty) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) + { + struct rip_interface *ri; + + ifp = getdata (node); + ri = ifp->info; + + vty_out (vty, "interface %s%s", ifp->name, + VTY_NEWLINE); + + if (ifp->desc) + vty_out (vty, " description %s%s", ifp->desc, + VTY_NEWLINE); + + /* Split horizon. */ + if (ri->split_horizon != ri->split_horizon_default) + { + if (ri->split_horizon) + vty_out (vty, " ip split-horizon%s", VTY_NEWLINE); + else + vty_out (vty, " no ip split-horizon%s", VTY_NEWLINE); + } + + /* RIP version setting. */ + if (ri->ri_send != RI_RIP_UNSPEC) + vty_out (vty, " ip rip send version %s%s", + lookup (ri_version_msg, ri->ri_send), + VTY_NEWLINE); + + if (ri->ri_receive != RI_RIP_UNSPEC) + vty_out (vty, " ip rip receive version %s%s", + lookup (ri_version_msg, ri->ri_receive), + VTY_NEWLINE); + + /* RIP authentication. */ + if (ri->auth_type == RIP_AUTH_MD5) + vty_out (vty, " ip rip authentication mode md5%s", VTY_NEWLINE); + + if (ri->auth_str) + vty_out (vty, " ip rip authentication string %s%s", + ri->auth_str, VTY_NEWLINE); + + if (ri->key_chain) + vty_out (vty, " ip rip authentication key-chain %s%s", + ri->key_chain, VTY_NEWLINE); + + vty_out (vty, "!%s", VTY_NEWLINE); + } + return 0; +} + +int +config_write_rip_network (struct vty *vty, int config_mode) +{ + int i; + char *ifname; + struct route_node *node; + + /* Network type RIP enable interface statement. */ + for (node = route_top (rip_enable_network); node; node = route_next (node)) + if (node->info) + vty_out (vty, "%s%s/%d%s", + config_mode ? " network " : " ", + inet_ntoa (node->p.u.prefix4), + node->p.prefixlen, + VTY_NEWLINE); + + /* Interface name RIP enable statement. */ + for (i = 0; i < vector_max (rip_enable_interface); i++) + if ((ifname = vector_slot (rip_enable_interface, i)) != NULL) + vty_out (vty, "%s%s%s", + config_mode ? " network " : " ", + ifname, + VTY_NEWLINE); + + /* RIP neighbors listing. */ + for (node = route_top (rip->neighbor); node; node = route_next (node)) + if (node->info) + vty_out (vty, "%s%s%s", + config_mode ? " neighbor " : " ", + inet_ntoa (node->p.u.prefix4), + VTY_NEWLINE); + + /* RIP passive interface listing. */ + if (config_mode) + for (i = 0; i < vector_max (Vrip_passive_interface); i++) + if ((ifname = vector_slot (Vrip_passive_interface, i)) != NULL) + vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE); + + return 0; +} + +struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", + 1, +}; + +/* Called when interface structure allocated. */ +int +rip_interface_new_hook (struct interface *ifp) +{ + ifp->info = rip_interface_new (); + return 0; +} + +/* Called when interface structure deleted. */ +int +rip_interface_delete_hook (struct interface *ifp) +{ + XFREE (MTYPE_RIP_INTERFACE, ifp->info); + return 0; +} + +/* Allocate and initialize interface vector. */ +void +rip_if_init () +{ + /* Default initial size of interface vector. */ + if_init(); + if_add_hook (IF_NEW_HOOK, rip_interface_new_hook); + if_add_hook (IF_DELETE_HOOK, rip_interface_delete_hook); + + /* RIP network init. */ + rip_enable_interface = vector_init (1); + rip_enable_network = route_table_init (); + + /* RIP passive interface. */ + Vrip_passive_interface = vector_init (1); + + /* Install interface node. */ + install_node (&interface_node, rip_interface_config_write); + + /* Install commands. */ + install_element (CONFIG_NODE, &interface_cmd); + install_default (INTERFACE_NODE); + install_element (INTERFACE_NODE, &interface_desc_cmd); + install_element (INTERFACE_NODE, &no_interface_desc_cmd); + install_element (RIP_NODE, &rip_network_cmd); + install_element (RIP_NODE, &no_rip_network_cmd); + install_element (RIP_NODE, &rip_neighbor_cmd); + install_element (RIP_NODE, &no_rip_neighbor_cmd); + + install_element (RIP_NODE, &rip_passive_interface_cmd); + install_element (RIP_NODE, &no_rip_passive_interface_cmd); + + install_element (INTERFACE_NODE, &ip_rip_send_version_cmd); + install_element (INTERFACE_NODE, &ip_rip_send_version_1_cmd); + install_element (INTERFACE_NODE, &ip_rip_send_version_2_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_send_version_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_send_version_num_cmd); + + install_element (INTERFACE_NODE, &ip_rip_receive_version_cmd); + install_element (INTERFACE_NODE, &ip_rip_receive_version_1_cmd); + install_element (INTERFACE_NODE, &ip_rip_receive_version_2_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_receive_version_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_receive_version_num_cmd); + + install_element (INTERFACE_NODE, &ip_rip_authentication_mode_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_cmd); + + install_element (INTERFACE_NODE, &ip_rip_authentication_key_chain_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain2_cmd); + + install_element (INTERFACE_NODE, &ip_rip_authentication_string_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_string_cmd); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_string2_cmd); + + install_element (INTERFACE_NODE, &rip_split_horizon_cmd); + install_element (INTERFACE_NODE, &no_rip_split_horizon_cmd); +} diff --git a/ripd/rip_main.c b/ripd/rip_main.c new file mode 100644 index 0000000..1070fb4 --- /dev/null +++ b/ripd/rip_main.c @@ -0,0 +1,270 @@ +/* RIPd main routine. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "version.h" +#include "getopt.h" +#include "thread.h" +#include "command.h" +#include "memory.h" +#include "prefix.h" +#include "filter.h" +#include "keychain.h" +#include "log.h" + +#include "ripd/ripd.h" + +/* ripd options. */ +static struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "help", no_argument, NULL, 'h'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "retain", no_argument, NULL, 'r'}, + { "version", no_argument, NULL, 'v'}, + { 0 } +}; + +/* Configuration file and directory. */ +char config_current[] = RIPD_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR RIPD_DEFAULT_CONFIG; +char *config_file = NULL; + +/* ripd program name */ + +/* Route retain mode flag. */ +int retain_mode = 0; + +/* RIP VTY bind address. */ +char *vty_addr = NULL; + +/* RIP VTY connection port. */ +int vty_port = RIP_VTY_PORT; + +/* Master of threads. */ +struct thread_master *master; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_RIPD_PID; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\ +Daemon which manages RIP version 1 and 2.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-r, --retain When program terminates, retain added route by ripd.\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + + exit (status); +} + +/* Signale wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog_info ("SIGHUP received"); + rip_clean (); + rip_reset (); + zlog_info ("ripd restarting!"); + + /* Reload config file. */ + vty_read_config (config_file, config_current, config_default); + + /* Create VTY's socket */ + vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); + + /* Try to return to normal operation. */ +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + zlog (NULL, LOG_INFO, "Terminating on signal"); + + if (! retain_mode) + rip_clean (); + + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_rotate (NULL); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigint); + signal_set (SIGPIPE, SIG_IGN); + signal_set (SIGUSR1, sigusr1); +} + +/* Main routine of ripd. */ +int +main (int argc, char **argv) +{ + char *p; + int daemon_mode = 0; + char *progname; + struct thread thread; + + /* Set umask before anything for security */ + umask (0027); + + /* Get program name. */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + /* First of all we need logging init. */ + zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_RIP, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + /* Command line option parse. */ + while (1) + { + int opt; + + opt = getopt_long (argc, argv, "df:hA:P:rv", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'd': + daemon_mode = 1; + break; + case 'f': + config_file = optarg; + break; + case 'A': + vty_addr = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'r': + retain_mode = 1; + break; + case 'v': + print_version (progname); + exit (0); + break; + case 'h': + usage (progname, 0); + break; + default: + usage (progname, 1); + break; + } + } + + /* Prepare master thread. */ + master = thread_master_create (); + + /* Library initialization. */ + signal_init (); + cmd_init (1); + vty_init (); + memory_init (); + keychain_init (); + + /* RIP related initialization. */ + rip_init (); + rip_if_init (); + rip_zclient_init (); + rip_peer_init (); + + /* Sort all installed commands. */ + sort_node (); + + /* Get configuration file. */ + vty_read_config (config_file, config_current, config_default); + + /* Change to the daemon program. */ + if (daemon_mode) + daemon (0, 0); + + /* Pid file create. */ + pid_output (pid_file); + + /* Create VTY's socket */ + vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); + + /* Execute each thread. */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Not reached. */ + exit (0); +} diff --git a/ripd/rip_offset.c b/ripd/rip_offset.c new file mode 100644 index 0000000..0d47348 --- /dev/null +++ b/ripd/rip_offset.c @@ -0,0 +1,414 @@ +/* RIP offset-list + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "prefix.h" +#include "filter.h" +#include "command.h" +#include "linklist.h" +#include "memory.h" + +#define RIP_OFFSET_LIST_IN 0 +#define RIP_OFFSET_LIST_OUT 1 +#define RIP_OFFSET_LIST_MAX 2 + +struct rip_offset_list +{ + char *ifname; + + struct + { + char *alist_name; + /* struct access_list *alist; */ + int metric; + } direct[RIP_OFFSET_LIST_MAX]; +}; + +static struct list *rip_offset_list_master; + +int +strcmp_safe (char *s1, char *s2) +{ + if (s1 == NULL && s2 == NULL) + return 0; + if (s1 == NULL) + return -1; + if (s2 == NULL) + return 1; + return strcmp (s1, s2); +} + +struct rip_offset_list * +rip_offset_list_new () +{ + struct rip_offset_list *new; + + new = XMALLOC (MTYPE_RIP_OFFSET_LIST, sizeof (struct rip_offset_list)); + memset (new, 0, sizeof (struct rip_offset_list)); + return new; +} + +void +rip_offset_list_free (struct rip_offset_list *offset) +{ + XFREE (MTYPE_RIP_OFFSET_LIST, offset); +} + +struct rip_offset_list * +rip_offset_list_lookup (char *ifname) +{ + struct rip_offset_list *offset; + struct listnode *nn; + + LIST_LOOP (rip_offset_list_master, offset, nn) + { + if (strcmp_safe (offset->ifname, ifname) == 0) + return offset; + } + return NULL; +} + +struct rip_offset_list * +rip_offset_list_get (char *ifname) +{ + struct rip_offset_list *offset; + + offset = rip_offset_list_lookup (ifname); + if (offset) + return offset; + + offset = rip_offset_list_new (); + if (ifname) + offset->ifname = strdup (ifname); + listnode_add_sort (rip_offset_list_master, offset); + + return offset; +} + +int +rip_offset_list_set (struct vty *vty, char *alist, char *direct_str, + char *metric_str, char *ifname) +{ + int direct; + int metric; + struct rip_offset_list *offset; + + /* Check direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = RIP_OFFSET_LIST_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = RIP_OFFSET_LIST_OUT; + else + { + vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check metric. */ + metric = atoi (metric_str); + if (metric < 0 || metric > 16) + { + vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get offset-list structure with interface name. */ + offset = rip_offset_list_get (ifname); + + if (offset->direct[direct].alist_name) + free (offset->direct[direct].alist_name); + offset->direct[direct].alist_name = strdup (alist); + offset->direct[direct].metric = metric; + + return CMD_SUCCESS; +} + +int +rip_offset_list_unset (struct vty *vty, char *alist, char *direct_str, + char *metric_str, char *ifname) +{ + int direct; + int metric; + struct rip_offset_list *offset; + + /* Check direction. */ + if (strncmp (direct_str, "i", 1) == 0) + direct = RIP_OFFSET_LIST_IN; + else if (strncmp (direct_str, "o", 1) == 0) + direct = RIP_OFFSET_LIST_OUT; + else + { + vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check metric. */ + metric = atoi (metric_str); + if (metric < 0 || metric > 16) + { + vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get offset-list structure with interface name. */ + offset = rip_offset_list_lookup (ifname); + + if (offset) + { + if (offset->direct[direct].alist_name) + free (offset->direct[direct].alist_name); + offset->direct[direct].alist_name = NULL; + + if (offset->direct[RIP_OFFSET_LIST_IN].alist_name == NULL && + offset->direct[RIP_OFFSET_LIST_OUT].alist_name == NULL) + { + listnode_delete (rip_offset_list_master, offset); + if (offset->ifname) + free (offset->ifname); + rip_offset_list_free (offset); + } + } + else + { + vty_out (vty, "Can't find offset-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +#define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIP_OFFSET_LIST_IN].alist_name) +#define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_IN].metric) + +#define OFFSET_LIST_OUT_NAME(O) ((O)->direct[RIP_OFFSET_LIST_OUT].alist_name) +#define OFFSET_LIST_OUT_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_OUT].metric) + +/* If metric is modifed return 1. */ +int +rip_offset_list_apply_in (struct prefix_ipv4 *p, struct interface *ifp, + u_int32_t *metric) +{ + struct rip_offset_list *offset; + struct access_list *alist; + + /* Look up offset-list with interface name. */ + offset = rip_offset_list_lookup (ifp->name); + if (offset && OFFSET_LIST_IN_NAME (offset)) + { + alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset)); + + if (alist + && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) + { + *metric += OFFSET_LIST_IN_METRIC (offset); + return 1; + } + return 0; + } + /* Look up offset-list without interface name. */ + offset = rip_offset_list_lookup (NULL); + if (offset && OFFSET_LIST_IN_NAME (offset)) + { + alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset)); + + if (alist + && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) + { + *metric += OFFSET_LIST_IN_METRIC (offset); + return 1; + } + return 0; + } + return 0; +} + +/* If metric is modifed return 1. */ +int +rip_offset_list_apply_out (struct prefix_ipv4 *p, struct interface *ifp, + u_int32_t *metric) +{ + struct rip_offset_list *offset; + struct access_list *alist; + + /* Look up offset-list with interface name. */ + offset = rip_offset_list_lookup (ifp->name); + if (offset && OFFSET_LIST_OUT_NAME (offset)) + { + alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset)); + + if (alist + && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) + { + *metric += OFFSET_LIST_OUT_METRIC (offset); + return 1; + } + return 0; + } + + /* Look up offset-list without interface name. */ + offset = rip_offset_list_lookup (NULL); + if (offset && OFFSET_LIST_OUT_NAME (offset)) + { + alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset)); + + if (alist + && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) + { + *metric += OFFSET_LIST_OUT_METRIC (offset); + return 1; + } + return 0; + } + return 0; +} + +DEFUN (rip_offset_list, + rip_offset_list_cmd, + "offset-list WORD (in|out) <0-16>", + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n") +{ + return rip_offset_list_set (vty, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (rip_offset_list_ifname, + rip_offset_list_ifname_cmd, + "offset-list WORD (in|out) <0-16> IFNAME", + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n" + "Interface to match\n") +{ + return rip_offset_list_set (vty, argv[0], argv[1], argv[2], argv[3]); +} + +DEFUN (no_rip_offset_list, + no_rip_offset_list_cmd, + "no offset-list WORD (in|out) <0-16>", + NO_STR + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n") +{ + return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (no_rip_offset_list_ifname, + no_rip_offset_list_ifname_cmd, + "no offset-list WORD (in|out) <0-16> IFNAME", + NO_STR + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n" + "Interface to match\n") +{ + return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], argv[3]); +} + +int +offset_list_cmp (struct rip_offset_list *o1, struct rip_offset_list *o2) +{ + return strcmp_safe (o1->ifname, o2->ifname); +} + +void +offset_list_del (struct rip_offset_list *offset) +{ + if (OFFSET_LIST_IN_NAME (offset)) + free (OFFSET_LIST_IN_NAME (offset)); + if (OFFSET_LIST_OUT_NAME (offset)) + free (OFFSET_LIST_OUT_NAME (offset)); + if (offset->ifname) + free (offset->ifname); + rip_offset_list_free (offset); +} + +void +rip_offset_init () +{ + rip_offset_list_master = list_new (); + rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp; + rip_offset_list_master->del = (void (*)(void *)) offset_list_del; + + install_element (RIP_NODE, &rip_offset_list_cmd); + install_element (RIP_NODE, &rip_offset_list_ifname_cmd); + install_element (RIP_NODE, &no_rip_offset_list_cmd); + install_element (RIP_NODE, &no_rip_offset_list_ifname_cmd); +} + +void +rip_offset_clean () +{ + list_delete (rip_offset_list_master); + + rip_offset_list_master = list_new (); + rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp; + rip_offset_list_master->del = (void (*)(void *)) offset_list_del; +} + +int +config_write_rip_offset_list (struct vty *vty) +{ + struct listnode *nn; + struct rip_offset_list *offset; + + LIST_LOOP (rip_offset_list_master, offset, nn) + { + if (! offset->ifname) + { + if (offset->direct[RIP_OFFSET_LIST_IN].alist_name) + vty_out (vty, " offset-list %s in %d%s", + offset->direct[RIP_OFFSET_LIST_IN].alist_name, + offset->direct[RIP_OFFSET_LIST_IN].metric, + VTY_NEWLINE); + if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name) + vty_out (vty, " offset-list %s out %d%s", + offset->direct[RIP_OFFSET_LIST_OUT].alist_name, + offset->direct[RIP_OFFSET_LIST_OUT].metric, + VTY_NEWLINE); + } + else + { + if (offset->direct[RIP_OFFSET_LIST_IN].alist_name) + vty_out (vty, " offset-list %s in %d %s%s", + offset->direct[RIP_OFFSET_LIST_IN].alist_name, + offset->direct[RIP_OFFSET_LIST_IN].metric, + offset->ifname, VTY_NEWLINE); + if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name) + vty_out (vty, " offset-list %s out %d %s%s", + offset->direct[RIP_OFFSET_LIST_OUT].alist_name, + offset->direct[RIP_OFFSET_LIST_OUT].metric, + offset->ifname, VTY_NEWLINE); + } + } + + return 0; +} diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c new file mode 100644 index 0000000..20c2da7 --- /dev/null +++ b/ripd/rip_peer.c @@ -0,0 +1,211 @@ +/* RIP peer support + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "prefix.h" +#include "command.h" +#include "linklist.h" +#include "thread.h" +#include "memory.h" + +#include "ripd/ripd.h" + +/* Linked list of RIP peer. */ +struct list *peer_list; + +struct rip_peer * +rip_peer_new () +{ + struct rip_peer *new; + + new = XMALLOC (MTYPE_RIP_PEER, sizeof (struct rip_peer)); + memset (new, 0, sizeof (struct rip_peer)); + return new; +} + +void +rip_peer_free (struct rip_peer *peer) +{ + XFREE (MTYPE_RIP_PEER, peer); +} + +struct rip_peer * +rip_peer_lookup (struct in_addr *addr) +{ + struct rip_peer *peer; + struct listnode *nn; + + LIST_LOOP (peer_list, peer, nn) + { + if (IPV4_ADDR_SAME (&peer->addr, addr)) + return peer; + } + return NULL; +} + +struct rip_peer * +rip_peer_lookup_next (struct in_addr *addr) +{ + struct rip_peer *peer; + struct listnode *nn; + + LIST_LOOP (peer_list, peer, nn) + { + if (htonl (peer->addr.s_addr) > htonl (addr->s_addr)) + return peer; + } + return NULL; +} + +/* RIP peer is timeout. */ +int +rip_peer_timeout (struct thread *t) +{ + struct rip_peer *peer; + + peer = THREAD_ARG (t); + listnode_delete (peer_list, peer); + rip_peer_free (peer); + + return 0; +} + +/* Get RIP peer. At the same time update timeout thread. */ +struct rip_peer * +rip_peer_get (struct in_addr *addr) +{ + struct rip_peer *peer; + + peer = rip_peer_lookup (addr); + + if (peer) + { + if (peer->t_timeout) + thread_cancel (peer->t_timeout); + } + else + { + peer = rip_peer_new (); + peer->addr = *addr; + listnode_add_sort (peer_list, peer); + } + + /* Update timeout thread. */ + peer->t_timeout = thread_add_timer (master, rip_peer_timeout, peer, + RIP_PEER_TIMER_DEFAULT); + + /* Last update time set. */ + time (&peer->uptime); + + return peer; +} + +void +rip_peer_update (struct sockaddr_in *from, u_char version) +{ + struct rip_peer *peer; + peer = rip_peer_get (&from->sin_addr); + peer->version = version; +} + +void +rip_peer_bad_route (struct sockaddr_in *from) +{ + struct rip_peer *peer; + peer = rip_peer_get (&from->sin_addr); + peer->recv_badroutes++; +} + +void +rip_peer_bad_packet (struct sockaddr_in *from) +{ + struct rip_peer *peer; + peer = rip_peer_get (&from->sin_addr); + peer->recv_badpackets++; +} + +/* Display peer uptime. */ +char * +rip_peer_uptime (struct rip_peer *peer, char *buf, size_t len) +{ + time_t uptime; + struct tm *tm; + + /* If there is no connection has been done before print `never'. */ + if (peer->uptime == 0) + { + snprintf (buf, len, "never "); + return buf; + } + + /* Get current time. */ + uptime = time (NULL); + uptime -= peer->uptime; + tm = gmtime (&uptime); + + /* Making formatted timer strings. */ +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + + if (uptime < ONE_DAY_SECOND) + snprintf (buf, len, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (uptime < ONE_WEEK_SECOND) + snprintf (buf, len, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + snprintf (buf, len, "%02dw%dd%02dh", + tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + return buf; +} + +void +rip_peer_display (struct vty *vty) +{ + struct rip_peer *peer; + struct listnode *nn; +#define RIP_UPTIME_LEN 25 + char timebuf[RIP_UPTIME_LEN]; + + LIST_LOOP (peer_list, peer, nn) + { + vty_out (vty, " %-16s %9d %9d %9d %s%s", inet_ntoa (peer->addr), + peer->recv_badpackets, peer->recv_badroutes, + ZEBRA_RIP_DISTANCE_DEFAULT, + rip_peer_uptime (peer, timebuf, RIP_UPTIME_LEN), + VTY_NEWLINE); + } +} + +int +rip_peer_list_cmp (struct rip_peer *p1, struct rip_peer *p2) +{ + return htonl (p1->addr.s_addr) > htonl (p2->addr.s_addr); +} + +void +rip_peer_init () +{ + peer_list = list_new (); + peer_list->cmp = (int (*)(void *, void *)) rip_peer_list_cmp; +} diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c new file mode 100644 index 0000000..db45023 --- /dev/null +++ b/ripd/rip_routemap.c @@ -0,0 +1,897 @@ +/* RIPv2 routemap. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "prefix.h" +#include "routemap.h" +#include "command.h" +#include "filter.h" +#include "log.h" +#include "sockunion.h" /* for inet_aton () */ +#include "plist.h" + +#include "ripd/ripd.h" + +/* Add rip route map rule. */ +int +rip_route_match_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Delete rip route map rule. */ +int +rip_route_match_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Add rip route map rule. */ +int +rip_route_set_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Delete rip route map rule. */ +int +rip_route_set_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +/* Hook function for updating route_map assignment. */ +void +rip_route_map_update () +{ + int i; + + if (rip) + { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (rip->route_map[i].name) + rip->route_map[i].map = + route_map_lookup_by_name (rip->route_map[i].name); + } + } +} + +/* `match metric METRIC' */ +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *metric; + struct rip_info *rinfo; + + if (type == RMAP_RIP) + { + metric = rule; + rinfo = object; + + if (rinfo->metric == *metric) + return RMAP_MATCH; + else + return RMAP_NOMATCH; + } + return RMAP_NOMATCH; +} + +/* Route map `match metric' match statement. `arg' is METRIC value */ +void * +route_match_metric_compile (char *arg) +{ + u_int32_t *metric; + + metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + *metric = atoi (arg); + + if(*metric > 0) + return metric; + + XFREE (MTYPE_ROUTE_MAP_COMPILED, metric); + return NULL; +} + +/* Free route map's compiled `match metric' value. */ +void +route_match_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for metric matching. */ +struct route_map_rule_cmd route_match_metric_cmd = +{ + "metric", + route_match_metric, + route_match_metric_compile, + route_match_metric_free +}; + +/* `match interface IFNAME' */ +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_interface (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct rip_info *rinfo; + struct interface *ifp; + char *ifname; + + if (type == RMAP_RIP) + { + ifname = rule; + ifp = if_lookup_by_name(ifname); + + if (!ifp) + return RMAP_NOMATCH; + + rinfo = object; + + if (rinfo->ifindex_out == ifp->ifindex) + return RMAP_MATCH; + else + return RMAP_NOMATCH; + } + return RMAP_NOMATCH; +} + +/* Route map `match interface' match statement. `arg' is IFNAME value */ +/* XXX I don`t know if I need to check does interface exist? */ +void * +route_match_interface_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `match interface' value. */ +void +route_match_interface_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for interface matching. */ +struct route_map_rule_cmd route_match_interface_cmd = +{ + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; + +/* `match ip next-hop IP_ACCESS_LIST' */ + +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_ip_next_hop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + struct rip_info *rinfo; + struct prefix_ipv4 p; + + if (type == RMAP_RIP) + { + rinfo = object; + p.family = AF_INET; + p.prefix = rinfo->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, &p) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip next-hop' match statement. `arg' should be + access-list name. */ +void * +route_match_ip_next_hop_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `. */ +void +route_match_ip_next_hop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip next-hop matching. */ +struct route_map_rule_cmd route_match_ip_next_hop_cmd = +{ + "ip next-hop", + route_match_ip_next_hop, + route_match_ip_next_hop_compile, + route_match_ip_next_hop_free +}; + +/* `match ip next-hop prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + struct rip_info *rinfo; + struct prefix_ipv4 p; + + if (type == RMAP_RIP) + { + rinfo = object; + p.family = AF_INET; + p.prefix = rinfo->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, &p) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_next_hop_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_next_hop_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = +{ + "ip next-hop prefix-list", + route_match_ip_next_hop_prefix_list, + route_match_ip_next_hop_prefix_list_compile, + route_match_ip_next_hop_prefix_list_free +}; + +/* `match ip address IP_ACCESS_LIST' */ + +/* Match function should return 1 if match is success else return + zero. */ +route_map_result_t +route_match_ip_address (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + + if (type == RMAP_RIP) + { + alist = access_list_lookup (AFI_IP, (char *) rule); + if (alist == NULL) + return RMAP_NOMATCH; + + return (access_list_apply (alist, prefix) == FILTER_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +/* Route map `ip address' match statement. `arg' should be + access-list name. */ +void * +route_match_ip_address_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_address_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_ip_address_cmd = +{ + "ip address", + route_match_ip_address, + route_match_ip_address_compile, + route_match_ip_address_free +}; + +/* `match ip address prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_list *plist; + + if (type == RMAP_RIP) + { + plist = prefix_list_lookup (AFI_IP, (char *) rule); + if (plist == NULL) + return RMAP_NOMATCH; + + return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? + RMAP_NOMATCH : RMAP_MATCH); + } + return RMAP_NOMATCH; +} + +void * +route_match_ip_address_prefix_list_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_address_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = +{ + "ip address prefix-list", + route_match_ip_address_prefix_list, + route_match_ip_address_prefix_list_compile, + route_match_ip_address_prefix_list_free +}; + +/* `set metric METRIC' */ + +/* Set metric to attribute. */ +route_map_result_t +route_set_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + u_int32_t *metric; + struct rip_info *rinfo; + + if (type == RMAP_RIP) + { + /* Fetch routemap's rule information. */ + metric = rule; + rinfo = object; + + /* Set metric out value. */ + rinfo->metric_out = *metric; + rinfo->metric_set = 1; + } + return RMAP_OKAY; +} + +/* set metric compilation. */ +void * +route_set_metric_compile (char *arg) +{ + u_int32_t *metric; + + metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); + *metric = atoi (arg); + + return metric; +} + +/* Free route map's compiled `set metric' value. */ +void +route_set_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_metric_cmd = +{ + "metric", + route_set_metric, + route_set_metric_compile, + route_set_metric_free, +}; + +/* `set ip next-hop IP_ADDRESS' */ + +/* Set nexthop to object. ojbect must be pointer to struct attr. */ +route_map_result_t +route_set_ip_nexthop (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct in_addr *address; + struct rip_info *rinfo; + + if(type == RMAP_RIP) + { + /* Fetch routemap's rule information. */ + address = rule; + rinfo = object; + + /* Set next hop value. */ + rinfo->nexthop_out = *address; + } + + return RMAP_OKAY; +} + +/* Route map `ip nexthop' compile function. Given string is converted + to struct in_addr structure. */ +void * +route_set_ip_nexthop_compile (char *arg) +{ + int ret; + struct in_addr *address; + + address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); + + ret = inet_aton (arg, address); + + if (ret == 0) + { + XFREE (MTYPE_ROUTE_MAP_COMPILED, address); + return NULL; + } + + return address; +} + +/* Free route map's compiled `ip nexthop' value. */ +void +route_set_ip_nexthop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_ip_nexthop_cmd = +{ + "ip next-hop", + route_set_ip_nexthop, + route_set_ip_nexthop_compile, + route_set_ip_nexthop_free +}; + +#define MATCH_STR "Match values from routing table\n" +#define SET_STR "Set values in destination routing protocol\n" + +DEFUN (match_metric, + match_metric_cmd, + "match metric <0-4294967295>", + MATCH_STR + "Match metric of route\n" + "Metric value\n") +{ + return rip_route_match_add (vty, vty->index, "metric", argv[0]); +} + +DEFUN (no_match_metric, + no_match_metric_cmd, + "no match metric", + NO_STR + MATCH_STR + "Match metric of route\n") +{ + if (argc == 0) + return rip_route_match_delete (vty, vty->index, "metric", NULL); + + return rip_route_match_delete (vty, vty->index, "metric", argv[0]); +} + +ALIAS (no_match_metric, + no_match_metric_val_cmd, + "no match metric <0-4294967295>", + NO_STR + MATCH_STR + "Match metric of route\n" + "Metric value\n"); + +DEFUN (match_interface, + match_interface_cmd, + "match interface WORD", + MATCH_STR + "Match first hop interface of route\n" + "Interface name\n") +{ + return rip_route_match_add (vty, vty->index, "interface", argv[0]); +} + +DEFUN (no_match_interface, + no_match_interface_cmd, + "no match interface", + NO_STR + MATCH_STR + "Match first hop interface of route\n") +{ + if (argc == 0) + return rip_route_match_delete (vty, vty->index, "interface", NULL); + + return rip_route_match_delete (vty, vty->index, "interface", argv[0]); +} + +ALIAS (no_match_interface, + no_match_interface_val_cmd, + "no match interface WORD", + NO_STR + MATCH_STR + "Match first hop interface of route\n" + "Interface name\n"); + +DEFUN (match_ip_next_hop, + match_ip_next_hop_cmd, + "match ip next-hop (<1-199>|<1300-2699>|WORD)", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") +{ + return rip_route_match_add (vty, vty->index, "ip next-hop", argv[0]); +} + +DEFUN (no_match_ip_next_hop, + no_match_ip_next_hop_cmd, + "no match ip next-hop", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n") +{ + if (argc == 0) + return rip_route_match_delete (vty, vty->index, "ip next-hop", NULL); + + return rip_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); +} + +ALIAS (no_match_ip_next_hop, + no_match_ip_next_hop_val_cmd, + "no match ip next-hop (<1-199>|<1300-2699>|WORD)", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n"); + +DEFUN (match_ip_next_hop_prefix_list, + match_ip_next_hop_prefix_list_cmd, + "match ip next-hop prefix-list WORD", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return rip_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]); +} + +DEFUN (no_match_ip_next_hop_prefix_list, + no_match_ip_next_hop_prefix_list_cmd, + "no match ip next-hop prefix-list", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n") +{ + if (argc == 0) + return rip_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL); + + return rip_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]); +} + +ALIAS (no_match_ip_next_hop_prefix_list, + no_match_ip_next_hop_prefix_list_val_cmd, + "no match ip next-hop prefix-list WORD", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n"); + +DEFUN (match_ip_address, + match_ip_address_cmd, + "match ip address (<1-199>|<1300-2699>|WORD)", + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") + +{ + return rip_route_match_add (vty, vty->index, "ip address", argv[0]); +} + +DEFUN (no_match_ip_address, + no_match_ip_address_cmd, + "no match ip address", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n") +{ + if (argc == 0) + return rip_route_match_delete (vty, vty->index, "ip address", NULL); + + return rip_route_match_delete (vty, vty->index, "ip address", argv[0]); +} + +ALIAS (no_match_ip_address, + no_match_ip_address_val_cmd, + "no match ip address (<1-199>|<1300-2699>|WORD)", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n"); + +DEFUN (match_ip_address_prefix_list, + match_ip_address_prefix_list_cmd, + "match ip address prefix-list WORD", + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + return rip_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]); +} + +DEFUN (no_match_ip_address_prefix_list, + no_match_ip_address_prefix_list_cmd, + "no match ip address prefix-list", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n") +{ + if (argc == 0) + return rip_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); + + return rip_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]); +} + +ALIAS (no_match_ip_address_prefix_list, + no_match_ip_address_prefix_list_val_cmd, + "no match ip address prefix-list WORD", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n"); + +/* set functions */ + +DEFUN (set_metric, + set_metric_cmd, + "set metric <0-4294967295>", + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n") +{ + return rip_route_set_add (vty, vty->index, "metric", argv[0]); +} + +DEFUN (no_set_metric, + no_set_metric_cmd, + "no set metric", + NO_STR + SET_STR + "Metric value for destination routing protocol\n") +{ + if (argc == 0) + return rip_route_set_delete (vty, vty->index, "metric", NULL); + + return rip_route_set_delete (vty, vty->index, "metric", argv[0]); +} + +ALIAS (no_set_metric, + no_set_metric_val_cmd, + "no set metric <0-4294967295>", + NO_STR + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n"); + +DEFUN (set_ip_nexthop, + set_ip_nexthop_cmd, + "set ip next-hop A.B.C.D", + SET_STR + IP_STR + "Next hop address\n" + "IP address of next hop\n") +{ + union sockunion su; + int ret; + + ret = str2sockunion (argv[0], &su); + if (ret < 0) + { + vty_out (vty, "%% Malformed next-hop address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return rip_route_set_add (vty, vty->index, "ip next-hop", argv[0]); +} + +DEFUN (no_set_ip_nexthop, + no_set_ip_nexthop_cmd, + "no set ip next-hop", + NO_STR + SET_STR + IP_STR + "Next hop address\n") +{ + if (argc == 0) + return rip_route_set_delete (vty, vty->index, "ip next-hop", NULL); + + return rip_route_set_delete (vty, vty->index, "ip next-hop", argv[0]); +} + +ALIAS (no_set_ip_nexthop, + no_set_ip_nexthop_val_cmd, + "no set ip next-hop A.B.C.D", + NO_STR + SET_STR + IP_STR + "Next hop address\n" + "IP address of next hop\n"); + +void +rip_route_map_reset () +{ + ; +} + +/* Route-map init */ +void +rip_route_map_init () +{ + route_map_init (); + route_map_init_vty (); + route_map_add_hook (rip_route_map_update); + route_map_delete_hook (rip_route_map_update); + + route_map_install_match (&route_match_metric_cmd); + route_map_install_match (&route_match_interface_cmd); + route_map_install_match (&route_match_ip_next_hop_cmd); + route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); + route_map_install_match (&route_match_ip_address_cmd); + route_map_install_match (&route_match_ip_address_prefix_list_cmd); + + route_map_install_set (&route_set_metric_cmd); + route_map_install_set (&route_set_ip_nexthop_cmd); + + install_element (RMAP_NODE, &match_metric_cmd); + install_element (RMAP_NODE, &no_match_metric_cmd); + install_element (RMAP_NODE, &no_match_metric_val_cmd); + install_element (RMAP_NODE, &match_interface_cmd); + install_element (RMAP_NODE, &no_match_interface_cmd); + install_element (RMAP_NODE, &no_match_interface_val_cmd); + install_element (RMAP_NODE, &match_ip_next_hop_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd); + install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd); + install_element (RMAP_NODE, &match_ip_address_cmd); + install_element (RMAP_NODE, &no_match_ip_address_cmd); + install_element (RMAP_NODE, &no_match_ip_address_val_cmd); + install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); + install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); + + install_element (RMAP_NODE, &set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_val_cmd); + install_element (RMAP_NODE, &set_ip_nexthop_cmd); + install_element (RMAP_NODE, &no_set_ip_nexthop_cmd); + install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd); +} diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c new file mode 100644 index 0000000..b12b6ad --- /dev/null +++ b/ripd/rip_snmp.c @@ -0,0 +1,573 @@ +/* RIP SNMP support + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#ifdef HAVE_SNMP + +#ifdef HAVE_NETSNMP +#include +#endif /* HAVE_NETSNMP */ + +#include +#include +#include + +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "command.h" +#include "table.h" +#include "smux.h" + +#include "ripd/ripd.h" + +/* RIPv2-MIB. */ +#define RIPV2MIB 1,3,6,1,2,1,23 + +/* Zebra enterprise RIP MIB. This variable is used for register + RIPv2-MIB to SNMP agent under SMUX protocol. */ +#define RIPDOID 1,3,6,1,4,1,3317,1,2,3 + +/* RIPv2-MIB rip2Globals values. */ +#define RIP2GLOBALROUTECHANGES 1 +#define RIP2GLOBALQUERIES 2 + +/* RIPv2-MIB rip2IfStatEntry. */ +#define RIP2IFSTATENTRY 1 + +/* RIPv2-MIB rip2IfStatTable. */ +#define RIP2IFSTATADDRESS 1 +#define RIP2IFSTATRCVBADPACKETS 2 +#define RIP2IFSTATRCVBADROUTES 3 +#define RIP2IFSTATSENTUPDATES 4 +#define RIP2IFSTATSTATUS 5 + +/* RIPv2-MIB rip2IfConfTable. */ +#define RIP2IFCONFADDRESS 1 +#define RIP2IFCONFDOMAIN 2 +#define RIP2IFCONFAUTHTYPE 3 +#define RIP2IFCONFAUTHKEY 4 +#define RIP2IFCONFSEND 5 +#define RIP2IFCONFRECEIVE 6 +#define RIP2IFCONFDEFAULTMETRIC 7 +#define RIP2IFCONFSTATUS 8 +#define RIP2IFCONFSRCADDRESS 9 + +/* RIPv2-MIB rip2PeerTable. */ +#define RIP2PEERADDRESS 1 +#define RIP2PEERDOMAIN 2 +#define RIP2PEERLASTUPDATE 3 +#define RIP2PEERVERSION 4 +#define RIP2PEERRCVBADPACKETS 5 +#define RIP2PEERRCVBADROUTES 6 + +/* SNMP value hack. */ +#define COUNTER ASN_COUNTER +#define INTEGER ASN_INTEGER +#define TIMETICKS ASN_TIMETICKS +#define IPADDRESS ASN_IPADDRESS +#define STRING ASN_OCTET_STR + +/* Define SNMP local variables. */ +SNMP_LOCAL_VARIABLES + +/* RIP-MIB instances. */ +oid rip_oid [] = { RIPV2MIB }; +oid ripd_oid [] = { RIPDOID }; + +/* Interface cache table sorted by interface's address. */ +struct route_table *rip_ifaddr_table; + +/* Hook functions. */ +static u_char *rip2Globals (); +static u_char *rip2IfStatEntry (); +static u_char *rip2IfConfAddress (); +static u_char *rip2PeerTable (); + +struct variable rip_variables[] = +{ + /* RIP Global Counters. */ + {RIP2GLOBALROUTECHANGES, COUNTER, RONLY, rip2Globals, + 2, {1, 1}}, + {RIP2GLOBALQUERIES, COUNTER, RONLY, rip2Globals, + 2, {1, 2}}, + /* RIP Interface Tables. */ + {RIP2IFSTATADDRESS, IPADDRESS, RONLY, rip2IfStatEntry, + 3, {2, 1, 1}}, + {RIP2IFSTATRCVBADPACKETS, COUNTER, RONLY, rip2IfStatEntry, + 3, {2, 1, 2}}, + {RIP2IFSTATRCVBADROUTES, COUNTER, RONLY, rip2IfStatEntry, + 3, {2, 1, 3}}, + {RIP2IFSTATSENTUPDATES, COUNTER, RONLY, rip2IfStatEntry, + 3, {2, 1, 4}}, + {RIP2IFSTATSTATUS, COUNTER, RWRITE, rip2IfStatEntry, + 3, {2, 1, 5}}, + {RIP2IFCONFADDRESS, IPADDRESS, RONLY, rip2IfConfAddress, + /* RIP Interface Configuration Table. */ + 3, {3, 1, 1}}, + {RIP2IFCONFDOMAIN, STRING, RONLY, rip2IfConfAddress, + 3, {3, 1, 2}}, + {RIP2IFCONFAUTHTYPE, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 3}}, + {RIP2IFCONFAUTHKEY, STRING, RONLY, rip2IfConfAddress, + 3, {3, 1, 4}}, + {RIP2IFCONFSEND, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 5}}, + {RIP2IFCONFRECEIVE, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 6}}, + {RIP2IFCONFDEFAULTMETRIC, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 7}}, + {RIP2IFCONFSTATUS, COUNTER, RONLY, rip2IfConfAddress, + 3, {3, 1, 8}}, + {RIP2IFCONFSRCADDRESS, IPADDRESS, RONLY, rip2IfConfAddress, + 3, {3, 1, 9}}, + {RIP2PEERADDRESS, IPADDRESS, RONLY, rip2PeerTable, + /* RIP Peer Table. */ + 3, {4, 1, 1}}, + {RIP2PEERDOMAIN, INTEGER, RONLY, rip2PeerTable, + 3, {4, 1, 2}}, + {RIP2PEERLASTUPDATE, TIMETICKS, RONLY, rip2PeerTable, + 3, {4, 1, 3}}, + {RIP2PEERVERSION, INTEGER, RONLY, rip2PeerTable, + 3, {4, 1, 4}}, + {RIP2PEERRCVBADPACKETS, COUNTER, RONLY, rip2PeerTable, + 3, {4, 1, 5}}, + {RIP2PEERRCVBADROUTES, COUNTER, RONLY, rip2PeerTable, + 3, {4, 1, 6}} +}; + +static u_char * +rip2Globals (struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Retrun global counter. */ + switch (v->magic) + { + case RIP2GLOBALROUTECHANGES: + return SNMP_INTEGER (rip_global_route_changes); + break; + case RIP2GLOBALQUERIES: + return SNMP_INTEGER (rip_global_queries); + break; + default: + return NULL; + break; + } + return NULL; +} + +void +rip_ifaddr_add (struct interface *ifp, struct connected *ifc) +{ + struct prefix *p; + struct route_node *rn; + + p = ifc->address; + + if (p->family != AF_INET) + return; + + rn = route_node_get (rip_ifaddr_table, p); + rn->info = ifp; +} + +void +rip_ifaddr_delete (struct interface *ifp, struct connected *ifc) +{ + struct prefix *p; + struct route_node *rn; + struct interface *i; + + p = ifc->address; + + if (p->family != AF_INET) + return; + + rn = route_node_lookup (rip_ifaddr_table, p); + if (! rn) + return; + i = rn->info; + if (rn && !strncmp(i->name,ifp->name,INTERFACE_NAMSIZ)) + { + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + } +} + +struct interface * +rip_ifaddr_lookup_next (struct in_addr *addr) +{ + struct prefix_ipv4 p; + struct route_node *rn; + struct interface *ifp; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.prefix = *addr; + + rn = route_node_get (rip_ifaddr_table, (struct prefix *) &p); + + for (rn = route_next (rn); rn; rn = route_next (rn)) + if (rn->info) + break; + + if (rn && rn->info) + { + ifp = rn->info; + *addr = rn->p.u.prefix4; + route_unlock_node (rn); + return ifp; + } + return NULL; +} + +static struct interface * +rip2IfLookup (struct variable *v, oid name[], size_t *length, + struct in_addr *addr, int exact) +{ + int len; + struct interface *ifp; + + if (exact) + { + /* Check the length. */ + if (*length - v->namelen != sizeof (struct in_addr)) + return NULL; + + oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); + + return if_lookup_exact_address (*addr); + } + else + { + len = *length - v->namelen; + if (len > 4) len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + ifp = rip_ifaddr_lookup_next (addr); + + if (ifp == NULL) + return NULL; + + oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); + + *length = v->namelen + sizeof (struct in_addr); + + return ifp; + } + return NULL; +} + +static struct rip_peer * +rip2PeerLookup (struct variable *v, oid name[], size_t *length, + struct in_addr *addr, int exact) +{ + int len; + struct rip_peer *peer; + + if (exact) + { + /* Check the length. */ + if (*length - v->namelen != sizeof (struct in_addr) + 1) + return NULL; + + oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); + + peer = rip_peer_lookup (addr); + + if (peer->domain == name[v->namelen + sizeof (struct in_addr)]) + return peer; + + return NULL; + } + else + { + len = *length - v->namelen; + if (len > 4) len = 4; + + oid2in_addr (name + v->namelen, len, addr); + + len = *length - v->namelen; + peer = rip_peer_lookup (addr); + if (peer) + { + if ((len < sizeof (struct in_addr) + 1) || + (peer->domain > name[v->namelen + sizeof (struct in_addr)])) + { + oid_copy_addr (name + v->namelen, &peer->addr, + sizeof (struct in_addr)); + name[v->namelen + sizeof (struct in_addr)] = peer->domain; + *length = sizeof (struct in_addr) + v->namelen + 1; + return peer; + } + } + peer = rip_peer_lookup_next (addr); + + if (! peer) + return NULL; + + oid_copy_addr (name + v->namelen, &peer->addr, + sizeof (struct in_addr)); + name[v->namelen + sizeof (struct in_addr)] = peer->domain; + *length = sizeof (struct in_addr) + v->namelen + 1; + + return peer; + } + return NULL; +} + +static u_char * +rip2IfStatEntry (struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + struct interface *ifp; + struct rip_interface *ri; + static struct in_addr addr; + static long valid = SNMP_VALID; + + memset (&addr, 0, sizeof (struct in_addr)); + + /* Lookup interface. */ + ifp = rip2IfLookup (v, name, length, &addr, exact); + if (! ifp) + return NULL; + + /* Fetch rip_interface information. */ + ri = ifp->info; + + switch (v->magic) + { + case RIP2IFSTATADDRESS: + return SNMP_IPADDRESS (addr); + break; + case RIP2IFSTATRCVBADPACKETS: + *var_len = sizeof (long); + return (u_char *) &ri->recv_badpackets; + + case RIP2IFSTATRCVBADROUTES: + *var_len = sizeof (long); + return (u_char *) &ri->recv_badroutes; + + case RIP2IFSTATSENTUPDATES: + *var_len = sizeof (long); + return (u_char *) &ri->sent_updates; + + case RIP2IFSTATSTATUS: + *var_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &valid; + + default: + return NULL; + + } + return NULL; +} + +static long +rip2IfConfSend (struct rip_interface *ri) +{ +#define doNotSend 1 +#define ripVersion1 2 +#define rip1Compatible 3 +#define ripVersion2 4 +#define ripV1Demand 5 +#define ripV2Demand 6 + + if (! ri->running) + return doNotSend; + + if (ri->ri_send & RIPv2) + return ripVersion2; + else if (ri->ri_send & RIPv1) + return ripVersion1; + else if (rip) + { + if (rip->version == RIPv2) + return ripVersion2; + else if (rip->version == RIPv1) + return ripVersion1; + } + return doNotSend; +} + +static long +rip2IfConfReceive (struct rip_interface *ri) +{ +#define rip1 1 +#define rip2 2 +#define rip1OrRip2 3 +#define doNotReceive 4 + + if (! ri->running) + return doNotReceive; + + if (ri->ri_receive == RI_RIP_VERSION_1_AND_2) + return rip1OrRip2; + else if (ri->ri_receive & RIPv2) + return ripVersion2; + else if (ri->ri_receive & RIPv1) + return ripVersion1; + else + return doNotReceive; +} + +static u_char * +rip2IfConfAddress (struct variable *v, oid name[], size_t *length, + int exact, size_t *val_len, WriteMethod **write_method) +{ + static struct in_addr addr; + static long valid = SNMP_INVALID; + static long domain = 0; + static long config = 0; + static u_int auth = 0; + struct interface *ifp; + struct rip_interface *ri; + + memset (&addr, 0, sizeof (struct in_addr)); + + /* Lookup interface. */ + ifp = rip2IfLookup (v, name, length, &addr, exact); + if (! ifp) + return NULL; + + /* Fetch rip_interface information. */ + ri = ifp->info; + + switch (v->magic) + { + case RIP2IFCONFADDRESS: + *val_len = sizeof (struct in_addr); + return (u_char *) &addr; + + case RIP2IFCONFDOMAIN: + *val_len = 2; + return (u_char *) &domain; + + case RIP2IFCONFAUTHTYPE: + auth = ri->auth_type; + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *)&auth; + + case RIP2IFCONFAUTHKEY: + *val_len = 0; + return (u_char *) &domain; + case RIP2IFCONFSEND: + config = rip2IfConfSend (ri); + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &config; + case RIP2IFCONFRECEIVE: + config = rip2IfConfReceive (ri); + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &config; + + case RIP2IFCONFDEFAULTMETRIC: + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &ifp->metric; + case RIP2IFCONFSTATUS: + *val_len = sizeof (long); + v->type = ASN_INTEGER; + return (u_char *) &valid; + case RIP2IFCONFSRCADDRESS: + *val_len = sizeof (struct in_addr); + return (u_char *) &addr; + + default: + return NULL; + + } + return NULL; +} + +static u_char * +rip2PeerTable (struct variable *v, oid name[], size_t *length, + int exact, size_t *val_len, WriteMethod **write_method) +{ + static struct in_addr addr; + static int version; + static time_t uptime; + + struct rip_peer *peer; + + memset (&addr, 0, sizeof (struct in_addr)); + + /* Lookup interface. */ + peer = rip2PeerLookup (v, name, length, &addr, exact); + if (! peer) + return NULL; + + switch (v->magic) + { + case RIP2PEERADDRESS: + *val_len = sizeof (struct in_addr); + return (u_char *) &peer->addr; + + case RIP2PEERDOMAIN: + *val_len = sizeof (int); + return (u_char *) &peer->domain; + + case RIP2PEERLASTUPDATE: + *val_len = sizeof (time_t); + uptime = peer->uptime; + return (u_char *) &uptime; + + case RIP2PEERVERSION: + *val_len = sizeof (int); + version = peer->version; + return (u_char *) &version; + + case RIP2PEERRCVBADPACKETS: + *val_len = sizeof (int); + return (u_char *) &peer->recv_badpackets; + + case RIP2PEERRCVBADROUTES: + *val_len = sizeof (int); + return (u_char *) &peer->recv_badroutes; + + default: + return NULL; + + } + return NULL; +} + +/* Register RIPv2-MIB. */ +void +rip_snmp_init () +{ + rip_ifaddr_table = route_table_init (); + + smux_init (ripd_oid, sizeof (ripd_oid) / sizeof (oid)); + REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid); + smux_start (); +} +#endif /* HAVE_SNMP */ diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c new file mode 100644 index 0000000..b6caf3b --- /dev/null +++ b/ripd/rip_zebra.c @@ -0,0 +1,691 @@ +/* RIPd and zebra interface. + * Copyright (C) 1997, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "command.h" +#include "prefix.h" +#include "stream.h" +#include "routemap.h" +#include "zclient.h" +#include "log.h" +#include "ripd/ripd.h" +#include "ripd/rip_debug.h" + +/* All information about zebra. */ +struct zclient *zclient = NULL; + +/* Callback prototypes for zebra client service. */ +int rip_interface_add (int, struct zclient *, zebra_size_t); +int rip_interface_delete (int, struct zclient *, zebra_size_t); +int rip_interface_address_add (int, struct zclient *, zebra_size_t); +int rip_interface_address_delete (int, struct zclient *, zebra_size_t); +int rip_interface_up (int, struct zclient *, zebra_size_t); +int rip_interface_down (int, struct zclient *, zebra_size_t); + +/* RIPd to zebra command interface. */ +void +rip_zebra_ipv4_add (struct prefix_ipv4 *p, struct in_addr *nexthop, + u_int32_t metric, u_char distance) +{ + struct zapi_ipv4 api; + + if (zclient->redist[ZEBRA_ROUTE_RIP]) + { + api.type = ZEBRA_ROUTE_RIP; + api.flags = 0; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + api.ifindex_num = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + + if (distance && distance != ZEBRA_RIP_DISTANCE_DEFAULT) + { + SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); + api.distance = distance; + } + + zapi_ipv4_add (zclient, p, &api); + + rip_global_route_changes++; + } +} + +void +rip_zebra_ipv4_delete (struct prefix_ipv4 *p, struct in_addr *nexthop, + u_int32_t metric) +{ + struct zapi_ipv4 api; + + if (zclient->redist[ZEBRA_ROUTE_RIP]) + { + api.type = ZEBRA_ROUTE_RIP; + api.flags = 0; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + api.ifindex_num = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + + zapi_ipv4_delete (zclient, p, &api); + + rip_global_route_changes++; + } +} + +/* Zebra route add and delete treatment. */ +int +rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv4 api; + unsigned long ifindex; + struct in_addr nexthop; + struct prefix_ipv4 p; + + s = zclient->ibuf; + ifindex = 0; + nexthop.s_addr = 0; + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv4 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + nexthop.s_addr = stream_get_ipv4 (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + + /* Then fetch IPv4 prefixes. */ + if (command == ZEBRA_IPV4_ROUTE_ADD) + rip_redistribute_add (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex, &nexthop); + else + rip_redistribute_delete (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex); + + return 0; +} + +void +rip_zclient_reset () +{ + zclient_reset (zclient); +} + +/* RIP route-map set for redistribution */ +void +rip_routemap_set (int type, char *name) +{ + if (rip->route_map[type].name) + free(rip->route_map[type].name); + + rip->route_map[type].name = strdup (name); + rip->route_map[type].map = route_map_lookup_by_name (name); +} + +void +rip_redistribute_metric_set (int type, int metric) +{ + rip->route_map[type].metric_config = 1; + rip->route_map[type].metric = metric; +} + +int +rip_metric_unset (int type,int metric) +{ +#define DONT_CARE_METRIC_RIP 17 + if (metric != DONT_CARE_METRIC_RIP && + rip->route_map[type].metric != metric) + return 1; + rip->route_map[type].metric_config = 0; + rip->route_map[type].metric = 0; + return 0; +} + +/* RIP route-map unset for redistribution */ +int +rip_routemap_unset (int type,char *name) +{ + if (! rip->route_map[type].name || + (name != NULL && strcmp(rip->route_map[type].name,name))) + return 1; + + free (rip->route_map[type].name); + rip->route_map[type].name = NULL; + rip->route_map[type].map = NULL; + + return 0; +} + +/* Redistribution types */ +static struct { + int type; + int str_min_len; + char *str; +} redist_type[] = { + {ZEBRA_ROUTE_KERNEL, 1, "kernel"}, + {ZEBRA_ROUTE_CONNECT, 1, "connected"}, + {ZEBRA_ROUTE_STATIC, 1, "static"}, + {ZEBRA_ROUTE_OSPF, 1, "ospf"}, + {ZEBRA_ROUTE_BGP, 1, "bgp"}, + {0, 0, NULL} +}; + +DEFUN (router_zebra, + router_zebra_cmd, + "router zebra", + "Enable a routing process\n" + "Make connection to zebra daemon\n") +{ + vty->node = ZEBRA_NODE; + zclient->enable = 1; + zclient_start (zclient); + return CMD_SUCCESS; +} + +DEFUN (no_router_zebra, + no_router_zebra_cmd, + "no router zebra", + NO_STR + "Enable a routing process\n" + "Make connection to zebra daemon\n") +{ + zclient->enable = 0; + zclient_stop (zclient); + return CMD_SUCCESS; +} + +int +rip_redistribute_set (int type) +{ + if (zclient->redist[type]) + return CMD_SUCCESS; + + zclient->redist[type] = 1; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type); + + return CMD_SUCCESS; +} + +int +rip_redistribute_unset (int type) +{ + if (! zclient->redist[type]) + return CMD_SUCCESS; + + zclient->redist[type] = 0; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type); + + /* Remove the routes from RIP table. */ + rip_redistribute_withdraw (type); + + return CMD_SUCCESS; +} + +int +rip_redistribute_check (int type) +{ + return (zclient->redist[type]); +} + +void +rip_redistribute_clean () +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (zclient->redist[redist_type[i].type]) + { + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, + zclient->sock, redist_type[i].type); + + zclient->redist[redist_type[i].type] = 0; + + /* Remove the routes from RIP table. */ + rip_redistribute_withdraw (redist_type[i].type); + } + } +} + +DEFUN (rip_redistribute_rip, + rip_redistribute_rip_cmd, + "redistribute rip", + "Redistribute information from another routing protocol\n" + "Routing Information Protocol (RIP)\n") +{ + zclient->redist[ZEBRA_ROUTE_RIP] = 1; + return CMD_SUCCESS; +} + +DEFUN (no_rip_redistribute_rip, + no_rip_redistribute_rip_cmd, + "no redistribute rip", + NO_STR + "Redistribute information from another routing protocol\n" + "Routing Information Protocol (RIP)\n") +{ + zclient->redist[ZEBRA_ROUTE_RIP] = 0; + return CMD_SUCCESS; +} + +DEFUN (rip_redistribute_type, + rip_redistribute_type_cmd, + "redistribute (kernel|connected|static|ospf|bgp)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n") +{ + int i; + + for(i = 0; redist_type[i].str; i++) + { + if (strncmp (redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + zclient_redistribute_set (zclient, redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (no_rip_redistribute_type, + no_rip_redistribute_type_cmd, + "no redistribute (kernel|connected|static|ospf|bgp)", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + rip_metric_unset (redist_type[i].type, DONT_CARE_METRIC_RIP); + rip_routemap_unset (redist_type[i].type,NULL); + rip_redistribute_unset (redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (rip_redistribute_type_routemap, + rip_redistribute_type_routemap_cmd, + "redistribute (kernel|connected|static|ospf|bgp) route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + rip_routemap_set (redist_type[i].type, argv[1]); + zclient_redistribute_set (zclient, redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (no_rip_redistribute_type_routemap, + no_rip_redistribute_type_routemap_cmd, + "no redistribute (kernel|connected|static|ospf|bgp) route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + if (rip_routemap_unset (redist_type[i].type,argv[1])) + return CMD_WARNING; + rip_redistribute_unset (redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (rip_redistribute_type_metric, + rip_redistribute_type_metric_cmd, + "redistribute (kernel|connected|static|ospf|bgp) metric <0-16>", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n") +{ + int i; + int metric; + + metric = atoi (argv[1]); + + for (i = 0; redist_type[i].str; i++) { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + rip_redistribute_metric_set (redist_type[i].type, metric); + zclient_redistribute_set (zclient, redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (no_rip_redistribute_type_metric, + no_rip_redistribute_type_metric_cmd, + "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16>", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + if (rip_metric_unset (redist_type[i].type, atoi(argv[1]))) + return CMD_WARNING; + rip_redistribute_unset (redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +DEFUN (no_rip_redistribute_type_metric_routemap, + no_rip_redistribute_type_metric_routemap_cmd, + "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) + { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) + { + if (rip_metric_unset (redist_type[i].type, atoi(argv[1]))) + return CMD_WARNING; + if (rip_routemap_unset (redist_type[i].type, argv[2])) + { + rip_redistribute_metric_set(redist_type[i].type, atoi(argv[1])); + return CMD_WARNING; + } + rip_redistribute_unset (redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], + VTY_NEWLINE); + + return CMD_WARNING; +} + +/* Default information originate. */ + +DEFUN (rip_default_information_originate, + rip_default_information_originate_cmd, + "default-information originate", + "Control distribution of default route\n" + "Distribute a default route\n") +{ + struct prefix_ipv4 p; + + if (! rip->default_information) + { + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + + rip->default_information = 1; + + rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL); + } + + return CMD_SUCCESS; +} + +DEFUN (no_rip_default_information_originate, + no_rip_default_information_originate_cmd, + "no default-information originate", + NO_STR + "Control distribution of default route\n" + "Distribute a default route\n") +{ + struct prefix_ipv4 p; + + if (rip->default_information) + { + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + + rip->default_information = 0; + + rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0); + } + + return CMD_SUCCESS; +} + +/* RIP configuration write function. */ +int +config_write_zebra (struct vty *vty) +{ + if (! zclient->enable) + { + vty_out (vty, "no router zebra%s", VTY_NEWLINE); + return 1; + } + else if (! zclient->redist[ZEBRA_ROUTE_RIP]) + { + vty_out (vty, "router zebra%s", VTY_NEWLINE); + vty_out (vty, " no redistribute rip%s", VTY_NEWLINE); + return 1; + } + return 0; +} + +int +config_write_rip_redistribute (struct vty *vty, int config_mode) +{ + int i; + char *str[] = { "system", "kernel", "connected", "static", "rip", + "ripng", "ospf", "ospf6", "bgp"}; + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (i != zclient->redist_default && zclient->redist[i]) + { + if (config_mode) + { + if (rip->route_map[i].metric_config) + { + if (rip->route_map[i].name) + vty_out (vty, " redistribute %s metric %d route-map %s%s", + str[i], rip->route_map[i].metric, + rip->route_map[i].name, + VTY_NEWLINE); + else + vty_out (vty, " redistribute %s metric %d%s", + str[i], rip->route_map[i].metric, + VTY_NEWLINE); + } + else + { + if (rip->route_map[i].name) + vty_out (vty, " redistribute %s route-map %s%s", + str[i], rip->route_map[i].name, + VTY_NEWLINE); + else + vty_out (vty, " redistribute %s%s", str[i], + VTY_NEWLINE); + } + } + else + vty_out (vty, " %s", str[i]); + } + return 0; +} + +/* Zebra node structure. */ +struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "%s(config-router)# ", +}; + +void +rip_zclient_init () +{ + /* Set default value to the zebra client structure. */ + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_RIP); + zclient->interface_add = rip_interface_add; + zclient->interface_delete = rip_interface_delete; + zclient->interface_address_add = rip_interface_address_add; + zclient->interface_address_delete = rip_interface_address_delete; + zclient->ipv4_route_add = rip_zebra_read_ipv4; + zclient->ipv4_route_delete = rip_zebra_read_ipv4; + zclient->interface_up = rip_interface_up; + zclient->interface_down = rip_interface_down; + + /* Install zebra node. */ + install_node (&zebra_node, config_write_zebra); + + /* Install command elements to zebra node. */ + install_element (CONFIG_NODE, &router_zebra_cmd); + install_element (CONFIG_NODE, &no_router_zebra_cmd); + install_default (ZEBRA_NODE); + install_element (ZEBRA_NODE, &rip_redistribute_rip_cmd); + install_element (ZEBRA_NODE, &no_rip_redistribute_rip_cmd); + + /* Install command elements to rip node. */ + install_element (RIP_NODE, &rip_redistribute_type_cmd); + install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd); + install_element (RIP_NODE, &rip_redistribute_type_metric_cmd); + install_element (RIP_NODE, &no_rip_redistribute_type_cmd); + install_element (RIP_NODE, &no_rip_redistribute_type_routemap_cmd); + install_element (RIP_NODE, &no_rip_redistribute_type_metric_cmd); + install_element (RIP_NODE, &no_rip_redistribute_type_metric_routemap_cmd); + install_element (RIP_NODE, &rip_default_information_originate_cmd); + install_element (RIP_NODE, &no_rip_default_information_originate_cmd); +} diff --git a/ripd/ripd.c b/ripd/ripd.c new file mode 100644 index 0000000..ad3f296 --- /dev/null +++ b/ripd/ripd.c @@ -0,0 +1,3555 @@ +/* RIP version 1 and 2. + * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "command.h" +#include "prefix.h" +#include "table.h" +#include "thread.h" +#include "memory.h" +#include "log.h" +#include "stream.h" +#include "filter.h" +#include "sockunion.h" +#include "routemap.h" +#include "plist.h" +#include "distribute.h" +#include "md5-gnu.h" +#include "keychain.h" + +#include "ripd/ripd.h" +#include "ripd/rip_debug.h" + +/* RIP Structure. */ +struct rip *rip = NULL; + +/* RIP neighbor address table. */ +struct route_table *rip_neighbor_table; + +/* RIP route changes. */ +long rip_global_route_changes = 0; + +/* RIP queries. */ +long rip_global_queries = 0; + +/* Prototypes. */ +void rip_event (enum rip_event, int); + +void rip_output_process (struct interface *, struct sockaddr_in *, + int, u_char); + +/* RIP output routes type. */ +enum + { + rip_all_route, + rip_changed_route + }; + +/* RIP command strings. */ +struct message rip_msg[] = + { + {RIP_REQUEST, "REQUEST"}, + {RIP_RESPONSE, "RESPONSE"}, + {RIP_TRACEON, "TRACEON"}, + {RIP_TRACEOFF, "TRACEOFF"}, + {RIP_POLL, "POLL"}, + {RIP_POLL_ENTRY, "POLL ENTRY"}, + {0, NULL} + }; + +/* Each route type's strings and default preference. */ +struct +{ + int key; + char *str; + char *str_long; +} route_info[] = + { + { ZEBRA_ROUTE_SYSTEM, "X", "system"}, + { ZEBRA_ROUTE_KERNEL, "K", "kernel"}, + { ZEBRA_ROUTE_CONNECT, "C", "connected"}, + { ZEBRA_ROUTE_STATIC, "S", "static"}, + { ZEBRA_ROUTE_RIP, "R", "rip"}, + { ZEBRA_ROUTE_RIPNG, "R", "ripng"}, + { ZEBRA_ROUTE_OSPF, "O", "ospf"}, + { ZEBRA_ROUTE_OSPF6, "O", "ospf6"}, + { ZEBRA_ROUTE_BGP, "B", "bgp"} + }; + +/* Utility function to set boradcast option to the socket. */ +int +sockopt_broadcast (int sock) +{ + int ret; + int on = 1; + + ret = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof on); + if (ret < 0) + { + zlog_warn ("can't set sockopt SO_BROADCAST to socket %d: %s", + sock, strerror (errno)); + return ret; + } + return 0; +} + +/* Utility function to set size of UDP SO_RCVBUF. */ +static int +sockopt_recvbuf (int sock, int size) +{ + int ret; + + ret = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof (int)); + if (ret < 0) + zlog_warn ("can't setsockopt SO_RCVBUF to socket %d: %s", + sock, strerror (errno)); + return ret; +} + +int +rip_route_rte (struct rip_info *rinfo) +{ + return (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE); +} + +struct rip_info * +rip_info_new () +{ + struct rip_info *new; + + new = XMALLOC (MTYPE_RIP_INFO, sizeof (struct rip_info)); + memset (new, 0, sizeof (struct rip_info)); + return new; +} + +void +rip_info_free (struct rip_info *rinfo) +{ + XFREE (MTYPE_RIP_INFO, rinfo); +} + +/* RIP route garbage collect timer. */ +int +rip_garbage_collect (struct thread *t) +{ + struct rip_info *rinfo; + struct route_node *rp; + + rinfo = THREAD_ARG (t); + rinfo->t_garbage_collect = NULL; + + /* Off timeout timer. */ + RIP_TIMER_OFF (rinfo->t_timeout); + + /* Get route_node pointer. */ + rp = rinfo->rp; + + /* Unlock route_node. */ + rp->info = NULL; + route_unlock_node (rp); + + /* Free RIP routing information. */ + rip_info_free (rinfo); + + return 0; +} + +/* Timeout RIP routes. */ +int +rip_timeout (struct thread *t) +{ + struct rip_info *rinfo; + struct route_node *rn; + + rinfo = THREAD_ARG (t); + rinfo->t_timeout = NULL; + + rn = rinfo->rp; + + /* - The garbage-collection timer is set for 120 seconds. */ + RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, + rip->garbage_time); + + rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop, + rinfo->metric); + /* - The metric for the route is set to 16 (infinity). This causes + the route to be removed from service. */ + rinfo->metric = RIP_METRIC_INFINITY; + rinfo->flags &= ~RIP_RTF_FIB; + + /* - The route change flag is to indicate that this entry has been + changed. */ + rinfo->flags |= RIP_RTF_CHANGED; + + /* - The output process is signalled to trigger a response. */ + rip_event (RIP_TRIGGERED_UPDATE, 0); + + return 0; +} + +void +rip_timeout_update (struct rip_info *rinfo) +{ + if (rinfo->metric != RIP_METRIC_INFINITY) + { + RIP_TIMER_OFF (rinfo->t_timeout); + RIP_TIMER_ON (rinfo->t_timeout, rip_timeout, rip->timeout_time); + } +} + +int +rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri) +{ + struct distribute *dist; + struct access_list *alist; + struct prefix_list *plist; + + /* Input distribute-list filtering. */ + if (ri->list[RIP_FILTER_IN]) + { + if (access_list_apply (ri->list[RIP_FILTER_IN], + (struct prefix *) p) == FILTER_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d filtered by distribute in", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + if (ri->prefix[RIP_FILTER_IN]) + { + if (prefix_list_apply (ri->prefix[RIP_FILTER_IN], + (struct prefix *) p) == PREFIX_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d filtered by prefix-list in", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + + /* All interface filter check. */ + dist = distribute_lookup (NULL); + if (dist) + { + if (dist->list[DISTRIBUTE_IN]) + { + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]); + + if (alist) + { + if (access_list_apply (alist, + (struct prefix *) p) == FILTER_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d filtered by distribute in", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + } + if (dist->prefix[DISTRIBUTE_IN]) + { + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]); + + if (plist) + { + if (prefix_list_apply (plist, + (struct prefix *) p) == PREFIX_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d filtered by prefix-list in", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + } + } + return 0; +} + +int +rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri) +{ + struct distribute *dist; + struct access_list *alist; + struct prefix_list *plist; + + if (ri->list[RIP_FILTER_OUT]) + { + if (access_list_apply (ri->list[RIP_FILTER_OUT], + (struct prefix *) p) == FILTER_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d is filtered by distribute out", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + if (ri->prefix[RIP_FILTER_OUT]) + { + if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT], + (struct prefix *) p) == PREFIX_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d is filtered by prefix-list out", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + + /* All interface filter check. */ + dist = distribute_lookup (NULL); + if (dist) + { + if (dist->list[DISTRIBUTE_OUT]) + { + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]); + + if (alist) + { + if (access_list_apply (alist, + (struct prefix *) p) == FILTER_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d filtered by distribute out", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + } + if (dist->prefix[DISTRIBUTE_OUT]) + { + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]); + + if (plist) + { + if (prefix_list_apply (plist, + (struct prefix *) p) == PREFIX_DENY) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d filtered by prefix-list out", + inet_ntoa (p->prefix), p->prefixlen); + return -1; + } + } + } + } + return 0; +} + +/* Check nexthop address validity. */ +static int +rip_nexthop_check (struct in_addr *addr) +{ + listnode node; + listnode cnode; + struct interface *ifp; + struct connected *ifc; + struct prefix *p; + + /* If nexthop address matches local configured address then it is + invalid nexthop. */ + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + ifc = getdata (cnode); + p = ifc->address; + + if (p->family == AF_INET + && IPV4_ADDR_SAME (&p->u.prefix4, addr)) + return -1; + } + } + return 0; +} + +/* RIP add route to routing table. */ +void +rip_rte_process (struct rte *rte, struct sockaddr_in *from, + struct interface *ifp) + +{ + int ret; + struct prefix_ipv4 p; + struct route_node *rp; + struct rip_info *rinfo; + struct rip_interface *ri; + struct in_addr *nexthop; + u_char oldmetric; + int same = 0; + + /* Make prefix structure. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefix = rte->prefix; + p.prefixlen = ip_masklen (rte->mask); + + /* Make sure mask is applied. */ + apply_mask_ipv4 (&p); + + /* Apply input filters. */ + ri = ifp->info; + + ret = rip_incoming_filter (&p, ri); + if (ret < 0) + return; + + /* Once the entry has been validated, update the metric by + adding the cost of the network on wich the message + arrived. If the result is greater than infinity, use infinity + (RFC2453 Sec. 3.9.2) */ + /* Zebra ripd can handle offset-list in. */ + ret = rip_offset_list_apply_in (&p, ifp, &rte->metric); + + /* If offset-list does not modify the metric use interface's + metric. */ + if (! ret) + rte->metric += ifp->metric; + + if (rte->metric > RIP_METRIC_INFINITY) + rte->metric = RIP_METRIC_INFINITY; + + /* Set nexthop pointer. */ + if (rte->nexthop.s_addr == 0) + nexthop = &from->sin_addr; + else + nexthop = &rte->nexthop; + + /* Check nexthop address. */ + if (rip_nexthop_check (nexthop) < 0) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("Nexthop address %s is invalid", inet_ntoa (*nexthop)); + return; + } + + /* Get index for the prefix. */ + rp = route_node_get (rip->table, (struct prefix *) &p); + + /* Check to see whether there is already RIP route on the table. */ + rinfo = rp->info; + + if (rinfo) + { + /* Redistributed route check. */ + if (rinfo->type != ZEBRA_ROUTE_RIP + && rinfo->metric != RIP_METRIC_INFINITY) + return; + + /* Local static route. */ + if (rinfo->type == ZEBRA_ROUTE_RIP + && rinfo->sub_type == RIP_ROUTE_STATIC + && rinfo->metric != RIP_METRIC_INFINITY) + return; + } + + if (! rinfo) + { + /* Now, check to see whether there is already an explicit route + for the destination prefix. If there is no such route, add + this route to the routing table, unless the metric is + infinity (there is no point in adding a route which + unusable). */ + if (rte->metric != RIP_METRIC_INFINITY) + { + rinfo = rip_info_new (); + + /* - Setting the destination prefix and length to those in + the RTE. */ + rinfo->rp = rp; + + /* - Setting the metric to the newly calculated metric (as + described above). */ + rinfo->metric = rte->metric; + rinfo->tag = ntohs (rte->tag); + + /* - Set the next hop address to be the address of the router + from which the datagram came or the next hop address + specified by a next hop RTE. */ + IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); + IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr); + rinfo->ifindex = ifp->ifindex; + + /* - Initialize the timeout for the route. If the + garbage-collection timer is running for this route, stop it + (see section 2.3 for a discussion of the timers). */ + rip_timeout_update (rinfo); + + /* - Set the route change flag. */ + rinfo->flags |= RIP_RTF_CHANGED; + + /* - Signal the output process to trigger an update (see section + 2.5). */ + rip_event (RIP_TRIGGERED_UPDATE, 0); + + /* Finally, route goes into the kernel. */ + rinfo->type = ZEBRA_ROUTE_RIP; + rinfo->sub_type = RIP_ROUTE_RTE; + + /* Set distance value. */ + rinfo->distance = rip_distance_apply (rinfo); + + rp->info = rinfo; + rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric, + rinfo->distance); + rinfo->flags |= RIP_RTF_FIB; + } + } + else + { + /* Route is there but we are not sure the route is RIP or not. */ + rinfo = rp->info; + + /* If there is an existing route, compare the next hop address + to the address of the router from which the datagram came. + If this datagram is from the same router as the existing + route, reinitialize the timeout. */ + same = IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr); + + if (same) + rip_timeout_update (rinfo); + + /* Next, compare the metrics. If the datagram is from the same + router as the existing route, and the new metric is different + than the old one; or, if the new metric is lower than the old + one; do the following actions: */ + if ((same && (rinfo->metric != rte->metric + || rinfo->tag != rte->tag + || !IPV4_ADDR_SAME(&rte->nexthop, &rinfo->nexthop))) + || rte->metric < rinfo->metric) + { + /* - Adopt the route from the datagram. That is, put the + new metric in, and adjust the next hop address (if + necessary). */ + oldmetric = rinfo->metric; + rinfo->metric = rte->metric; + rinfo->tag = ntohs (rte->tag); + IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr); + rinfo->ifindex = ifp->ifindex; + rinfo->distance = rip_distance_apply (rinfo); + + /* Should a new route to this network be established + while the garbage-collection timer is running, the + new route will replace the one that is about to be + deleted. In this case the garbage-collection timer + must be cleared. */ + + if (oldmetric == RIP_METRIC_INFINITY && + rinfo->metric < RIP_METRIC_INFINITY) + { + rinfo->type = ZEBRA_ROUTE_RIP; + rinfo->sub_type = RIP_ROUTE_RTE; + + RIP_TIMER_OFF (rinfo->t_garbage_collect); + + if (! IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) + IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); + + rip_zebra_ipv4_add (&p, nexthop, rinfo->metric, + rinfo->distance); + rinfo->flags |= RIP_RTF_FIB; + } + + /* Update nexthop and/or metric value. */ + if (oldmetric != RIP_METRIC_INFINITY) + { + rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric); + rip_zebra_ipv4_add (&p, nexthop, rinfo->metric, + rinfo->distance); + rinfo->flags |= RIP_RTF_FIB; + + if (! IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) + IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); + } + + /* - Set the route change flag and signal the output process + to trigger an update. */ + rinfo->flags |= RIP_RTF_CHANGED; + rip_event (RIP_TRIGGERED_UPDATE, 0); + + /* - If the new metric is infinity, start the deletion + process (described above); */ + if (rinfo->metric == RIP_METRIC_INFINITY) + { + /* If the new metric is infinity, the deletion process + begins for the route, which is no longer used for + routing packets. Note that the deletion process is + started only when the metric is first set to + infinity. If the metric was already infinity, then a + new deletion process is not started. */ + if (oldmetric != RIP_METRIC_INFINITY) + { + /* - The garbage-collection timer is set for 120 seconds. */ + RIP_TIMER_ON (rinfo->t_garbage_collect, + rip_garbage_collect, rip->garbage_time); + RIP_TIMER_OFF (rinfo->t_timeout); + + /* - The metric for the route is set to 16 + (infinity). This causes the route to be removed + from service.*/ + rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric); + rinfo->flags &= ~RIP_RTF_FIB; + + /* - The route change flag is to indicate that this + entry has been changed. */ + /* - The output process is signalled to trigger a + response. */ + ; /* Above processes are already done previously. */ + } + } + else + { + /* otherwise, re-initialize the timeout. */ + rip_timeout_update (rinfo); + } + } + /* Unlock tempolary lock of the route. */ + route_unlock_node (rp); + } +} + +/* Dump RIP packet */ +void +rip_packet_dump (struct rip_packet *packet, int size, char *sndrcv) +{ + caddr_t lim; + struct rte *rte; + char *command_str; + char pbuf[BUFSIZ], nbuf[BUFSIZ]; + u_char netmask = 0; + u_char *p; + + /* Set command string. */ + if (packet->command > 0 && packet->command < RIP_COMMAND_MAX) + command_str = lookup (rip_msg, packet->command); + else + command_str = "unknown"; + + /* Dump packet header. */ + zlog_info ("%s %s version %d packet size %d", + sndrcv, command_str, packet->version, size); + + /* Dump each routing table entry. */ + rte = packet->rte; + + for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++) + { + if (packet->version == RIPv2) + { + netmask = ip_masklen (rte->mask); + + if (ntohs (rte->family) == 0xffff) + { + if (ntohs (rte->tag) == RIP_AUTH_SIMPLE_PASSWORD) + { + p = (u_char *)&rte->prefix; + + zlog_info (" family 0x%X type %d auth string: %s", + ntohs (rte->family), ntohs (rte->tag), p); + } + else if (ntohs (rte->tag) == RIP_AUTH_MD5) + { + struct rip_md5_info *md5; + + md5 = (struct rip_md5_info *) &packet->rte; + + zlog_info (" family 0x%X type %d (MD5 authentication)", + ntohs (md5->family), ntohs (md5->type)); + zlog_info (" RIP-2 packet len %d Key ID %d" + " Auth Data len %d", ntohs (md5->packet_len), + md5->keyid, md5->auth_len); + zlog_info (" Sequence Number %ld", (u_long)ntohl (md5->sequence)); + } + else if (ntohs (rte->tag) == RIP_AUTH_DATA) + { + p = (u_char *)&rte->prefix; + + zlog_info (" family 0x%X type %d (MD5 data)", + ntohs (rte->family), ntohs (rte->tag)); + zlog_info (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X", + p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7], + p[9],p[10],p[11],p[12],p[13],p[14],p[15]); + } + else + { + zlog_info (" family 0x%X type %d (Unknown auth type)", + ntohs (rte->family), ntohs (rte->tag)); + } + } + else + zlog_info (" %s/%d -> %s family %d tag %d metric %ld", + inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),netmask, + inet_ntop (AF_INET, &rte->nexthop, nbuf, BUFSIZ), + ntohs (rte->family), ntohs (rte->tag), + (u_long)ntohl (rte->metric)); + } + else + { + zlog_info (" %s family %d tag %d metric %ld", + inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ), + ntohs (rte->family), ntohs (rte->tag), + (u_long)ntohl (rte->metric)); + } + } +} + +/* Check if the destination address is valid (unicast; not net 0 + or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't + check net 0 because we accept default route. */ +int +rip_destination_check (struct in_addr addr) +{ + u_int32_t destination; + + /* Convert to host byte order. */ + destination = ntohl (addr.s_addr); + + if (IPV4_NET127 (destination)) + return 0; + + /* Net 0 may match to the default route. */ + if (IPV4_NET0 (destination) && destination != 0) + return 0; + + /* Unicast address must belong to class A, B, C. */ + if (IN_CLASSA (destination)) + return 1; + if (IN_CLASSB (destination)) + return 1; + if (IN_CLASSC (destination)) + return 1; + + return 0; +} + +/* RIP version 2 authentication. */ +int +rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from, + struct interface *ifp) +{ + struct rip_interface *ri; + char *auth_str; + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("RIPv2 simple password authentication from %s", + inet_ntoa (from->sin_addr)); + + ri = ifp->info; + + if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD + || ntohs (rte->tag) != RIP_AUTH_SIMPLE_PASSWORD) + return 0; + + /* Simple password authentication. */ + if (ri->auth_str) + { + auth_str = (char *) &rte->prefix; + + if (strncmp (auth_str, ri->auth_str, 16) == 0) + return 1; + } + if (ri->key_chain) + { + struct keychain *keychain; + struct key *key; + + keychain = keychain_lookup (ri->key_chain); + if (keychain == NULL) + return 0; + + key = key_match_for_accept (keychain, (char *) &rte->prefix); + if (key) + return 1; + } + return 0; +} + +/* RIP version 2 authentication with MD5. */ +int +rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from, + struct interface *ifp) +{ + struct rip_interface *ri; + struct rip_md5_info *md5; + struct rip_md5_data *md5data; + struct keychain *keychain; + struct key *key; + struct md5_ctx ctx; + u_char pdigest[RIP_AUTH_MD5_SIZE]; + u_char digest[RIP_AUTH_MD5_SIZE]; + u_int16_t packet_len; + char *auth_str = NULL; + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("RIPv2 MD5 authentication from %s", inet_ntoa (from->sin_addr)); + + ri = ifp->info; + md5 = (struct rip_md5_info *) &packet->rte; + + /* Check auth type. */ + if (ri->auth_type != RIP_AUTH_MD5 || ntohs (md5->type) != RIP_AUTH_MD5) + return 0; + + if (md5->auth_len != RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE) + return 0; + + if (ri->key_chain) + { + keychain = keychain_lookup (ri->key_chain); + if (keychain == NULL) + return 0; + + key = key_lookup_for_accept (keychain, md5->keyid); + if (key == NULL) + return 0; + + auth_str = key->string; + } + + if (ri->auth_str) + auth_str = ri->auth_str; + + if (! auth_str) + return 0; + + /* MD5 digest authentication. */ + packet_len = ntohs (md5->packet_len); + md5data = (struct rip_md5_data *)(((u_char *) packet) + packet_len); + + /* Save digest to pdigest. */ + memcpy (pdigest, md5data->digest, RIP_AUTH_MD5_SIZE); + + /* Overwrite digest by my secret. */ + memset (md5data->digest, 0, RIP_AUTH_MD5_SIZE); + strncpy (md5data->digest, auth_str, RIP_AUTH_MD5_SIZE); + + md5_init_ctx (&ctx); + md5_process_bytes (packet, packet_len + md5->auth_len, &ctx); + md5_finish_ctx (&ctx, digest); + + if (memcmp (pdigest, digest, RIP_AUTH_MD5_SIZE) == 0) + return packet_len; + else + return 0; +} + +void +rip_auth_md5_set (struct stream *s, struct interface *ifp) +{ + struct rip_interface *ri; + struct keychain *keychain = NULL; + struct key *key = NULL; + unsigned long len; + struct md5_ctx ctx; + unsigned char secret[RIP_AUTH_MD5_SIZE]; + unsigned char digest[RIP_AUTH_MD5_SIZE]; + char *auth_str = NULL; + + ri = ifp->info; + + /* Make it sure this interface is configured as MD5 + authentication. */ + if (ri->auth_type != RIP_AUTH_MD5) + return; + + /* Lookup key chain. */ + if (ri->key_chain) + { + keychain = keychain_lookup (ri->key_chain); + if (keychain == NULL) + return; + + /* Lookup key. */ + key = key_lookup_for_send (keychain); + if (key == NULL) + return; + + auth_str = key->string; + } + + if (ri->auth_str) + auth_str = ri->auth_str; + + if (! auth_str) + return; + + /* Get packet length. */ + len = s->putp; + + /* Check packet length. */ + if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE)) + { + zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len); + return; + } + + /* Move RTE. */ + memmove (s->data + RIP_HEADER_SIZE + RIP_RTE_SIZE, + s->data + RIP_HEADER_SIZE, + len - RIP_HEADER_SIZE); + + /* Set pointer to authentication header. */ + stream_set_putp (s, RIP_HEADER_SIZE); + len += RIP_RTE_SIZE; + + /* MD5 authentication. */ + stream_putw (s, 0xffff); + stream_putw (s, RIP_AUTH_MD5); + + /* RIP-2 Packet length. Actual value is filled in + rip_auth_md5_set(). */ + stream_putw (s, len); + + /* Key ID. */ + if (key) + stream_putc (s, key->index % 256); + else + stream_putc (s, 1); + + /* Auth Data Len. Set 16 for MD5 authentication + data. */ + stream_putc (s, RIP_AUTH_MD5_SIZE + RIP_HEADER_SIZE); + + /* Sequence Number (non-decreasing). */ + /* RFC2080: The value used in the sequence number is + arbitrary, but two suggestions are the time of the + message's creation or a simple message counter. */ + stream_putl (s, time (NULL)); + + /* Reserved field must be zero. */ + stream_putl (s, 0); + stream_putl (s, 0); + + /* Set pointer to authentication data. */ + stream_set_putp (s, len); + + /* Set authentication data. */ + stream_putw (s, 0xffff); + stream_putw (s, 0x01); + + /* Generate a digest for the RIP packet. */ + memset (secret, 0, RIP_AUTH_MD5_SIZE); + strncpy (secret, auth_str, RIP_AUTH_MD5_SIZE); + md5_init_ctx (&ctx); + md5_process_bytes (s->data, s->endp, &ctx); + md5_process_bytes (secret, RIP_AUTH_MD5_SIZE, &ctx); + md5_finish_ctx (&ctx, digest); + + /* Copy the digest to the packet. */ + stream_write (s, digest, RIP_AUTH_MD5_SIZE); +} + +/* RIP routing information. */ +void +rip_response_process (struct rip_packet *packet, int size, + struct sockaddr_in *from, struct interface *ifp) +{ + caddr_t lim; + struct rte *rte; + + /* The Response must be ignored if it is not from the RIP + port. (RFC2453 - Sec. 3.9.2)*/ + if (ntohs (from->sin_port) != RIP_PORT_DEFAULT) + { + zlog_info ("response doesn't come from RIP port: %d", + from->sin_port); + rip_peer_bad_packet (from); + return; + } + + /* The datagram's IPv4 source address should be checked to see + whether the datagram is from a valid neighbor; the source of the + datagram must be on a directly connected network */ + if (! if_valid_neighbor (from->sin_addr)) + { + zlog_info ("This datagram doesn't came from a valid neighbor: %s", + inet_ntoa (from->sin_addr)); + rip_peer_bad_packet (from); + return; + } + + /* It is also worth checking to see whether the response is from one + of the router's own addresses. */ + + ; /* Alredy done in rip_read () */ + + /* Update RIP peer. */ + rip_peer_update (from, packet->version); + + /* Set RTE pointer. */ + rte = packet->rte; + + for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++) + { + /* RIPv2 authentication check. */ + /* If the Address Family Identifier of the first (and only the + first) entry in the message is 0xFFFF, then the remainder of + the entry contains the authentication. */ + /* If the packet gets here it means authentication enabled */ + /* Check is done in rip_read(). So, just skipping it */ + if (packet->version == RIPv2 && + rte == packet->rte && + rte->family == 0xffff) + continue; + + if (ntohs (rte->family) != AF_INET) + { + /* Address family check. RIP only supports AF_INET. */ + zlog_info ("Unsupported family %d from %s.", + ntohs (rte->family), inet_ntoa (from->sin_addr)); + continue; + } + + /* - is the destination address valid (e.g., unicast; not net 0 + or 127) */ + if (! rip_destination_check (rte->prefix)) + { + zlog_info ("Network is net 0 or net 127 or it is not unicast network"); + rip_peer_bad_route (from); + continue; + } + + /* Convert metric value to host byte order. */ + rte->metric = ntohl (rte->metric); + + /* - is the metric valid (i.e., between 1 and 16, inclusive) */ + if (! (rte->metric >= 1 && rte->metric <= 16)) + { + zlog_info ("Route's metric is not in the 1-16 range."); + rip_peer_bad_route (from); + continue; + } + + /* RIPv1 does not have nexthop value. */ + if (packet->version == RIPv1 && rte->nexthop.s_addr != 0) + { + zlog_info ("RIPv1 packet with nexthop value %s", + inet_ntoa (rte->nexthop)); + rip_peer_bad_route (from); + continue; + } + + /* That is, if the provided information is ignored, a possibly + sub-optimal, but absolutely valid, route may be taken. If + the received Next Hop is not directly reachable, it should be + treated as 0.0.0.0. */ + if (packet->version == RIPv2 && rte->nexthop.s_addr != 0) + { + u_int32_t addrval; + + /* Multicast address check. */ + addrval = ntohl (rte->nexthop.s_addr); + if (IN_CLASSD (addrval)) + { + zlog_info ("Nexthop %s is multicast address, skip this rte", + inet_ntoa (rte->nexthop)); + continue; + } + + if (! if_lookup_address (rte->nexthop)) + { + struct route_node *rn; + struct rip_info *rinfo; + + rn = route_node_match_ipv4 (rip->table, &rte->nexthop); + + if (rn) + { + rinfo = rn->info; + + if (rinfo->type == ZEBRA_ROUTE_RIP + && rinfo->sub_type == RIP_ROUTE_RTE) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("Next hop %s is on RIP network. Set nexthop to the packet's originator", inet_ntoa (rte->nexthop)); + rte->nexthop = rinfo->from; + } + else + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop)); + rte->nexthop.s_addr = 0; + } + + route_unlock_node (rn); + } + else + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop)); + rte->nexthop.s_addr = 0; + } + + } + } + + /* For RIPv1, there won't be a valid netmask. + + This is a best guess at the masks. If everyone was using old + Ciscos before the 'ip subnet zero' option, it would be almost + right too :-) + + Cisco summarize ripv1 advertisments to the classful boundary + (/16 for class B's) except when the RIP packet does to inside + the classful network in question. */ + + if ((packet->version == RIPv1 && rte->prefix.s_addr != 0) + || (packet->version == RIPv2 + && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0))) + { + u_int32_t destination; + + destination = ntohl (rte->prefix.s_addr); + + if (destination & 0xff) + { + masklen2ip (32, &rte->mask); + } + else if ((destination & 0xff00) || IN_CLASSC (destination)) + { + masklen2ip (24, &rte->mask); + } + else if ((destination & 0xff0000) || IN_CLASSB (destination)) + { + masklen2ip (16, &rte->mask); + } + else + { + masklen2ip (8, &rte->mask); + } + } + + /* In case of RIPv2, if prefix in RTE is not netmask applied one + ignore the entry. */ + if ((packet->version == RIPv2) + && (rte->mask.s_addr != 0) + && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)) + { + zlog_warn ("RIPv2 address %s is not mask /%d applied one", + inet_ntoa (rte->prefix), ip_masklen (rte->mask)); + rip_peer_bad_route (from); + continue; + } + + /* Default route's netmask is ignored. */ + if (packet->version == RIPv2 + && (rte->prefix.s_addr == 0) + && (rte->mask.s_addr != 0)) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("Default route with non-zero netmask. Set zero to netmask"); + rte->mask.s_addr = 0; + } + + /* Routing table updates. */ + rip_rte_process (rte, from, ifp); + } +} + +/* RIP packet send to destination address. */ +int +rip_send_packet (caddr_t buf, int size, struct sockaddr_in *to, + struct interface *ifp) +{ + int ret; + struct sockaddr_in sin; + int sock; + + /* Make destination address. */ + memset (&sin, 0, sizeof (struct sockaddr_in)); + sin.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + sin.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + + /* When destination is specified, use it's port and address. */ + if (to) + { + sock = rip->sock; + + sin.sin_port = to->sin_port; + sin.sin_addr = to->sin_addr; + } + else + { + sock = socket (AF_INET, SOCK_DGRAM, 0); + + sockopt_broadcast (sock); + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); + + sin.sin_port = htons (RIP_PORT_DEFAULT); + sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP); + + /* Set multicast interface. */ + rip_interface_multicast_set (sock, ifp); + } + + ret = sendto (sock, buf, size, 0, (struct sockaddr *)&sin, + sizeof (struct sockaddr_in)); + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("SEND to socket %d port %d addr %s", + sock, ntohs (sin.sin_port), inet_ntoa(sin.sin_addr)); + + if (ret < 0) + zlog_warn ("can't send packet : %s", strerror (errno)); + + if (! to) + close (sock); + + return ret; +} + +/* Add redistributed route to RIP table. */ +void +rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, + unsigned int ifindex, struct in_addr *nexthop) +{ + int ret; + struct route_node *rp; + struct rip_info *rinfo; + + /* Redistribute route */ + ret = rip_destination_check (p->prefix); + if (! ret) + return; + + rp = route_node_get (rip->table, (struct prefix *) p); + + rinfo = rp->info; + + if (rinfo) + { + if (rinfo->type == ZEBRA_ROUTE_CONNECT + && rinfo->sub_type == RIP_ROUTE_INTERFACE + && rinfo->metric != RIP_METRIC_INFINITY) + { + route_unlock_node (rp); + return; + } + + /* Manually configured RIP route check. */ + if (rinfo->type == ZEBRA_ROUTE_RIP + && rinfo->sub_type == RIP_ROUTE_STATIC) + { + if (type != ZEBRA_ROUTE_RIP || sub_type != RIP_ROUTE_STATIC) + { + route_unlock_node (rp); + return; + } + } + + RIP_TIMER_OFF (rinfo->t_timeout); + RIP_TIMER_OFF (rinfo->t_garbage_collect); + + if (rip_route_rte (rinfo)) + rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop, + rinfo->metric); + rp->info = NULL; + rip_info_free (rinfo); + + route_unlock_node (rp); + } + + rinfo = rip_info_new (); + + rinfo->type = type; + rinfo->sub_type = sub_type; + rinfo->ifindex = ifindex; + rinfo->metric = 1; + rinfo->rp = rp; + + if (nexthop) + rinfo->nexthop = *nexthop; + + rinfo->flags |= RIP_RTF_FIB; + rp->info = rinfo; + + rinfo->flags |= RIP_RTF_CHANGED; + + rip_event (RIP_TRIGGERED_UPDATE, 0); +} + +/* Delete redistributed route from RIP table. */ +void +rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p, + unsigned int ifindex) +{ + int ret; + struct route_node *rp; + struct rip_info *rinfo; + + ret = rip_destination_check (p->prefix); + if (! ret) + return; + + rp = route_node_lookup (rip->table, (struct prefix *) p); + if (rp) + { + rinfo = rp->info; + + if (rinfo != NULL + && rinfo->type == type + && rinfo->sub_type == sub_type + && rinfo->ifindex == ifindex) + { + /* Perform poisoned reverse. */ + rinfo->metric = RIP_METRIC_INFINITY; + RIP_TIMER_ON (rinfo->t_garbage_collect, + rip_garbage_collect, rip->garbage_time); + RIP_TIMER_OFF (rinfo->t_timeout); + rinfo->flags |= RIP_RTF_CHANGED; + + rip_event (RIP_TRIGGERED_UPDATE, 0); + } + } +} + +/* Response to request called from rip_read ().*/ +void +rip_request_process (struct rip_packet *packet, int size, + struct sockaddr_in *from, struct interface *ifp) +{ + caddr_t lim; + struct rte *rte; + struct prefix_ipv4 p; + struct route_node *rp; + struct rip_info *rinfo; + struct rip_interface *ri; + + ri = ifp->info; + + /* When passive interface is specified, suppress responses */ + if (ri->passive) + return; + + /* RIP peer update. */ + rip_peer_update (from, packet->version); + + lim = ((caddr_t) packet) + size; + rte = packet->rte; + + /* The Request is processed entry by entry. If there are no + entries, no response is given. */ + if (lim == (caddr_t) rte) + return; + + /* There is one special case. If there is exactly one entry in the + request, and it has an address family identifier of zero and a + metric of infinity (i.e., 16), then this is a request to send the + entire routing table. */ + if ((rte->family == 0xFFFF) && (lim == ((caddr_t) (rte + 2)) )) rte++; + + if (lim == ((caddr_t) (rte + 1)) && + ntohs (rte->family) == 0 && + ntohl (rte->metric) == RIP_METRIC_INFINITY) + { + /* All route with split horizon */ + rip_output_process (ifp, from, rip_all_route, packet->version); + } + else + { + /* Examine the list of RTEs in the Request one by one. For each + entry, look up the destination in the router's routing + database and, if there is a route, put that route's metric in + the metric field of the RTE. If there is no explicit route + to the specified destination, put infinity in the metric + field. Once all the entries have been filled in, change the + command from Request to Response and send the datagram back + to the requestor. */ + p.family = AF_INET; + + for (; ((caddr_t) rte) < lim; rte++) + { + p.prefix = rte->prefix; + p.prefixlen = ip_masklen (rte->mask); + apply_mask_ipv4 (&p); + + rp = route_node_lookup (rip->table, (struct prefix *) &p); + if (rp) + { + rinfo = rp->info; + rte->metric = htonl (rinfo->metric); + route_unlock_node (rp); + } + else + rte->metric = htonl (RIP_METRIC_INFINITY); + } + packet->command = RIP_RESPONSE; + + rip_send_packet ((caddr_t) packet, size, from, ifp); + } + rip_global_queries++; +} + +#if RIP_RECVMSG +/* Set IPv6 packet info to the socket. */ +static int +setsockopt_pktinfo (int sock) +{ + int ret; + int val = 1; + + ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val)); + if (ret < 0) + zlog_warn ("Can't setsockopt IP_PKTINFO : %s", strerror (errno)); + return ret; +} + +/* Read RIP packet by recvmsg function. */ +int +rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from, + int *ifindex) +{ + int ret; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *ptr; + char adata[1024]; + + msg.msg_name = (void *) from; + msg.msg_namelen = sizeof (struct sockaddr_in); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = (void *) adata; + msg.msg_controllen = sizeof adata; + iov.iov_base = buf; + iov.iov_len = size; + + ret = recvmsg (sock, &msg, 0); + if (ret < 0) + return ret; + + for (ptr = CMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr)) + if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO) + { + struct in_pktinfo *pktinfo; + int i; + + pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr); + i = pktinfo->ipi_ifindex; + } + return ret; +} + +/* RIP packet read function. */ +int +rip_read_new (struct thread *t) +{ + int ret; + int sock; + char buf[RIP_PACKET_MAXSIZ]; + struct sockaddr_in from; + unsigned int ifindex; + + /* Fetch socket then register myself. */ + sock = THREAD_FD (t); + rip_event (RIP_READ, sock); + + /* Read RIP packet. */ + ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex); + if (ret < 0) + { + zlog_warn ("Can't read RIP packet: %s", strerror (errno)); + return ret; + } + + return ret; +} +#endif /* RIP_RECVMSG */ + +/* First entry point of RIP packet. */ +int +rip_read (struct thread *t) +{ + int sock; + int ret; + int rtenum; + union rip_buf rip_buf; + struct rip_packet *packet; + struct sockaddr_in from; + int fromlen, len; + struct interface *ifp; + struct rip_interface *ri; + + /* Fetch socket then register myself. */ + sock = THREAD_FD (t); + rip->t_read = NULL; + + /* Add myself to tne next event */ + rip_event (RIP_READ, sock); + + /* RIPd manages only IPv4. */ + memset (&from, 0, sizeof (struct sockaddr_in)); + fromlen = sizeof (struct sockaddr_in); + + len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0, + (struct sockaddr *) &from, &fromlen); + if (len < 0) + { + zlog_info ("recvfrom failed: %s", strerror (errno)); + return len; + } + + /* Check is this packet comming from myself? */ + if (if_check_address (from.sin_addr)) + { + if (IS_RIP_DEBUG_PACKET) + zlog_warn ("ignore packet comes from myself"); + return -1; + } + + /* Which interface is this packet comes from. */ + ifp = if_lookup_address (from.sin_addr); + + /* RIP packet received */ + if (IS_RIP_DEBUG_EVENT) + zlog_info ("RECV packet from %s port %d on %s", + inet_ntoa (from.sin_addr), ntohs (from.sin_port), + ifp ? ifp->name : "unknown"); + + /* If this packet come from unknown interface, ignore it. */ + if (ifp == NULL) + { + zlog_info ("packet comes from unknown interface"); + return -1; + } + + /* Packet length check. */ + if (len < RIP_PACKET_MINSIZ) + { + zlog_warn ("packet size %d is smaller than minimum size %d", + len, RIP_PACKET_MINSIZ); + rip_peer_bad_packet (&from); + return len; + } + if (len > RIP_PACKET_MAXSIZ) + { + zlog_warn ("packet size %d is larger than max size %d", + len, RIP_PACKET_MAXSIZ); + rip_peer_bad_packet (&from); + return len; + } + + /* Packet alignment check. */ + if ((len - RIP_PACKET_MINSIZ) % 20) + { + zlog_warn ("packet size %d is wrong for RIP packet alignment", len); + rip_peer_bad_packet (&from); + return len; + } + + /* Set RTE number. */ + rtenum = ((len - RIP_PACKET_MINSIZ) / 20); + + /* For easy to handle. */ + packet = &rip_buf.rip_packet; + + /* RIP version check. */ + if (packet->version == 0) + { + zlog_info ("version 0 with command %d received.", packet->command); + rip_peer_bad_packet (&from); + return -1; + } + + /* Dump RIP packet. */ + if (IS_RIP_DEBUG_RECV) + rip_packet_dump (packet, len, "RECV"); + + /* RIP version adjust. This code should rethink now. RFC1058 says + that "Version 1 implementations are to ignore this extra data and + process only the fields specified in this document.". So RIPv3 + packet should be treated as RIPv1 ignoring must be zero field. */ + if (packet->version > RIPv2) + packet->version = RIPv2; + + /* Is RIP running or is this RIP neighbor ?*/ + ri = ifp->info; + if (! ri->running && ! rip_neighbor_lookup (&from)) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("RIP is not enabled on interface %s.", ifp->name); + rip_peer_bad_packet (&from); + return -1; + } + + /* RIP Version check. */ + if (packet->command == RIP_RESPONSE) + { + if (ri->ri_receive == RI_RIP_UNSPEC) + { + if (packet->version != rip->version) + { + if (IS_RIP_DEBUG_PACKET) + zlog_warn (" packet's v%d doesn't fit to my version %d", + packet->version, rip->version); + rip_peer_bad_packet (&from); + return -1; + } + } + else + { + if (packet->version == RIPv1) + if (! (ri->ri_receive & RIPv1)) + { + if (IS_RIP_DEBUG_PACKET) + zlog_warn (" packet's v%d doesn't fit to if version spec", + packet->version); + rip_peer_bad_packet (&from); + return -1; + } + if (packet->version == RIPv2) + if (! (ri->ri_receive & RIPv2)) + { + if (IS_RIP_DEBUG_PACKET) + zlog_warn (" packet's v%d doesn't fit to if version spec", + packet->version); + rip_peer_bad_packet (&from); + return -1; + } + } + } + + /* RFC2453 5.2 If the router is not configured to authenticate RIP-2 + messages, then RIP-1 and unauthenticated RIP-2 messages will be + accepted; authenticated RIP-2 messages shall be discarded. */ + + if ((ri->auth_type == RIP_NO_AUTH) + && rtenum + && (packet->version == RIPv2) && (packet->rte->family == 0xffff)) + { + if (IS_RIP_DEBUG_EVENT) + zlog_warn ("packet RIPv%d is dropped because authentication disabled", + packet->version); + rip_peer_bad_packet (&from); + return -1; + } + + /* If the router is configured to authenticate RIP-2 messages, then + RIP-1 messages and RIP-2 messages which pass authentication + testing shall be accepted; unauthenticated and failed + authentication RIP-2 messages shall be discarded. For maximum + security, RIP-1 messages should be ignored when authentication is + in use (see section 4.1); otherwise, the routing information from + authenticated messages will be propagated by RIP-1 routers in an + unauthenticated manner. */ + + if ((ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD + || ri->auth_type == RIP_AUTH_MD5) + && rtenum) + { + /* We follow maximum security. */ + if (packet->version == RIPv1 && packet->rte->family == 0xffff) + { + if (IS_RIP_DEBUG_PACKET) + zlog_warn ("packet RIPv%d is dropped because authentication enabled", packet->version); + rip_peer_bad_packet (&from); + return -1; + } + + /* Check RIPv2 authentication. */ + if (packet->version == RIPv2) + { + if (packet->rte->family == 0xffff) + { + if (ntohs (packet->rte->tag) == RIP_AUTH_SIMPLE_PASSWORD) + { + ret = rip_auth_simple_password (packet->rte, &from, ifp); + if (! ret) + { + if (IS_RIP_DEBUG_EVENT) + zlog_warn ("RIPv2 simple password authentication failed"); + rip_peer_bad_packet (&from); + return -1; + } + else + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("RIPv2 simple password authentication success"); + } + } + else if (ntohs (packet->rte->tag) == RIP_AUTH_MD5) + { + ret = rip_auth_md5 (packet, &from, ifp); + if (! ret) + { + if (IS_RIP_DEBUG_EVENT) + zlog_warn ("RIPv2 MD5 authentication failed"); + rip_peer_bad_packet (&from); + return -1; + } + else + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("RIPv2 MD5 authentication success"); + } + /* Reset RIP packet length to trim MD5 data. */ + len = ret; + } + else + { + if (IS_RIP_DEBUG_EVENT) + zlog_warn ("Unknown authentication type %d", + ntohs (packet->rte->tag)); + rip_peer_bad_packet (&from); + return -1; + } + } + else + { + /* There is no authentication in the packet. */ + if (ri->auth_str || ri->key_chain) + { + if (IS_RIP_DEBUG_EVENT) + zlog_warn ("RIPv2 authentication failed: no authentication in packet"); + rip_peer_bad_packet (&from); + return -1; + } + } + } + } + + /* Process each command. */ + switch (packet->command) + { + case RIP_RESPONSE: + rip_response_process (packet, len, &from, ifp); + break; + case RIP_REQUEST: + case RIP_POLL: + rip_request_process (packet, len, &from, ifp); + break; + case RIP_TRACEON: + case RIP_TRACEOFF: + zlog_info ("Obsolete command %s received, please sent it to routed", + lookup (rip_msg, packet->command)); + rip_peer_bad_packet (&from); + break; + case RIP_POLL_ENTRY: + zlog_info ("Obsolete command %s received", + lookup (rip_msg, packet->command)); + rip_peer_bad_packet (&from); + break; + default: + zlog_info ("Unknown RIP command %d received", packet->command); + rip_peer_bad_packet (&from); + break; + } + + return len; +} + +/* Make socket for RIP protocol. */ +int +rip_create_socket () +{ + int ret; + int sock; + struct sockaddr_in addr; + struct servent *sp; + + memset (&addr, 0, sizeof (struct sockaddr_in)); + + /* Set RIP port. */ + sp = getservbyname ("router", "udp"); + if (sp) + addr.sin_port = sp->s_port; + else + addr.sin_port = htons (RIP_PORT_DEFAULT); + + /* Address shoud be any address. */ + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + + /* Make datagram socket. */ + sock = socket (AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + { + perror ("socket"); + exit (1); + } + + sockopt_broadcast (sock); + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); + sockopt_recvbuf (sock, RIP_UDP_RCV_BUF); +#ifdef RIP_RECVMSG + setsockopt_pktinfo (sock); +#endif /* RIP_RECVMSG */ + + ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr)); + if (ret < 0) + { + perror ("bind"); + return ret; + } + + return sock; +} + +/* Write routing table entry to the stream and return next index of + the routing table entry in the stream. */ +int +rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p, + u_char version, struct rip_info *rinfo, struct interface *ifp) +{ + struct in_addr mask; + struct rip_interface *ri; + + /* RIP packet header. */ + if (num == 0) + { + stream_putc (s, RIP_RESPONSE); + stream_putc (s, version); + stream_putw (s, 0); + + /* In case of we need RIPv2 authentication. */ + if (version == RIPv2 && ifp) + { + ri = ifp->info; + + if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD) + { + if (ri->auth_str) + { + stream_putw (s, 0xffff); + stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD); + + memset ((s->data + s->putp), 0, 16); + strncpy ((s->data + s->putp), ri->auth_str, 16); + stream_set_putp (s, s->putp + 16); + + num++; + } + if (ri->key_chain) + { + struct keychain *keychain; + struct key *key; + + keychain = keychain_lookup (ri->key_chain); + + if (keychain) + { + key = key_lookup_for_send (keychain); + + if (key) + { + stream_putw (s, 0xffff); + stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD); + + memset ((s->data + s->putp), 0, 16); + strncpy ((s->data + s->putp), key->string, 16); + stream_set_putp (s, s->putp + 16); + + num++; + } + } + } + } + } + } + + /* Write routing table entry. */ + if (version == RIPv1) + { + stream_putw (s, AF_INET); + stream_putw (s, 0); + stream_put_ipv4 (s, p->prefix.s_addr); + stream_put_ipv4 (s, 0); + stream_put_ipv4 (s, 0); + stream_putl (s, rinfo->metric_out); + } + else + { + masklen2ip (p->prefixlen, &mask); + + stream_putw (s, AF_INET); + stream_putw (s, rinfo->tag); + stream_put_ipv4 (s, p->prefix.s_addr); + stream_put_ipv4 (s, mask.s_addr); + stream_put_ipv4 (s, rinfo->nexthop_out.s_addr); + stream_putl (s, rinfo->metric_out); + } + + return ++num; +} + +/* Send update to the ifp or spcified neighbor. */ +void +rip_output_process (struct interface *ifp, struct sockaddr_in *to, + int route_type, u_char version) +{ + int ret; + struct stream *s; + struct route_node *rp; + struct rip_info *rinfo; + struct rip_interface *ri; + struct prefix_ipv4 *p; + struct prefix_ipv4 classfull; + int num; + int rtemax; + + /* Logging output event. */ + if (IS_RIP_DEBUG_EVENT) + { + if (to) + zlog_info ("update routes to neighbor %s", inet_ntoa (to->sin_addr)); + else + zlog_info ("update routes on interface %s ifindex %d", + ifp->name, ifp->ifindex); + } + + /* Set output stream. */ + s = rip->obuf; + + /* Reset stream and RTE counter. */ + stream_reset (s); + num = 0; + rtemax = (RIP_PACKET_MAXSIZ - 4) / 20; + + /* Get RIP interface. */ + ri = ifp->info; + + /* If output interface is in simple password authentication mode, we + need space for authentication data. */ + if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD) + rtemax -= 1; + + /* If output interface is in MD5 authentication mode, we need space + for authentication header and data. */ + if (ri->auth_type == RIP_AUTH_MD5) + rtemax -= 2; + + /* If output interface is in simple password authentication mode + and string or keychain is specified we need space for auth. data */ + if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD) + { + if (ri->key_chain) + { + struct keychain *keychain; + + keychain = keychain_lookup (ri->key_chain); + if (keychain) + if (key_lookup_for_send (keychain)) + rtemax -=1; + } + else + if (ri->auth_str) + rtemax -=1; + } + + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + { + /* Some inheritance stuff: */ + /* Before we process with ipv4 prefix we should mask it */ + /* with Classful mask if we send RIPv1 packet.That's because */ + /* user could set non-classful mask or we could get it by RIPv2 */ + /* or other protocol. checked with Cisco's way of life :) */ + + if (version == RIPv1) + { + memcpy (&classfull, &rp->p, sizeof (struct prefix_ipv4)); + + if (IS_RIP_DEBUG_PACKET) + zlog_info("%s/%d before RIPv1 mask check ", + inet_ntoa (classfull.prefix), classfull.prefixlen); + + apply_classful_mask_ipv4 (&classfull); + p = &classfull; + + if (IS_RIP_DEBUG_PACKET) + zlog_info("%s/%d after RIPv1 mask check", + inet_ntoa (p->prefix), p->prefixlen); + } + else + p = (struct prefix_ipv4 *) &rp->p; + + /* Apply output filters. */ + ret = rip_outgoing_filter (p, ri); + if (ret < 0) + continue; + + /* Changed route only output. */ + if (route_type == rip_changed_route && + (! (rinfo->flags & RIP_RTF_CHANGED))) + continue; + + /* Split horizon. */ + /* if (split_horizon == rip_split_horizon) */ + if (ri->split_horizon) + { + /* We perform split horizon for RIP and connected route. */ + if ((rinfo->type == ZEBRA_ROUTE_RIP || + rinfo->type == ZEBRA_ROUTE_CONNECT) && + rinfo->ifindex == ifp->ifindex) + continue; + } + + /* Preparation for route-map. */ + rinfo->metric_set = 0; + rinfo->nexthop_out.s_addr = 0; + rinfo->metric_out = rinfo->metric; + rinfo->ifindex_out = ifp->ifindex; + + /* In order to avoid some local loops, if the RIP route has a + nexthop via this interface, keep the nexthop, otherwise set + it to 0. The nexthop should not be propagated beyond the + local broadcast/multicast area in order to avoid an IGP + multi-level recursive look-up. For RIP and connected + route, we don't set next hop value automatically. For + settting next hop to those routes, please use + route-map. */ + + if (rinfo->type != ZEBRA_ROUTE_RIP + && rinfo->type != ZEBRA_ROUTE_CONNECT + && rinfo->ifindex == ifp->ifindex) + rinfo->nexthop_out = rinfo->nexthop; + + /* Apply route map - continue, if deny */ + if (rip->route_map[rinfo->type].name + && rinfo->sub_type != RIP_ROUTE_INTERFACE) + { + ret = route_map_apply (rip->route_map[rinfo->type].map, + (struct prefix *)p, RMAP_RIP, rinfo); + + if (ret == RMAP_DENYMATCH) + { + if (IS_RIP_DEBUG_PACKET) + zlog_info ("%s/%d is filtered by route-map", + inet_ntoa (p->prefix), p->prefixlen); + continue; + } + } + + /* When route-map does not set metric. */ + if (! rinfo->metric_set) + { + /* If redistribute metric is set. */ + if (rip->route_map[rinfo->type].metric_config + && rinfo->metric != RIP_METRIC_INFINITY) + { + rinfo->metric_out = rip->route_map[rinfo->type].metric; + } + else + { + /* If the route is not connected or localy generated + one, use default-metric value*/ + if (rinfo->type != ZEBRA_ROUTE_RIP + && rinfo->type != ZEBRA_ROUTE_CONNECT + && rinfo->metric != RIP_METRIC_INFINITY) + rinfo->metric_out = rip->default_metric; + } + } + + /* Apply offset-list */ + if (rinfo->metric != RIP_METRIC_INFINITY) + rip_offset_list_apply_out (p, ifp, &rinfo->metric_out); + + if (rinfo->metric_out > RIP_METRIC_INFINITY) + rinfo->metric_out = RIP_METRIC_INFINITY; + + /* Write RTE to the stream. */ + num = rip_write_rte (num, s, p, version, rinfo, to ? NULL : ifp); + if (num == rtemax) + { + if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5) + rip_auth_md5_set (s, ifp); + + ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), + to, ifp); + + if (ret >= 0 && IS_RIP_DEBUG_SEND) + rip_packet_dump ((struct rip_packet *)STREAM_DATA (s), + stream_get_endp(s), "SEND"); + num = 0; + stream_reset (s); + } + } + + /* Flush unwritten RTE. */ + if (num != 0) + { + if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5) + rip_auth_md5_set (s, ifp); + + ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifp); + + if (ret >= 0 && IS_RIP_DEBUG_SEND) + rip_packet_dump ((struct rip_packet *)STREAM_DATA (s), + stream_get_endp (s), "SEND"); + num = 0; + stream_reset (s); + } + + /* Statistics updates. */ + ri->sent_updates++; +} + +/* Send RIP packet to the interface. */ +void +rip_update_interface (struct interface *ifp, u_char version, int route_type) +{ + struct prefix_ipv4 *p; + struct connected *connected; + listnode node; + struct sockaddr_in to; + + /* When RIP version is 2 and multicast enable interface. */ + if (version == RIPv2 && if_is_multicast (ifp)) + { + if (IS_RIP_DEBUG_EVENT) + zlog_info ("multicast announce on %s ", ifp->name); + + rip_output_process (ifp, NULL, route_type, version); + return; + } + + /* If we can't send multicast packet, send it with unicast. */ + if (if_is_broadcast (ifp) || if_is_pointopoint (ifp)) + { + for (node = listhead (ifp->connected); node; nextnode (node)) + { + connected = getdata (node); + + /* Fetch broadcast address or poin-to-point destination + address . */ + p = (struct prefix_ipv4 *) connected->destination; + + if (p->family == AF_INET) + { + /* Destination address and port setting. */ + memset (&to, 0, sizeof (struct sockaddr_in)); + to.sin_addr = p->prefix; + to.sin_port = htons (RIP_PORT_DEFAULT); + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("%s announce to %s on %s", + if_is_pointopoint (ifp) ? "unicast" : "broadcast", + inet_ntoa (to.sin_addr), ifp->name); + + rip_output_process (ifp, &to, route_type, version); + } + } + } +} + +/* Update send to all interface and neighbor. */ +void +rip_update_process (int route_type) +{ + listnode node; + struct interface *ifp; + struct rip_interface *ri; + struct route_node *rp; + struct sockaddr_in to; + struct prefix_ipv4 *p; + + /* Send RIP update to each interface. */ + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + if (if_is_loopback (ifp)) + continue; + + if (! if_is_up (ifp)) + continue; + + /* Fetch RIP interface information. */ + ri = ifp->info; + + /* When passive interface is specified, suppress announce to the + interface. */ + if (ri->passive) + continue; + + if (ri->running) + { + if (IS_RIP_DEBUG_EVENT) + { + if (ifp->name) + zlog_info ("SEND UPDATE to %s ifindex %d", + ifp->name, ifp->ifindex); + else + zlog_info ("SEND UPDATE to _unknown_ ifindex %d", + ifp->ifindex); + } + + /* If there is no version configuration in the interface, + use rip's version setting. */ + if (ri->ri_send == RI_RIP_UNSPEC) + { + if (rip->version == RIPv1) + rip_update_interface (ifp, RIPv1, route_type); + else + rip_update_interface (ifp, RIPv2, route_type); + } + /* If interface has RIP version configuration use it. */ + else + { + if (ri->ri_send & RIPv1) + rip_update_interface (ifp, RIPv1, route_type); + if (ri->ri_send & RIPv2) + rip_update_interface (ifp, RIPv2, route_type); + } + } + } + + /* RIP send updates to each neighbor. */ + for (rp = route_top (rip->neighbor); rp; rp = route_next (rp)) + if (rp->info != NULL) + { + p = (struct prefix_ipv4 *) &rp->p; + + ifp = if_lookup_address (p->prefix); + if (! ifp) + { + zlog_warn ("Neighbor %s doesn't exist direct connected network", + inet_ntoa (p->prefix)); + continue; + } + + /* Set destination address and port */ + memset (&to, 0, sizeof (struct sockaddr_in)); + to.sin_addr = p->prefix; + to.sin_port = htons (RIP_PORT_DEFAULT); + + /* RIP version is rip's configuration. */ + rip_output_process (ifp, &to, route_type, rip->version); + } +} + +/* RIP's periodical timer. */ +int +rip_update (struct thread *t) +{ + /* Clear timer pointer. */ + rip->t_update = NULL; + + if (IS_RIP_DEBUG_EVENT) + zlog_info ("update timer fire!"); + + /* Process update output. */ + rip_update_process (rip_all_route); + + /* Triggered updates may be suppressed if a regular update is due by + the time the triggered update would be sent. */ + if (rip->t_triggered_interval) + { + thread_cancel (rip->t_triggered_interval); + rip->t_triggered_interval = NULL; + } + rip->trigger = 0; + + /* Register myself. */ + rip_event (RIP_UPDATE_EVENT, 0); + + return 0; +} + +/* Walk down the RIP routing table then clear changed flag. */ +void +rip_clear_changed_flag () +{ + struct route_node *rp; + struct rip_info *rinfo; + + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + if (rinfo->flags & RIP_RTF_CHANGED) + rinfo->flags &= ~RIP_RTF_CHANGED; +} + +/* Triggered update interval timer. */ +int +rip_triggered_interval (struct thread *t) +{ + int rip_triggered_update (struct thread *); + + rip->t_triggered_interval = NULL; + + if (rip->trigger) + { + rip->trigger = 0; + rip_triggered_update (t); + } + return 0; +} + +/* Execute triggered update. */ +int +rip_triggered_update (struct thread *t) +{ + int interval; + + /* Clear thred pointer. */ + rip->t_triggered_update = NULL; + + /* Cancel interval timer. */ + if (rip->t_triggered_interval) + { + thread_cancel (rip->t_triggered_interval); + rip->t_triggered_interval = NULL; + } + rip->trigger = 0; + + /* Logging triggered update. */ + if (IS_RIP_DEBUG_EVENT) + zlog_info ("triggered update!"); + + /* Split Horizon processing is done when generating triggered + updates as well as normal updates (see section 2.6). */ + rip_update_process (rip_changed_route); + + /* Once all of the triggered updates have been generated, the route + change flags should be cleared. */ + rip_clear_changed_flag (); + + /* After a triggered update is sent, a timer should be set for a + random interval between 1 and 5 seconds. If other changes that + would trigger updates occur before the timer expires, a single + update is triggered when the timer expires. */ + interval = (random () % 5) + 1; + + rip->t_triggered_interval = + thread_add_timer (master, rip_triggered_interval, NULL, interval); + + return 0; +} + +/* Withdraw redistributed route. */ +void +rip_redistribute_withdraw (int type) +{ + struct route_node *rp; + struct rip_info *rinfo; + + if (!rip) + return; + + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + { + if (rinfo->type == type + && rinfo->sub_type != RIP_ROUTE_INTERFACE) + { + /* Perform poisoned reverse. */ + rinfo->metric = RIP_METRIC_INFINITY; + RIP_TIMER_ON (rinfo->t_garbage_collect, + rip_garbage_collect, rip->garbage_time); + RIP_TIMER_OFF (rinfo->t_timeout); + rinfo->flags |= RIP_RTF_CHANGED; + + rip_event (RIP_TRIGGERED_UPDATE, 0); + } + } +} + +/* Create new RIP instance and set it to global variable. */ +int +rip_create () +{ + rip = XMALLOC (MTYPE_RIP, sizeof (struct rip)); + memset (rip, 0, sizeof (struct rip)); + + /* Set initial value. */ + rip->version = RIPv2; + rip->update_time = RIP_UPDATE_TIMER_DEFAULT; + rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT; + rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT; + rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT; + + /* Initialize RIP routig table. */ + rip->table = route_table_init (); + rip->route = route_table_init (); + rip->neighbor = route_table_init (); + + /* Make output stream. */ + rip->obuf = stream_new (1500); + + /* Make socket. */ + rip->sock = rip_create_socket (); + if (rip->sock < 0) + return rip->sock; + + /* Create read and timer thread. */ + rip_event (RIP_READ, rip->sock); + rip_event (RIP_UPDATE_EVENT, 1); + + return 0; +} + +/* Sned RIP request to the destination. */ +int +rip_request_send (struct sockaddr_in *to, struct interface *ifp, + u_char version) +{ + struct rte *rte; + struct rip_packet rip_packet; + + memset (&rip_packet, 0, sizeof (rip_packet)); + + rip_packet.command = RIP_REQUEST; + rip_packet.version = version; + rte = rip_packet.rte; + rte->metric = htonl (RIP_METRIC_INFINITY); + + return rip_send_packet ((caddr_t) &rip_packet, sizeof (rip_packet), to, ifp); +} + +int +rip_update_jitter (unsigned long time) +{ + return ((rand () % (time + 1)) - (time / 2)); +} + +void +rip_event (enum rip_event event, int sock) +{ + int jitter = 0; + + switch (event) + { + case RIP_READ: + rip->t_read = thread_add_read (master, rip_read, NULL, sock); + break; + case RIP_UPDATE_EVENT: + if (rip->t_update) + { + thread_cancel (rip->t_update); + rip->t_update = NULL; + } + jitter = rip_update_jitter (rip->update_time); + rip->t_update = + thread_add_timer (master, rip_update, NULL, + sock ? 2 : rip->update_time + jitter); + break; + case RIP_TRIGGERED_UPDATE: + if (rip->t_triggered_interval) + rip->trigger = 1; + else if (! rip->t_triggered_update) + rip->t_triggered_update = + thread_add_event (master, rip_triggered_update, NULL, 0); + break; + default: + break; + } +} + +DEFUN (router_rip, + router_rip_cmd, + "router rip", + "Enable a routing process\n" + "Routing Information Protocol (RIP)\n") +{ + int ret; + + /* If rip is not enabled before. */ + if (! rip) + { + ret = rip_create (); + if (ret < 0) + { + zlog_info ("Can't create RIP"); + return CMD_WARNING; + } + } + vty->node = RIP_NODE; + vty->index = rip; + + return CMD_SUCCESS; +} + +DEFUN (no_router_rip, + no_router_rip_cmd, + "no router rip", + NO_STR + "Enable a routing process\n" + "Routing Information Protocol (RIP)\n") +{ + if (rip) + rip_clean (); + return CMD_SUCCESS; +} + +DEFUN (rip_version, + rip_version_cmd, + "version <1-2>", + "Set routing protocol version\n" + "version\n") +{ + int version; + + version = atoi (argv[0]); + if (version != RIPv1 && version != RIPv2) + { + vty_out (vty, "invalid rip version %d%s", version, + VTY_NEWLINE); + return CMD_WARNING; + } + rip->version = version; + + return CMD_SUCCESS; +} + +DEFUN (no_rip_version, + no_rip_version_cmd, + "no version", + NO_STR + "Set routing protocol version\n") +{ + /* Set RIP version to the default. */ + rip->version = RIPv2; + + return CMD_SUCCESS; +} + +ALIAS (no_rip_version, + no_rip_version_val_cmd, + "no version <1-2>", + NO_STR + "Set routing protocol version\n" + "version\n"); + +DEFUN (rip_route, + rip_route_cmd, + "route A.B.C.D/M", + "RIP static route configuration\n" + "IP prefix /\n") +{ + int ret; + struct prefix_ipv4 p; + struct route_node *node; + + ret = str2prefix_ipv4 (argv[0], &p); + if (ret < 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask_ipv4 (&p); + + /* For router rip configuration. */ + node = route_node_get (rip->route, (struct prefix *) &p); + + if (node->info) + { + vty_out (vty, "There is already same static route.%s", VTY_NEWLINE); + route_unlock_node (node); + return CMD_WARNING; + } + + node->info = "static"; + + rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL); + + return CMD_SUCCESS; +} + +DEFUN (no_rip_route, + no_rip_route_cmd, + "no route A.B.C.D/M", + NO_STR + "RIP static route configuration\n" + "IP prefix /\n") +{ + int ret; + struct prefix_ipv4 p; + struct route_node *node; + + ret = str2prefix_ipv4 (argv[0], &p); + if (ret < 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask_ipv4 (&p); + + /* For router rip configuration. */ + node = route_node_lookup (rip->route, (struct prefix *) &p); + if (! node) + { + vty_out (vty, "Can't find route %s.%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0); + route_unlock_node (node); + + node->info = NULL; + route_unlock_node (node); + + return CMD_SUCCESS; +} + +void +rip_update_default_metric () +{ + struct route_node *np; + struct rip_info *rinfo; + + for (np = route_top (rip->table); np; np = route_next (np)) + if ((rinfo = np->info) != NULL) + if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT) + rinfo->metric = rip->default_metric; +} + +DEFUN (rip_default_metric, + rip_default_metric_cmd, + "default-metric <1-16>", + "Set a metric of redistribute routes\n" + "Default metric\n") +{ + if (rip) + { + rip->default_metric = atoi (argv[0]); + /* rip_update_default_metric (); */ + } + return CMD_SUCCESS; +} + +DEFUN (no_rip_default_metric, + no_rip_default_metric_cmd, + "no default-metric", + NO_STR + "Set a metric of redistribute routes\n" + "Default metric\n") +{ + if (rip) + { + rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT; + /* rip_update_default_metric (); */ + } + return CMD_SUCCESS; +} + +ALIAS (no_rip_default_metric, + no_rip_default_metric_val_cmd, + "no default-metric <1-16>", + NO_STR + "Set a metric of redistribute routes\n" + "Default metric\n"); + +DEFUN (rip_timers, + rip_timers_cmd, + "timers basic <5-2147483647> <5-2147483647> <5-2147483647>", + "Adjust routing timers\n" + "Basic routing protocol update timers\n" + "Routing table update timer value in second. Default is 30.\n" + "Routing information timeout timer. Default is 180.\n" + "Garbage collection timer. Default is 120.\n") +{ + unsigned long update; + unsigned long timeout; + unsigned long garbage; + char *endptr = NULL; + unsigned long RIP_TIMER_MAX = 2147483647; + unsigned long RIP_TIMER_MIN = 5; + + update = strtoul (argv[0], &endptr, 10); + if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0') + { + vty_out (vty, "update timer value error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + timeout = strtoul (argv[1], &endptr, 10); + if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0') + { + vty_out (vty, "timeout timer value error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + garbage = strtoul (argv[2], &endptr, 10); + if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0') + { + vty_out (vty, "garbage timer value error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Set each timer value. */ + rip->update_time = update; + rip->timeout_time = timeout; + rip->garbage_time = garbage; + + /* Reset update timer thread. */ + rip_event (RIP_UPDATE_EVENT, 0); + + return CMD_SUCCESS; +} + +DEFUN (no_rip_timers, + no_rip_timers_cmd, + "no timers basic", + NO_STR + "Adjust routing timers\n" + "Basic routing protocol update timers\n") +{ + /* Set each timer value to the default. */ + rip->update_time = RIP_UPDATE_TIMER_DEFAULT; + rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT; + rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT; + + /* Reset update timer thread. */ + rip_event (RIP_UPDATE_EVENT, 0); + + return CMD_SUCCESS; +} + +struct route_table *rip_distance_table; + +struct rip_distance +{ + /* Distance value for the IP source prefix. */ + u_char distance; + + /* Name of the access-list to be matched. */ + char *access_list; +}; + +struct rip_distance * +rip_distance_new () +{ + struct rip_distance *new; + new = XMALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance)); + memset (new, 0, sizeof (struct rip_distance)); + return new; +} + +void +rip_distance_free (struct rip_distance *rdistance) +{ + XFREE (MTYPE_RIP_DISTANCE, rdistance); +} + +int +rip_distance_set (struct vty *vty, char *distance_str, char *ip_str, + char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct route_node *rn; + struct rip_distance *rdistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + /* Get RIP distance node. */ + rn = route_node_get (rip_distance_table, (struct prefix *) &p); + if (rn->info) + { + rdistance = rn->info; + route_unlock_node (rn); + } + else + { + rdistance = rip_distance_new (); + rn->info = rdistance; + } + + /* Set distance value. */ + rdistance->distance = distance; + + /* Reset access-list configuration. */ + if (rdistance->access_list) + { + free (rdistance->access_list); + rdistance->access_list = NULL; + } + if (access_list_str) + rdistance->access_list = strdup (access_list_str); + + return CMD_SUCCESS; +} + +int +rip_distance_unset (struct vty *vty, char *distance_str, char *ip_str, + char *access_list_str) +{ + int ret; + struct prefix_ipv4 p; + u_char distance; + struct route_node *rn; + struct rip_distance *rdistance; + + ret = str2prefix_ipv4 (ip_str, &p); + if (ret == 0) + { + vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + distance = atoi (distance_str); + + rn = route_node_lookup (rip_distance_table, (struct prefix *)&p); + if (! rn) + { + vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rdistance = rn->info; + + if (rdistance->access_list) + free (rdistance->access_list); + rip_distance_free (rdistance); + + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + + return CMD_SUCCESS; +} + +void +rip_distance_reset () +{ + struct route_node *rn; + struct rip_distance *rdistance; + + for (rn = route_top (rip_distance_table); rn; rn = route_next (rn)) + if ((rdistance = rn->info) != NULL) + { + if (rdistance->access_list) + free (rdistance->access_list); + rip_distance_free (rdistance); + rn->info = NULL; + route_unlock_node (rn); + } +} + +/* Apply RIP information to distance method. */ +u_char +rip_distance_apply (struct rip_info *rinfo) +{ + struct route_node *rn; + struct prefix_ipv4 p; + struct rip_distance *rdistance; + struct access_list *alist; + + if (! rip) + return 0; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefix = rinfo->from; + p.prefixlen = IPV4_MAX_BITLEN; + + /* Check source address. */ + rn = route_node_match (rip_distance_table, (struct prefix *) &p); + if (rn) + { + rdistance = rn->info; + route_unlock_node (rn); + + if (rdistance->access_list) + { + alist = access_list_lookup (AFI_IP, rdistance->access_list); + if (alist == NULL) + return 0; + if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY) + return 0; + + return rdistance->distance; + } + else + return rdistance->distance; + } + + if (rip->distance) + return rip->distance; + + return 0; +} + +void +rip_distance_show (struct vty *vty) +{ + struct route_node *rn; + struct rip_distance *rdistance; + int header = 1; + char buf[BUFSIZ]; + + vty_out (vty, " Distance: (default is %d)%s", + rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT, + VTY_NEWLINE); + + for (rn = route_top (rip_distance_table); rn; rn = route_next (rn)) + if ((rdistance = rn->info) != NULL) + { + if (header) + { + vty_out (vty, " Address Distance List%s", + VTY_NEWLINE); + header = 0; + } + sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); + vty_out (vty, " %-20s %4d %s%s", + buf, rdistance->distance, + rdistance->access_list ? rdistance->access_list : "", + VTY_NEWLINE); + } +} + +DEFUN (rip_distance, + rip_distance_cmd, + "distance <1-255>", + "Administrative distance\n" + "Distance value\n") +{ + rip->distance = atoi (argv[0]); + return CMD_SUCCESS; +} + +DEFUN (no_rip_distance, + no_rip_distance_cmd, + "no distance <1-255>", + NO_STR + "Administrative distance\n" + "Distance value\n") +{ + rip->distance = 0; + return CMD_SUCCESS; +} + +DEFUN (rip_distance_source, + rip_distance_source_cmd, + "distance <1-255> A.B.C.D/M", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") +{ + rip_distance_set (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (no_rip_distance_source, + no_rip_distance_source_cmd, + "no distance <1-255> A.B.C.D/M", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") +{ + rip_distance_unset (vty, argv[0], argv[1], NULL); + return CMD_SUCCESS; +} + +DEFUN (rip_distance_source_access_list, + rip_distance_source_access_list_cmd, + "distance <1-255> A.B.C.D/M WORD", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + rip_distance_set (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} + +DEFUN (no_rip_distance_source_access_list, + no_rip_distance_source_access_list_cmd, + "no distance <1-255> A.B.C.D/M WORD", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") +{ + rip_distance_unset (vty, argv[0], argv[1], argv[2]); + return CMD_SUCCESS; +} + +/* Print out routes update time. */ +void +rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo) +{ + struct timeval timer_now; + time_t clock; + struct tm *tm; +#define TIME_BUF 25 + char timebuf [TIME_BUF]; + struct thread *thread; + + gettimeofday (&timer_now, NULL); + + if ((thread = rinfo->t_timeout) != NULL) + { + clock = thread->u.sands.tv_sec - timer_now.tv_sec; + tm = gmtime (&clock); + strftime (timebuf, TIME_BUF, "%M:%S", tm); + vty_out (vty, "%5s", timebuf); + } + else if ((thread = rinfo->t_garbage_collect) != NULL) + { + clock = thread->u.sands.tv_sec - timer_now.tv_sec; + tm = gmtime (&clock); + strftime (timebuf, TIME_BUF, "%M:%S", tm); + vty_out (vty, "%5s", timebuf); + } +} + +char * +rip_route_type_print (int sub_type) +{ + switch (sub_type) + { + case RIP_ROUTE_RTE: + return "n"; + case RIP_ROUTE_STATIC: + return "s"; + case RIP_ROUTE_DEFAULT: + return "d"; + case RIP_ROUTE_REDISTRIBUTE: + return "r"; + case RIP_ROUTE_INTERFACE: + return "i"; + default: + return "?"; + } +} + +DEFUN (show_ip_rip, + show_ip_rip_cmd, + "show ip rip", + SHOW_STR + IP_STR + "Show RIP routes\n") +{ + struct route_node *np; + struct rip_info *rinfo; + + if (! rip) + return CMD_SUCCESS; + + vty_out (vty, "Codes: R - RIP, C - connected, O - OSPF, B - BGP%s" + " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s" + " (i) - interface%s%s" + " Network Next Hop Metric From Time%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + for (np = route_top (rip->table); np; np = route_next (np)) + if ((rinfo = np->info) != NULL) + { + int len; + + len = vty_out (vty, "%s(%s) %s/%d", + /* np->lock, For debugging. */ + route_info[rinfo->type].str, + rip_route_type_print (rinfo->sub_type), + inet_ntoa (np->p.u.prefix4), np->p.prefixlen); + + len = 24 - len; + + if (len > 0) + vty_out (vty, "%*s", len, " "); + + if (rinfo->nexthop.s_addr) + vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop), + rinfo->metric); + else + vty_out (vty, "0.0.0.0 %2d ", rinfo->metric); + + /* Route which exist in kernel routing table. */ + if ((rinfo->type == ZEBRA_ROUTE_RIP) && + (rinfo->sub_type == RIP_ROUTE_RTE)) + { + vty_out (vty, "%-15s ", inet_ntoa (rinfo->from)); + rip_vty_out_uptime (vty, rinfo); + } + else if (rinfo->metric == RIP_METRIC_INFINITY) + { + vty_out (vty, "self "); + rip_vty_out_uptime (vty, rinfo); + } + else + vty_out (vty, "self"); + + vty_out (vty, "%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +/* Return next event time. */ +int +rip_next_thread_timer (struct thread *thread) +{ + struct timeval timer_now; + + gettimeofday (&timer_now, NULL); + + return thread->u.sands.tv_sec - timer_now.tv_sec; +} + +DEFUN (show_ip_protocols_rip, + show_ip_protocols_rip_cmd, + "show ip protocols", + SHOW_STR + IP_STR + "IP routing protocol process parameters and statistics\n") +{ + listnode node; + struct interface *ifp; + struct rip_interface *ri; + extern struct message ri_version_msg[]; + char *send_version; + char *receive_version; + + if (! rip) + return CMD_SUCCESS; + + vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE); + vty_out (vty, " Sending updates every %ld seconds with +/-50%%,", + rip->update_time); + vty_out (vty, " next due in %d seconds%s", + rip_next_thread_timer (rip->t_update), + VTY_NEWLINE); + vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time); + vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time, + VTY_NEWLINE); + + /* Filtering status show. */ + config_show_distribute (vty); + + /* Default metric information. */ + vty_out (vty, " Default redistribution metric is %d%s", + rip->default_metric, VTY_NEWLINE); + + /* Redistribute information. */ + vty_out (vty, " Redistributing:"); + config_write_rip_redistribute (vty, 0); + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, " Default version control: send version %d,", rip->version); + vty_out (vty, " receive version %d %s", rip->version, + VTY_NEWLINE); + + vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE); + + for (node = listhead (iflist); node; node = nextnode (node)) + { + ifp = getdata (node); + ri = ifp->info; + + if (ri->enable_network || ri->enable_interface) + { + if (ri->ri_send == RI_RIP_UNSPEC) + send_version = lookup (ri_version_msg, rip->version); + else + send_version = lookup (ri_version_msg, ri->ri_send); + + if (ri->ri_receive == RI_RIP_UNSPEC) + receive_version = lookup (ri_version_msg, rip->version); + else + receive_version = lookup (ri_version_msg, ri->ri_receive); + + vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name, + send_version, + receive_version, + ri->key_chain ? ri->key_chain : "", + VTY_NEWLINE); + } + } + + vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE); + config_write_rip_network (vty, 0); + + vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE); + vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE); + rip_peer_display (vty); + + rip_distance_show (vty); + + return CMD_SUCCESS; +} + +/* RIP configuration write function. */ +int +config_write_rip (struct vty *vty) +{ + int write = 0; + struct route_node *rn; + struct rip_distance *rdistance; + + if (rip) + { + /* Router RIP statement. */ + vty_out (vty, "router rip%s", VTY_NEWLINE); + write++; + + /* RIP version statement. Default is RIP version 2. */ + if (rip->version != RIPv2) + vty_out (vty, " version %d%s", rip->version, + VTY_NEWLINE); + + /* RIP timer configuration. */ + if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT + || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT + || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT) + vty_out (vty, " timers basic %lu %lu %lu%s", + rip->update_time, + rip->timeout_time, + rip->garbage_time, + VTY_NEWLINE); + + /* Default information configuration. */ + if (rip->default_information) + { + if (rip->default_information_route_map) + vty_out (vty, " default-information originate route-map %s%s", + rip->default_information_route_map, VTY_NEWLINE); + else + vty_out (vty, " default-information originate%s", + VTY_NEWLINE); + } + + /* Redistribute configuration. */ + config_write_rip_redistribute (vty, 1); + + /* RIP offset-list configuration. */ + config_write_rip_offset_list (vty); + + /* RIP enabled network and interface configuration. */ + config_write_rip_network (vty, 1); + + /* RIP default metric configuration */ + if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT) + vty_out (vty, " default-metric %d%s", + rip->default_metric, VTY_NEWLINE); + + /* Distribute configuration. */ + write += config_write_distribute (vty); + + /* Distance configuration. */ + if (rip->distance) + vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE); + + /* RIP source IP prefix distance configuration. */ + for (rn = route_top (rip_distance_table); rn; rn = route_next (rn)) + if ((rdistance = rn->info) != NULL) + vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance, + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + rdistance->access_list ? rdistance->access_list : "", + VTY_NEWLINE); + + /* RIP static route configuration. */ + for (rn = route_top (rip->route); rn; rn = route_next (rn)) + if (rn->info) + vty_out (vty, " route %s/%d%s", + inet_ntoa (rn->p.u.prefix4), + rn->p.prefixlen, + VTY_NEWLINE); + + } + return write; +} + +/* RIP node structure. */ +struct cmd_node rip_node = + { + RIP_NODE, + "%s(config-router)# ", + 1 + }; + +/* Distribute-list update functions. */ +void +rip_distribute_update (struct distribute *dist) +{ + struct interface *ifp; + struct rip_interface *ri; + struct access_list *alist; + struct prefix_list *plist; + + if (! dist->ifname) + return; + + ifp = if_lookup_by_name (dist->ifname); + if (ifp == NULL) + return; + + ri = ifp->info; + + if (dist->list[DISTRIBUTE_IN]) + { + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]); + if (alist) + ri->list[RIP_FILTER_IN] = alist; + else + ri->list[RIP_FILTER_IN] = NULL; + } + else + ri->list[RIP_FILTER_IN] = NULL; + + if (dist->list[DISTRIBUTE_OUT]) + { + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]); + if (alist) + ri->list[RIP_FILTER_OUT] = alist; + else + ri->list[RIP_FILTER_OUT] = NULL; + } + else + ri->list[RIP_FILTER_OUT] = NULL; + + if (dist->prefix[DISTRIBUTE_IN]) + { + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]); + if (plist) + ri->prefix[RIP_FILTER_IN] = plist; + else + ri->prefix[RIP_FILTER_IN] = NULL; + } + else + ri->prefix[RIP_FILTER_IN] = NULL; + + if (dist->prefix[DISTRIBUTE_OUT]) + { + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]); + if (plist) + ri->prefix[RIP_FILTER_OUT] = plist; + else + ri->prefix[RIP_FILTER_OUT] = NULL; + } + else + ri->prefix[RIP_FILTER_OUT] = NULL; +} + +void +rip_distribute_update_interface (struct interface *ifp) +{ + struct distribute *dist; + + dist = distribute_lookup (ifp->name); + if (dist) + rip_distribute_update (dist); +} + +/* Update all interface's distribute list. */ +void +rip_distribute_update_all () +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + rip_distribute_update_interface (ifp); + } +} + +/* Delete all added rip route. */ +void +rip_clean () +{ + int i; + struct route_node *rp; + struct rip_info *rinfo; + + if (rip) + { + /* Clear RIP routes */ + for (rp = route_top (rip->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + { + if (rinfo->type == ZEBRA_ROUTE_RIP && + rinfo->sub_type == RIP_ROUTE_RTE) + rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, + &rinfo->nexthop, rinfo->metric); + + RIP_TIMER_OFF (rinfo->t_timeout); + RIP_TIMER_OFF (rinfo->t_garbage_collect); + + rp->info = NULL; + route_unlock_node (rp); + + rip_info_free (rinfo); + } + + /* Cancel RIP related timers. */ + RIP_TIMER_OFF (rip->t_update); + RIP_TIMER_OFF (rip->t_triggered_update); + RIP_TIMER_OFF (rip->t_triggered_interval); + + /* Cancel read thread. */ + if (rip->t_read) + { + thread_cancel (rip->t_read); + rip->t_read = NULL; + } + + /* Close RIP socket. */ + if (rip->sock >= 0) + { + close (rip->sock); + rip->sock = -1; + } + + /* Static RIP route configuration. */ + for (rp = route_top (rip->route); rp; rp = route_next (rp)) + if (rp->info) + { + rp->info = NULL; + route_unlock_node (rp); + } + + /* RIP neighbor configuration. */ + for (rp = route_top (rip->neighbor); rp; rp = route_next (rp)) + if (rp->info) + { + rp->info = NULL; + route_unlock_node (rp); + } + + /* Redistribute related clear. */ + if (rip->default_information_route_map) + free (rip->default_information_route_map); + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (rip->route_map[i].name) + free (rip->route_map[i].name); + + XFREE (MTYPE_ROUTE_TABLE, rip->table); + XFREE (MTYPE_ROUTE_TABLE, rip->route); + XFREE (MTYPE_ROUTE_TABLE, rip->neighbor); + + XFREE (MTYPE_RIP, rip); + rip = NULL; + } + + rip_clean_network (); + rip_passive_interface_clean (); + rip_offset_clean (); + rip_interface_clean (); + rip_distance_reset (); + rip_redistribute_clean (); +} + +/* Reset all values to the default settings. */ +void +rip_reset () +{ + /* Reset global counters. */ + rip_global_route_changes = 0; + rip_global_queries = 0; + + /* Call ripd related reset functions. */ + rip_debug_reset (); + rip_route_map_reset (); + + /* Call library reset functions. */ + vty_reset (); + access_list_reset (); + prefix_list_reset (); + + distribute_list_reset (); + + rip_interface_reset (); + rip_distance_reset (); + + rip_zclient_reset (); +} + +/* Allocate new rip structure and set default value. */ +void +rip_init () +{ + /* Randomize for triggered update random(). */ + srand (time (NULL)); + + /* Install top nodes. */ + install_node (&rip_node, config_write_rip); + + /* Install rip commands. */ + install_element (VIEW_NODE, &show_ip_rip_cmd); + install_element (VIEW_NODE, &show_ip_protocols_rip_cmd); + install_element (ENABLE_NODE, &show_ip_rip_cmd); + install_element (ENABLE_NODE, &show_ip_protocols_rip_cmd); + install_element (CONFIG_NODE, &router_rip_cmd); + install_element (CONFIG_NODE, &no_router_rip_cmd); + + install_default (RIP_NODE); + install_element (RIP_NODE, &rip_version_cmd); + install_element (RIP_NODE, &no_rip_version_cmd); + install_element (RIP_NODE, &no_rip_version_val_cmd); + install_element (RIP_NODE, &rip_default_metric_cmd); + install_element (RIP_NODE, &no_rip_default_metric_cmd); + install_element (RIP_NODE, &no_rip_default_metric_val_cmd); + install_element (RIP_NODE, &rip_timers_cmd); + install_element (RIP_NODE, &no_rip_timers_cmd); + install_element (RIP_NODE, &rip_route_cmd); + install_element (RIP_NODE, &no_rip_route_cmd); + install_element (RIP_NODE, &rip_distance_cmd); + install_element (RIP_NODE, &no_rip_distance_cmd); + install_element (RIP_NODE, &rip_distance_source_cmd); + install_element (RIP_NODE, &no_rip_distance_source_cmd); + install_element (RIP_NODE, &rip_distance_source_access_list_cmd); + install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd); + + /* Debug related init. */ + rip_debug_init (); + + /* Filter related init. */ + rip_route_map_init (); + rip_offset_init (); + + /* SNMP init. */ +#ifdef HAVE_SNMP + rip_snmp_init (); +#endif /* HAVE_SNMP */ + + /* Access list install. */ + access_list_init (); + access_list_add_hook (rip_distribute_update_all); + access_list_delete_hook (rip_distribute_update_all); + + /* Prefix list initialize.*/ + prefix_list_init (); + prefix_list_add_hook (rip_distribute_update_all); + prefix_list_delete_hook (rip_distribute_update_all); + + /* Distribute list install. */ + distribute_list_init (RIP_NODE); + distribute_list_add_hook (rip_distribute_update); + distribute_list_delete_hook (rip_distribute_update); + + /* Distance control. */ + rip_distance_table = route_table_init (); +} diff --git a/ripd/ripd.conf.sample b/ripd/ripd.conf.sample new file mode 100644 index 0000000..22e267b --- /dev/null +++ b/ripd/ripd.conf.sample @@ -0,0 +1,24 @@ +! -*- rip -*- +! +! RIPd sample configuration file +! +! $Id: ripd.conf.sample,v 1.11 1999/02/19 17:28:42 developer Exp $ +! +hostname ripd +password zebra +! +! debug rip events +! debug rip packet +! +router rip +! network 11.0.0.0/8 +! network eth0 +! route 10.0.0.0/8 +! distribute-list private-only in eth0 +! +!access-list private-only permit 10.0.0.0/8 +!access-list private-only deny any +! +!log file ripd.log +! +log stdout diff --git a/ripd/ripd.h b/ripd/ripd.h new file mode 100644 index 0000000..9b25fce --- /dev/null +++ b/ripd/ripd.h @@ -0,0 +1,418 @@ +/* RIP related values and structures. + * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RIP_H +#define _ZEBRA_RIP_H + +/* RIP version number. */ +#define RIPv1 1 +#define RIPv2 2 + +/* RIP command list. */ +#define RIP_REQUEST 1 +#define RIP_RESPONSE 2 +#define RIP_TRACEON 3 /* Obsolete */ +#define RIP_TRACEOFF 4 /* Obsolete */ +#define RIP_POLL 5 +#define RIP_POLL_ENTRY 6 +#define RIP_COMMAND_MAX 7 + +/* RIP metric infinity value.*/ +#define RIP_METRIC_INFINITY 16 + +/* Normal RIP packet min size. */ +#define RIP_PACKET_MINSIZ 4 + +/* Normal RIP packet max size is 512 but some implementation has a bug + in authentication handling. In that case 524 length RIP packet may + come. */ +#define RIP_PACKET_MAXSIZ 512 + +#define RIP_HEADER_SIZE 4 +#define RIP_RTE_SIZE 20 + +/* Max count of routing table entry in one rip packet. */ +#define RIP_MAX_RTE 25 + +/* RIP version 2 multicast address. */ +#ifndef INADDR_RIP_GROUP +#define INADDR_RIP_GROUP 0xe0000009 /* 224.0.0.9 */ +#endif + +/* RIP timers */ +#define RIP_UPDATE_TIMER_DEFAULT 30 +#define RIP_TIMEOUT_TIMER_DEFAULT 180 +#define RIP_GARBAGE_TIMER_DEFAULT 120 + +/* RIP peer timeout value. */ +#define RIP_PEER_TIMER_DEFAULT 180 + +/* RIP port number. */ +#define RIP_PORT_DEFAULT 520 +#define RIP_VTY_PORT 2602 +#define RIP_VTYSH_PATH "/tmp/.ripd" + +/* Default configuration file name. */ +#define RIPD_DEFAULT_CONFIG "ripd.conf" + +/* RIP route types. */ +#define RIP_ROUTE_RTE 0 +#define RIP_ROUTE_STATIC 1 +#define RIP_ROUTE_DEFAULT 2 +#define RIP_ROUTE_REDISTRIBUTE 3 +#define RIP_ROUTE_INTERFACE 4 + +/* RIP MD5 authentication. */ +#define RIP_AUTH_MD5_SIZE 16 + +/* UDP socket receive buffer size. */ +#define RIP_UDP_RCV_BUF 41600 + +/* RIP structure. */ +struct rip +{ + /* RIP socket. */ + int sock; + + /* Default version of rip instance. */ + u_char version; + + /* Output buffer of RIP. */ + struct stream *obuf; + + /* RIP routing information base. */ + struct route_table *table; + + /* RIP only static routing information. */ + struct route_table *route; + + /* RIP neighbor. */ + struct route_table *neighbor; + + /* RIP threads. */ + struct thread *t_read; + + /* Update and garbage timer. */ + struct thread *t_update; + + /* Triggered update hack. */ + int trigger; + struct thread *t_triggered_update; + struct thread *t_triggered_interval; + + /* RIP timer values. */ + unsigned long update_time; + unsigned long timeout_time; + unsigned long garbage_time; + + /* RIP default metric. */ + int default_metric; + + /* RIP default-information originate. */ + u_char default_information; + char *default_information_route_map; + + /* RIP default distance. */ + u_char distance; + struct route_table *distance_table; + + /* For redistribute route map. */ + struct + { + char *name; + struct route_map *map; + int metric_config; + u_int32_t metric; + } route_map[ZEBRA_ROUTE_MAX]; +}; + +/* RIP routing table entry which belong to rip_packet. */ +struct rte +{ + u_int16_t family; /* Address family of this route. */ + u_int16_t tag; /* Route Tag which included in RIP2 packet. */ + struct in_addr prefix; /* Prefix of rip route. */ + struct in_addr mask; /* Netmask of rip route. */ + struct in_addr nexthop; /* Next hop of rip route. */ + u_int32_t metric; /* Metric value of rip route. */ +}; + +/* RIP packet structure. */ +struct rip_packet +{ + unsigned char command; /* Command type of RIP packet. */ + unsigned char version; /* RIP version which coming from peer. */ + unsigned char pad1; /* Padding of RIP packet header. */ + unsigned char pad2; /* Same as above. */ + struct rte rte[1]; /* Address structure. */ +}; + +/* Buffer to read RIP packet. */ +union rip_buf +{ + struct rip_packet rip_packet; + char buf[RIP_PACKET_MAXSIZ]; +}; + +/* RIP route information. */ +struct rip_info +{ + /* This route's type. */ + int type; + + /* Sub type. */ + int sub_type; + + /* RIP nexthop. */ + struct in_addr nexthop; + struct in_addr from; + + /* Which interface does this route come from. */ + unsigned int ifindex; + + /* Metric of this route. */ + u_int32_t metric; + + /* Tag information of this route. */ + u_int16_t tag; + + /* Flags of RIP route. */ +#define RIP_RTF_FIB 1 +#define RIP_RTF_CHANGED 2 + u_char flags; + + /* Garbage collect timer. */ + struct thread *t_timeout; + struct thread *t_garbage_collect; + + /* Route-map futures - this variables can be changed. */ + struct in_addr nexthop_out; + u_char metric_set; + u_int32_t metric_out; + unsigned int ifindex_out; + + struct route_node *rp; + + u_char distance; + +#ifdef NEW_RIP_TABLE + struct rip_info *next; + struct rip_info *prev; +#endif /* NEW_RIP_TABLE */ +}; + +/* RIP specific interface configuration. */ +struct rip_interface +{ + /* RIP is enabled on this interface. */ + int enable_network; + int enable_interface; + + /* RIP is running on this interface. */ + int running; + + /* Joined to multicast group for this interface. */ + int joined_multicast; + + /* RIP version control. */ + int ri_send; + int ri_receive; + + /* RIPv2 authentication type. */ +#define RIP_NO_AUTH 0 +#define RIP_AUTH_DATA 1 +#define RIP_AUTH_SIMPLE_PASSWORD 2 +#define RIP_AUTH_MD5 3 + int auth_type; + + /* RIPv2 authentication string. */ + char *auth_str; + + /* RIPv2 authentication key chain. */ + char *key_chain; + + /* Split horizon flag. */ + int split_horizon; + int split_horizon_default; + + /* For filter type slot. */ +#define RIP_FILTER_IN 0 +#define RIP_FILTER_OUT 1 +#define RIP_FILTER_MAX 2 + + /* Access-list. */ + struct access_list *list[RIP_FILTER_MAX]; + + /* Prefix-list. */ + struct prefix_list *prefix[RIP_FILTER_MAX]; + + /* Wake up thread. */ + struct thread *t_wakeup; + + /* Interface statistics. */ + int recv_badpackets; + int recv_badroutes; + int sent_updates; + + /* Passive interface. */ + int passive; +}; + +/* RIP peer information. */ +struct rip_peer +{ + /* Peer address. */ + struct in_addr addr; + + /* Peer RIP tag value. */ + int domain; + + /* Last update time. */ + time_t uptime; + + /* Peer RIP version. */ + u_char version; + + /* Statistics. */ + int recv_badpackets; + int recv_badroutes; + + /* Timeout thread. */ + struct thread *t_timeout; +}; + +struct rip_md5_info +{ + u_int16_t family; + u_int16_t type; + u_int16_t packet_len; + u_char keyid; + u_char auth_len; + u_int32_t sequence; + u_int32_t reserv1; + u_int32_t reserv2; +}; + +struct rip_md5_data +{ + u_int16_t family; + u_int16_t type; + u_char digest[16]; +}; + +/* RIP accepet/announce methods. */ +#define RI_RIP_UNSPEC 0 +#define RI_RIP_VERSION_1 1 +#define RI_RIP_VERSION_2 2 +#define RI_RIP_VERSION_1_AND_2 3 + +/* Default value for "default-metric" command. */ +#define RIP_DEFAULT_METRIC_DEFAULT 1 + +/* RIP event. */ +enum rip_event +{ + RIP_READ, + RIP_UPDATE_EVENT, + RIP_TRIGGERED_UPDATE, +}; + +/* Macro for timer turn on. */ +#define RIP_TIMER_ON(T,F,V) \ + do { \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), rinfo, (V)); \ + } while (0) + +/* Macro for timer turn off. */ +#define RIP_TIMER_OFF(X) \ + do { \ + if (X) \ + { \ + thread_cancel (X); \ + (X) = NULL; \ + } \ + } while (0) + +/* Prototypes. */ +void rip_init (); +void rip_reset (); +void rip_clean (); +void rip_clean_network (); +void rip_interface_clean (); +void rip_interface_reset (); +void rip_passive_interface_clean (); +void rip_if_init (); +void rip_if_down_all (); +void rip_route_map_init (); +void rip_route_map_reset (); +void rip_snmp_init (); +void rip_zclient_init (); +void rip_zclient_start (); +void rip_zclient_reset (); +void rip_offset_init (); +int if_check_address (struct in_addr addr); +int if_valid_neighbor (struct in_addr addr); + +int rip_request_send (struct sockaddr_in *, struct interface *, u_char); +int rip_neighbor_lookup (struct sockaddr_in *); +void rip_redistribute_add (int, int, struct prefix_ipv4 *, unsigned int, + struct in_addr *); +void rip_redistribute_delete (int, int, struct prefix_ipv4 *, unsigned int); +void rip_redistribute_withdraw (int); +void rip_zebra_ipv4_add (struct prefix_ipv4 *, struct in_addr *, u_int32_t, u_char); +void rip_zebra_ipv4_delete (struct prefix_ipv4 *, struct in_addr *, u_int32_t); +void rip_interface_multicast_set (int, struct interface *); +void rip_distribute_update_interface (struct interface *); + +int config_write_rip_network (struct vty *, int); +int config_write_rip_offset_list (struct vty *); +int config_write_rip_redistribute (struct vty *, int); + +void rip_peer_init (); +void rip_peer_update (struct sockaddr_in *, u_char); +void rip_peer_bad_route (struct sockaddr_in *); +void rip_peer_bad_packet (struct sockaddr_in *); +void rip_peer_display (struct vty *); +struct rip_peer *rip_peer_lookup (struct in_addr *); +struct rip_peer *rip_peer_lookup_next (struct in_addr *); + +int rip_offset_list_apply_in (struct prefix_ipv4 *, struct interface *, u_int32_t *); +int rip_offset_list_apply_out (struct prefix_ipv4 *, struct interface *, u_int32_t *); +void rip_offset_clean (); + +void rip_info_free (struct rip_info *); +u_char rip_distance_apply (struct rip_info *); +void rip_redistribute_clean (); +void rip_ifaddr_add (struct interface *, struct connected *); +void rip_ifaddr_delete (struct interface *, struct connected *); + +/* There is only one rip strucutre. */ +extern struct rip *rip; + +/* Master thread strucutre. */ +extern struct thread_master *master; + +/* RIP statistics for SNMP. */ +extern long rip_global_route_changes; +extern long rip_global_queries; + +#endif /* _ZEBRA_RIP_H */ diff --git a/ripngd/ChangeLog b/ripngd/ChangeLog new file mode 100644 index 0000000..07e3d76 --- /dev/null +++ b/ripngd/ChangeLog @@ -0,0 +1,216 @@ +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2001-08-28 NOGUCHI Kay + + * ripngd.c (no_ripng_route): route_unlock_node () is not needed. + +2001-08-26 NOGUCHI Kay + + * ripngd.h (struct ripng_interface): Add passive interface option. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-07 Akira Kato + + * ripngd.c (ripng_timers): "timers basic" argument is fixed. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + +2001-01-01 Kunihiro Ishiguro + + * ripngd.h (RIPNG_VTYSH_PATH): Change "/tmp/ripngd" to + "/tmp/.ripngd". + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-09-20 Kunihiro Ishiguro + + * ripngd.c (ripng_send_packet): Use CMSG_SPACE instead of sizeof + hack. Revert privious alignment patch. + +2000-09-20 URA Hiroshi + + * ripngd.c (ripng_send_packet): Fix an alignment bug. Thus ripngd + can't send packets. + +2000-09-10 Kunihiro Ishiguro + + * ripng_interface.c (ripng_interface_address_delete): Connected + address delete treatment added. + +2000-08-22 Kunihiro Ishiguro + + * ripng_routemap.c (route_set_metric_compile): When checking '-' + character, argv[1] should be argv[0]. Reported by SHIRASAKI + Yasuhiro . + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +2000-06-06 Kunihiro Ishiguro + + * ripngd.c (ripng_route_process): Clear prefix_ipv6 before using + it. + (ripng_redistribute_delete): Fix bug of missing + route_unlock_node() when redistribute route is not found. + (ripng_redistribute_delete): Make it sure that timers are off. + (ripng_redistribute_delete): Likewise. + +2000-01-19 Kunihiro Ishiguro + + * ripngd.c (ripng_route_process): Fix bug of mis-checking of same + route. + (show_ipv6_ripng): Include ifindex to "show ipv6 ripng" output. + +1999-11-12 Kunihiro Ishiguro + + * ripngd.c (ripng_output_process): Use MINMTU when mtu value is + not available. + +1999-11-05 Kunihiro Ishiguro + + * ripngd.c (ripng_output_process): Calculate max RTE count from + interface MTU value. + +1999-09-29 Kunihiro Ishiguro + + * ripngd.c (ripng_distribute_update): Fix bug of updating + access-list and prefix-list. + +1999-09-07 URA Hiroshi + + * ripngd.c (ripng_recv_packet): Change CMSG_DATA cast from (u_char + *) to (int *). (u_char *) does not work for NetBSD-currnet on + SparcStation 10. + +1999-08-15 Kunihiro Ishiguro + + * ripngd.c (ripng_request_process): When request packet comes, + check RIPng process is enabled on the interface. + (ripng_redistribute_withdraw): Delete routes when `no + redistribute' is executed. + +1999-08-13 Yasuhiro Ohara + + * ripng_zebra.c (ripng_redistribute_ospf6_cmd): Add OSPF6 + redistribute command. + +1999-07-21 Kunihiro Ishiguro + + * ripngd.c (default_information_originate): Add + default-information command. + +1999-07-19 Kunihiro Ishiguro + + * ripngd.c (ripng_route_process): rip_add_route() and + rip_delete_route() are deleted. Both functions are integrated + into ripng_route_process(). + (ripng_request_process): Proper reply for request message. + + * ripng_routemap.c: New file added. + +1999-07-18 Kunihiro Ishiguro + + * ripngd.c (ripng_nexthop_rte): RIPng next hop routine is + rewritten. + (show_ipv6_ripng): Change `show ip ripng' to `show ipv6 ripng'. + (ripng_response_process): RIPng incoming packet's hop count check + added. + (ripng_response_process): Add strict RTE checking. + +1999-07-03 Kunihiro Ishiguro + + * ripngd.c (ripng_add_route): Fix metric compare bug. + +1999-06-25 itojun@iijlab.net + + * ripngd.c (ripng_distribute_in): "distribute in" filter in ripngd + actually work. + +1999-05-25 Kunihiro Ishiguro + + * ripngd.c (ripng_zebra): Send each ripng information by separate + zebra packet. + +1999-05-15 Kunihiro Ishiguro + + * ripng_interface.c (if_add_multicast): Change log to zlog. + +1999-05-10 Kunihiro Ishiguro + + * ripng_interface.c (ripng_zebra_get_interface): Add function. + + * ripng_zebra.c (redistribute_ripng): Delete function because + redistirbute the routes to the zebra daemon is now default + behavior. + +1999-05-09 Kunihiro Ishiguro + + * ripngd.conf.sample: Change network to route statement. + +1999-03-25 Kunihiro Ishiguro + + * ripngd.c: Old non Advanced API version ripng_send_packet and + ripng_recv_packet is removed. + * ripng_radix.c: File removed. + +1998-12-15 Kunihiro Ishiguro + + * Now I assume KAME support Advanced API and use sendmsg/recvmsg. + +1998-12-13 Kunihiro Ishiguro + + * ripng_interface.c: Delete old ifa (interface address) related + functions. + +1998-12-10 Kunihiro Ishiguro + + * ripng_debug.[ch]: New file. + + * ripngd.c (ripng_supply): Do not send header only RIPng packet. + Change `network' statement to `route' statement. + (ripng_request_process): Reply to RIPng REQUEST packet. + +1998-12-09 Kunihiro Ishiguro + + * ripngd.c (ripng_config_write): Delete vector v argument. + * ripng_zebra.c (zebra_config_write): Likewise. + * ripng_interface.c (interface_config_write): Likewise. + +1998-12-07 Kunihiro Ishiguro + + * ripng_route.h: New file. + + * ripng_interface.c: Delete #include . + ripng_main.c: likewise. + ripng_radix.c: likewise. + ripng_route.c: likewise. + ripng_zebra.c: likewise. + ripngd.c: likewise. + +1998-12-06 Yasuhiro Ohara + + * ripngd.h (IPV6_ADD_MEMBERSHIP): If IPV6_ADD_MEMBERSHIP is not + defined. Define IPV6_ADD_MEMBERSHIP as IPV6_JOIN_GROUP. + +1998-09-15 HEO SeonMeyong + + * all Hydrangea define is changed to KAME. + diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am new file mode 100644 index 0000000..90b8b65 --- /dev/null +++ b/ripngd/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +noinst_LIBRARIES = libripng.a +sbin_PROGRAMS = ripngd + +libripng_a_SOURCES = \ + ripng_interface.c ripngd.c ripng_zebra.c ripng_route.c ripng_debug.c \ + ripng_routemap.c ripng_ifrmap.c + +noinst_HEADERS = \ + ripng_debug.h ripng_route.h ripngd.h ripng_ifrmap.h + +ripngd_SOURCES = \ + ripng_main.c $(libripng_a_SOURCES) + +ripngd_LDADD = ../lib/libzebra.a + +sysconf_DATA = ripngd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done diff --git a/ripngd/Makefile.in b/ripngd/Makefile.in new file mode 100644 index 0000000..aec2d18 --- /dev/null +++ b/ripngd/Makefile.in @@ -0,0 +1,420 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CPP = @CPP@ +CURSES = @CURSES@ +DEPDIR = @DEPDIR@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LIBPAM = @LIBPAM@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA = @INSTALL@ -m 600 + +noinst_LIBRARIES = libripng.a +sbin_PROGRAMS = ripngd + +libripng_a_SOURCES = \ + ripng_interface.c ripngd.c ripng_zebra.c ripng_route.c ripng_debug.c \ + ripng_routemap.c ripng_ifrmap.c + + +noinst_HEADERS = \ + ripng_debug.h ripng_route.h ripngd.h ripng_ifrmap.h + + +ripngd_SOURCES = \ + ripng_main.c $(libripng_a_SOURCES) + + +ripngd_LDADD = ../lib/libzebra.a + +sysconf_DATA = ripngd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) +subdir = ripngd +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libripng_a_AR = $(AR) cru +libripng_a_LIBADD = +am_libripng_a_OBJECTS = ripng_interface.$(OBJEXT) ripngd.$(OBJEXT) \ + ripng_zebra.$(OBJEXT) ripng_route.$(OBJEXT) \ + ripng_debug.$(OBJEXT) ripng_routemap.$(OBJEXT) \ + ripng_ifrmap.$(OBJEXT) +libripng_a_OBJECTS = $(am_libripng_a_OBJECTS) +sbin_PROGRAMS = ripngd$(EXEEXT) +PROGRAMS = $(sbin_PROGRAMS) + +am__objects_1 = ripng_interface.$(OBJEXT) ripngd.$(OBJEXT) \ + ripng_zebra.$(OBJEXT) ripng_route.$(OBJEXT) \ + ripng_debug.$(OBJEXT) ripng_routemap.$(OBJEXT) \ + ripng_ifrmap.$(OBJEXT) +am_ripngd_OBJECTS = ripng_main.$(OBJEXT) $(am__objects_1) +ripngd_OBJECTS = $(am_ripngd_OBJECTS) +ripngd_DEPENDENCIES = ../lib/libzebra.a +ripngd_LDFLAGS = +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ripng_debug.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ripng_ifrmap.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ripng_interface.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ripng_main.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ripng_route.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ripng_routemap.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ripng_zebra.Po ./$(DEPDIR)/ripngd.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CFLAGS = @CFLAGS@ +DIST_SOURCES = $(libripng_a_SOURCES) $(ripngd_SOURCES) +DATA = $(sysconf_DATA) + +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in +SOURCES = $(libripng_a_SOURCES) $(ripngd_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign ripngd/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libripng.a: $(libripng_a_OBJECTS) $(libripng_a_DEPENDENCIES) + -rm -f libripng.a + $(libripng_a_AR) libripng.a $(libripng_a_OBJECTS) $(libripng_a_LIBADD) + $(RANLIB) libripng.a +sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \ + rm -f $(DESTDIR)$(sbindir)/$$f; \ + done + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) +ripngd$(EXEEXT): $(ripngd_OBJECTS) $(ripngd_DEPENDENCIES) + @rm -f ripngd$(EXEEXT) + $(LINK) $(ripngd_LDFLAGS) $(ripngd_OBJECTS) $(ripngd_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_debug.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_ifrmap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_interface.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_route.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_routemap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_zebra.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripngd.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `cygpath -w $<` +CCDEPMODE = @CCDEPMODE@ +uninstall-info-am: +sysconfDATA_INSTALL = $(INSTALL_DATA) + +uninstall-sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(sysconf_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \ + rm -f $(DESTDIR)$(sysconfdir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-sbinPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-sbinPROGRAMS install-sysconfDATA + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \ + uninstall-sysconfDATA + +.PHONY: GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES clean-sbinPROGRAMS distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-sbinPROGRAMS install-strip install-sysconfDATA \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic tags uninstall uninstall-am \ + uninstall-info-am uninstall-sbinPROGRAMS uninstall-sysconfDATA + + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/ripngd/ripng_debug.c b/ripngd/ripng_debug.c new file mode 100644 index 0000000..4fb7965 --- /dev/null +++ b/ripngd/ripng_debug.c @@ -0,0 +1,292 @@ +/* + * RIPng debug output routines + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include "command.h" +#include "ripngd/ripng_debug.h" + +/* For debug statement. */ +unsigned long ripng_debug_event = 0; +unsigned long ripng_debug_packet = 0; +unsigned long ripng_debug_zebra = 0; + +DEFUN (debug_ripng_events, + debug_ripng_events_cmd, + "debug ripng events", + DEBUG_STR + "RIPng configuration\n" + "Debug option set for ripng events\n") +{ + ripng_debug_event = RIPNG_DEBUG_EVENT; + return CMD_WARNING; +} + +DEFUN (debug_ripng_packet, + debug_ripng_packet_cmd, + "debug ripng packet", + DEBUG_STR + "RIPng configuration\n" + "Debug option set for ripng packet\n") +{ + ripng_debug_packet = RIPNG_DEBUG_PACKET; + ripng_debug_packet |= RIPNG_DEBUG_SEND; + ripng_debug_packet |= RIPNG_DEBUG_RECV; + return CMD_SUCCESS; +} + +DEFUN (debug_ripng_packet_direct, + debug_ripng_packet_direct_cmd, + "debug ripng packet (recv|send)", + DEBUG_STR + "RIPng configuration\n" + "Debug option set for ripng packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n") +{ + ripng_debug_packet |= RIPNG_DEBUG_PACKET; + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + ripng_debug_packet |= RIPNG_DEBUG_SEND; + if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + ripng_debug_packet |= RIPNG_DEBUG_RECV; + ripng_debug_packet &= ~RIPNG_DEBUG_DETAIL; + return CMD_SUCCESS; +} + +DEFUN (debug_ripng_packet_detail, + debug_ripng_packet_detail_cmd, + "debug ripng packet (recv|send) detail", + DEBUG_STR + "RIPng configuration\n" + "Debug option set for ripng packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n" + "Debug option set detaied information\n") +{ + ripng_debug_packet |= RIPNG_DEBUG_PACKET; + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + ripng_debug_packet |= RIPNG_DEBUG_SEND; + if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + ripng_debug_packet |= RIPNG_DEBUG_RECV; + ripng_debug_packet |= RIPNG_DEBUG_DETAIL; + return CMD_SUCCESS; +} + +DEFUN (debug_ripng_zebra, + debug_ripng_zebra_cmd, + "debug ripng zebra", + DEBUG_STR + "RIPng configuration\n" + "Debug option set for ripng and zebra communication\n") +{ + ripng_debug_zebra = RIPNG_DEBUG_ZEBRA; + return CMD_WARNING; +} + +DEFUN (no_debug_ripng_events, + no_debug_ripng_events_cmd, + "no debug ripng events", + NO_STR + DEBUG_STR + "RIPng configuration\n" + "Debug option set for ripng events\n") +{ + ripng_debug_event = 0; + return CMD_SUCCESS; +} + +DEFUN (no_debug_ripng_packet, + no_debug_ripng_packet_cmd, + "no debug ripng packet", + NO_STR + DEBUG_STR + "RIPng configuration\n" + "Debug option set for ripng packet\n") +{ + ripng_debug_packet = 0; + return CMD_SUCCESS; +} + +DEFUN (no_debug_ripng_packet_direct, + no_debug_ripng_packet_direct_cmd, + "no debug ripng packet (recv|send)", + NO_STR + DEBUG_STR + "RIPng configuration\n" + "Debug option set for ripng packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n") +{ + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + { + if (IS_RIPNG_DEBUG_RECV) + ripng_debug_packet &= ~RIPNG_DEBUG_SEND; + else + ripng_debug_packet = 0; + } + else if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + { + if (IS_RIPNG_DEBUG_SEND) + ripng_debug_packet &= ~RIPNG_DEBUG_RECV; + else + ripng_debug_packet = 0; + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_ripng_zebra, + no_debug_ripng_zebra_cmd, + "no debug ripng zebra", + NO_STR + DEBUG_STR + "RIPng configuration\n" + "Debug option set for ripng and zebra communication\n") +{ + ripng_debug_zebra = 0; + return CMD_WARNING; +} + +DEFUN (show_debugging_ripng, + show_debugging_ripng_cmd, + "show debugging ripng", + SHOW_STR + "RIPng configuration\n" + "Debugging information\n") +{ + vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE); + + if (IS_RIPNG_DEBUG_EVENT) + vty_out (vty, " RIPng event debugging is on%s", VTY_NEWLINE); + + if (IS_RIPNG_DEBUG_PACKET) + { + if (IS_RIPNG_DEBUG_SEND && IS_RIPNG_DEBUG_RECV) + { + vty_out (vty, " RIPng packet%s debugging is on%s", + IS_RIPNG_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + } + else + { + if (IS_RIPNG_DEBUG_SEND) + vty_out (vty, " RIPng packet send%s debugging is on%s", + IS_RIPNG_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + else + vty_out (vty, " RIPng packet receive%s debugging is on%s", + IS_RIPNG_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + } + } + + if (IS_RIPNG_DEBUG_ZEBRA) + vty_out (vty, " RIPng zebra debugging is on%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +/* Debug node. */ +struct cmd_node debug_node = +{ + DEBUG_NODE, + "" /* Debug node has no interface. */ +}; + +int +config_write_debug (struct vty *vty) +{ + int write = 0; + + if (IS_RIPNG_DEBUG_EVENT) + { + vty_out (vty, "debug ripng events%s", VTY_NEWLINE); + write++; + } + if (IS_RIPNG_DEBUG_PACKET) + { + if (IS_RIPNG_DEBUG_SEND && IS_RIPNG_DEBUG_RECV) + { + vty_out (vty, "debug ripng packet%s%s", + IS_RIPNG_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + write++; + } + else + { + if (IS_RIPNG_DEBUG_SEND) + vty_out (vty, "debug ripng packet send%s%s", + IS_RIPNG_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + else + vty_out (vty, "debug ripng packet recv%s%s", + IS_RIPNG_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + write++; + } + } + if (IS_RIPNG_DEBUG_ZEBRA) + { + vty_out (vty, "debug ripng zebra%s", VTY_NEWLINE); + write++; + } + return write; +} + +void +ripng_debug_reset () +{ + ripng_debug_event = 0; + ripng_debug_packet = 0; + ripng_debug_zebra = 0; +} + +void +ripng_debug_init () +{ + ripng_debug_event = 0; + ripng_debug_packet = 0; + ripng_debug_zebra = 0; + + install_node (&debug_node, config_write_debug); + + install_element (ENABLE_NODE, &show_debugging_ripng_cmd); + install_element (ENABLE_NODE, &debug_ripng_events_cmd); + install_element (ENABLE_NODE, &debug_ripng_packet_cmd); + install_element (ENABLE_NODE, &debug_ripng_packet_direct_cmd); + install_element (ENABLE_NODE, &debug_ripng_packet_detail_cmd); + install_element (ENABLE_NODE, &debug_ripng_zebra_cmd); + install_element (ENABLE_NODE, &no_debug_ripng_events_cmd); + install_element (ENABLE_NODE, &no_debug_ripng_packet_cmd); + install_element (ENABLE_NODE, &no_debug_ripng_packet_direct_cmd); + install_element (ENABLE_NODE, &no_debug_ripng_zebra_cmd); + + install_element (CONFIG_NODE, &debug_ripng_events_cmd); + install_element (CONFIG_NODE, &debug_ripng_packet_cmd); + install_element (CONFIG_NODE, &debug_ripng_packet_direct_cmd); + install_element (CONFIG_NODE, &debug_ripng_packet_detail_cmd); + install_element (CONFIG_NODE, &debug_ripng_zebra_cmd); + install_element (CONFIG_NODE, &no_debug_ripng_events_cmd); + install_element (CONFIG_NODE, &no_debug_ripng_packet_cmd); + install_element (CONFIG_NODE, &no_debug_ripng_packet_direct_cmd); + install_element (CONFIG_NODE, &no_debug_ripng_zebra_cmd); + + install_element (VIEW_NODE, &show_debugging_ripng_cmd); +} diff --git a/ripngd/ripng_debug.h b/ripngd/ripng_debug.h new file mode 100644 index 0000000..6713a15 --- /dev/null +++ b/ripngd/ripng_debug.h @@ -0,0 +1,52 @@ +/* + * RIPng debug output routines + * Copyright (C) 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RIPNG_DEBUG_H +#define _ZEBRA_RIPNG_DEBUG_H + +/* Debug flags. */ +#define RIPNG_DEBUG_EVENT 0x01 + +#define RIPNG_DEBUG_PACKET 0x01 +#define RIPNG_DEBUG_SEND 0x20 +#define RIPNG_DEBUG_RECV 0x40 +#define RIPNG_DEBUG_DETAIL 0x80 + +#define RIPNG_DEBUG_ZEBRA 0x01 + +/* Debug related macro. */ +#define IS_RIPNG_DEBUG_EVENT (ripng_debug_event & RIPNG_DEBUG_EVENT) + +#define IS_RIPNG_DEBUG_PACKET (ripng_debug_packet & RIPNG_DEBUG_PACKET) +#define IS_RIPNG_DEBUG_SEND (ripng_debug_packet & RIPNG_DEBUG_SEND) +#define IS_RIPNG_DEBUG_RECV (ripng_debug_packet & RIPNG_DEBUG_RECV) +#define IS_RIPNG_DEBUG_DETAIL (ripng_debug_packet & RIPNG_DEBUG_DETAIL) + +#define IS_RIPNG_DEBUG_ZEBRA (ripng_debug_zebra & RIPNG_DEBUG_ZEBRA) + +extern unsigned long ripng_debug_event; +extern unsigned long ripng_debug_packet; +extern unsigned long ripng_debug_zebra; + +void ripng_debug_init (); + +#endif /* _ZEBRA_RIPNG_DEBUG_H */ diff --git a/ripngd/ripng_ifrmap.c b/ripngd/ripng_ifrmap.c new file mode 100644 index 0000000..d358690 --- /dev/null +++ b/ripngd/ripng_ifrmap.c @@ -0,0 +1,305 @@ +/* route-map for interface. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "hash.h" +#include "command.h" +#include "memory.h" +#include "if.h" +#include "ripng_ifrmap.h" + +struct hash *ifrmaphash; + +/* Hook functions. */ +void (*if_rmap_add_hook) (struct if_rmap *) = NULL; +void (*if_rmap_delete_hook) (struct if_rmap *) = NULL; + +struct if_rmap * +if_rmap_new () +{ + struct if_rmap *new; + + new = XCALLOC (MTYPE_IF_RMAP, sizeof (struct if_rmap)); + + return new; +} + +void +if_rmap_free (struct if_rmap *if_rmap) +{ + if (if_rmap->ifname) + free (if_rmap->ifname); + + if (if_rmap->routemap[IF_RMAP_IN]) + free (if_rmap->routemap[IF_RMAP_IN]); + if (if_rmap->routemap[IF_RMAP_OUT]) + free (if_rmap->routemap[IF_RMAP_OUT]); + + XFREE (MTYPE_IF_RMAP, if_rmap); +} + +struct if_rmap * +if_rmap_lookup (char *ifname) +{ + struct if_rmap key; + struct if_rmap *if_rmap; + + key.ifname = ifname; + + if_rmap = hash_lookup (ifrmaphash, &key); + + return if_rmap; +} + +void +if_rmap_hook_add (void (*func) (struct if_rmap *)) +{ + if_rmap_add_hook = func; +} + +void +if_rmap_hook_delete (void (*func) (struct if_rmap *)) +{ + if_rmap_delete_hook = func; +} + +void * +if_rmap_hash_alloc (struct if_rmap *arg) +{ + struct if_rmap *if_rmap; + + if_rmap = if_rmap_new (); + if_rmap->ifname = strdup (arg->ifname); + + return if_rmap; +} + +struct if_rmap * +if_rmap_get (char *ifname) +{ + struct if_rmap key; + + key.ifname = ifname; + + return (struct if_rmap *) hash_get (ifrmaphash, &key, if_rmap_hash_alloc); +} + +unsigned int +if_rmap_hash_make (struct if_rmap *if_rmap) +{ + unsigned int key; + int i; + + key = 0; + for (i = 0; i < strlen (if_rmap->ifname); i++) + key += if_rmap->ifname[i]; + + return key; +} + +int +if_rmap_hash_cmp (struct if_rmap *if_rmap1, struct if_rmap *if_rmap2) +{ + if (strcmp (if_rmap1->ifname, if_rmap2->ifname) == 0) + return 1; + return 0; +} + +struct if_rmap * +if_rmap_set (char *ifname, enum if_rmap_type type, char *routemap_name) +{ + struct if_rmap *if_rmap; + + if_rmap = if_rmap_get (ifname); + + if (type == IF_RMAP_IN) + { + if (if_rmap->routemap[IF_RMAP_IN]) + free (if_rmap->routemap[IF_RMAP_IN]); + if_rmap->routemap[IF_RMAP_IN] = strdup (routemap_name); + } + if (type == IF_RMAP_OUT) + { + if (if_rmap->routemap[IF_RMAP_OUT]) + free (if_rmap->routemap[IF_RMAP_OUT]); + if_rmap->routemap[IF_RMAP_OUT] = strdup (routemap_name); + } + + if (if_rmap_add_hook) + (*if_rmap_add_hook) (if_rmap); + + return if_rmap; +} + +int +if_rmap_unset (char *ifname, enum if_rmap_type type, char *routemap_name) +{ + struct if_rmap *if_rmap; + + if_rmap = if_rmap_lookup (ifname); + if (!if_rmap) + return 0; + + if (type == IF_RMAP_IN) + { + if (!if_rmap->routemap[IF_RMAP_IN]) + return 0; + if (strcmp (if_rmap->routemap[IF_RMAP_IN], routemap_name) != 0) + return 0; + + free (if_rmap->routemap[IF_RMAP_IN]); + if_rmap->routemap[IF_RMAP_IN] = NULL; + } + + if (type == IF_RMAP_OUT) + { + if (!if_rmap->routemap[IF_RMAP_OUT]) + return 0; + if (strcmp (if_rmap->routemap[IF_RMAP_OUT], routemap_name) != 0) + return 0; + + free (if_rmap->routemap[IF_RMAP_OUT]); + if_rmap->routemap[IF_RMAP_OUT] = NULL; + } + + if (if_rmap_delete_hook) + (*if_rmap_delete_hook) (if_rmap); + + if (if_rmap->routemap[IF_RMAP_IN] == NULL && + if_rmap->routemap[IF_RMAP_OUT] == NULL) + { + hash_release (ifrmaphash, if_rmap); + if_rmap_free (if_rmap); + } + + return 1; +} + +DEFUN (ripng_if_rmap, + ripng_if_rmap_cmd, + "route-map RMAP_NAME (in|out) IFNAME", + "Route map set\n" + "Route map name\n" + "Route map set for input filtering\n" + "Route map set for output filtering\n" + "Route map interface name\n") +{ + enum if_rmap_type type; + struct if_rmap *if_rmap; + + if (strncmp (argv[1], "i", 1) == 0) + type = IF_RMAP_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = IF_RMAP_OUT; + else + { + vty_out (vty, "route-map direction must be [in|out]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if_rmap = if_rmap_set (argv[2], type, argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_ripng_if_rmap, + no_ripng_if_rmap_cmd, + "no route-map ROUTEMAP_NAME (in|out) IFNAME", + NO_STR + "Route map unset\n" + "Route map name\n" + "Route map for input filtering\n" + "Route map for output filtering\n" + "Route map interface name\n") +{ + int ret; + enum if_rmap_type type; + + if (strncmp (argv[1], "i", 1) == 0) + type = IF_RMAP_IN; + else if (strncmp (argv[1], "o", 1) == 0) + type = IF_RMAP_OUT; + else + { + vty_out (vty, "route-map direction must be [in|out]%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = if_rmap_unset (argv[2], type, argv[0]); + if (! ret) + { + vty_out (vty, "route-map doesn't exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +/* Configuration write function. */ +int +config_write_if_rmap (struct vty *vty) +{ + int i; + struct hash_backet *mp; + int write = 0; + + for (i = 0; i < ifrmaphash->size; i++) + for (mp = ifrmaphash->index[i]; mp; mp = mp->next) + { + struct if_rmap *if_rmap; + + if_rmap = mp->data; + + if (if_rmap->routemap[IF_RMAP_IN]) + { + vty_out (vty, " route-map %s in %s%s", + if_rmap->routemap[IF_RMAP_IN], + if_rmap->ifname, + VTY_NEWLINE); + write++; + } + + if (if_rmap->routemap[IF_RMAP_OUT]) + { + vty_out (vty, " route-map %s out %s%s", + if_rmap->routemap[IF_RMAP_OUT], + if_rmap->ifname, + VTY_NEWLINE); + write++; + } + } + return write; +} + +void +if_rmap_reset () +{ + hash_clean (ifrmaphash, (void (*) (void *)) if_rmap_free); +} + +void +if_rmap_init (void) +{ + ifrmaphash = hash_create (if_rmap_hash_make, if_rmap_hash_cmp); + + install_element (RIPNG_NODE, &ripng_if_rmap_cmd); + install_element (RIPNG_NODE, &no_ripng_if_rmap_cmd); +} diff --git a/ripngd/ripng_ifrmap.h b/ripngd/ripng_ifrmap.h new file mode 100644 index 0000000..c8bc223 --- /dev/null +++ b/ripngd/ripng_ifrmap.h @@ -0,0 +1,47 @@ +/* route-map for interface. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_IF_RMAP_H +#define _ZEBRA_IF_RMAP_H + +enum if_rmap_type +{ + IF_RMAP_IN, + IF_RMAP_OUT, + IF_RMAP_MAX +}; + +struct if_rmap +{ + /* Name of the interface. */ + char *ifname; + + char *routemap[IF_RMAP_MAX]; +}; + +void if_rmap_init (void); +void if_rmap_reset (void); +void if_rmap_hook_add (void (*) (struct if_rmap *)); +void if_rmap_hook_delete (void (*) (struct if_rmap *)); +struct if_rmap *if_rmap_lookup (char *); +int config_write_if_rmap (struct vty *); + +#endif /* _ZEBRA_IF_RMAP_H */ diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c new file mode 100644 index 0000000..91554f9 --- /dev/null +++ b/ripngd/ripng_interface.c @@ -0,0 +1,827 @@ +/* + * Interface related function for RIPng. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "if.h" +#include "prefix.h" +#include "memory.h" +#include "network.h" +#include "filter.h" +#include "log.h" +#include "stream.h" +#include "zclient.h" +#include "command.h" +#include "table.h" +#include "thread.h" + +#include "ripngd/ripngd.h" +#include "ripngd/ripng_debug.h" + +/* If RFC2133 definition is used. */ +#ifndef IPV6_JOIN_GROUP +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#endif +#ifndef IPV6_LEAVE_GROUP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP +#endif + +/* Static utility function. */ +static void ripng_enable_apply (struct interface *); +static void ripng_passive_interface_apply (struct interface *); + +/* Join to the all rip routers multicast group. */ +int +ripng_multicast_join (struct interface *ifp) +{ + int ret; + struct ipv6_mreq mreq; + + memset (&mreq, 0, sizeof (mreq)); + inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); + mreq.ipv6mr_interface = ifp->ifindex; + + ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + (char *) &mreq, sizeof (mreq)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno)); + + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng %s join to all-rip-routers multicast group", ifp->name); + + return ret; +} + +/* Leave from the all rip routers multicast group. */ +int +ripng_multicast_leave (struct interface *ifp) +{ + int ret; + struct ipv6_mreq mreq; + + memset (&mreq, 0, sizeof (mreq)); + inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); + mreq.ipv6mr_interface = ifp->ifindex; + + ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + (char *) &mreq, sizeof (mreq)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", strerror (errno)); + + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng %s leave from all-rip-routers multicast group", + ifp->name); + + return ret; +} + +/* Check max mtu size. */ +int +ripng_check_max_mtu () +{ + listnode node; + struct interface *ifp; + int mtu; + + mtu = 0; + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + if (mtu < ifp->mtu) + mtu = ifp->mtu; + } + return mtu; +} + +int +ripng_if_down (struct interface *ifp) +{ + struct route_node *rp; + struct ripng_info *rinfo; + struct ripng_interface *ri; + + if (ripng) + { + for (rp = route_top (ripng->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + { + /* Routes got through this interface. */ + if (rinfo->ifindex == ifp->ifindex + && rinfo->type == ZEBRA_ROUTE_RIPNG + && rinfo->sub_type == RIPNG_ROUTE_RTE) + { + ripng_zebra_ipv6_delete ((struct prefix_ipv6 *) &rp->p, + &rinfo->nexthop, + rinfo->ifindex); + + RIPNG_TIMER_OFF (rinfo->t_timeout); + RIPNG_TIMER_OFF (rinfo->t_garbage_collect); + + rp->info = NULL; + route_unlock_node (rp); + + ripng_info_free (rinfo); + } + else + { + /* All redistributed routes got through this interface. */ + if (rinfo->ifindex == ifp->ifindex) + ripng_redistribute_delete (rinfo->type, rinfo->sub_type, + (struct prefix_ipv6 *) &rp->p, + rinfo->ifindex); + } + } + } + + ri = ifp->info; + + if (ripng && ri->running) + { + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("turn off %s", ifp->name); + + /* Leave from multicast group. */ + ripng_multicast_leave (ifp); + + ri->running = 0; + } + + return 0; +} + +/* Inteface link up message processing. */ +int +ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length) +{ + struct stream *s; + struct interface *ifp; + + /* zebra_interface_state_read() updates interface structure in iflist. */ + s = zclient->ibuf; + ifp = zebra_interface_state_read (s); + + if (ifp == NULL) + return 0; + + if (IS_RIPNG_DEBUG_ZEBRA) + zlog_info ("interface up %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + /* Check if this interface is RIPng enabled or not. */ + ripng_enable_apply (ifp); + + /* Check for a passive interface. */ + ripng_passive_interface_apply (ifp); + + /* Apply distribute list to the all interface. */ + ripng_distribute_update_interface (ifp); + + return 0; +} + +/* Inteface link down message processing. */ +int +ripng_interface_down (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct interface *ifp; + + /* zebra_interface_state_read() updates interface structure in iflist. */ + s = zclient->ibuf; + ifp = zebra_interface_state_read (s); + + if (ifp == NULL) + return 0; + + ripng_if_down (ifp); + + if (IS_RIPNG_DEBUG_ZEBRA) + zlog_info ("interface down %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + return 0; +} + +/* Inteface addition message from zebra. */ +int +ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read (zclient->ibuf); + + if (IS_RIPNG_DEBUG_ZEBRA) + zlog_info ("RIPng interface add %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + /* Check is this interface is RIP enabled or not.*/ + ripng_enable_apply (ifp); + + /* Apply distribute list to the interface. */ + ripng_distribute_update_interface (ifp); + + /* Check interface routemap. */ + ripng_if_rmap_update_interface (ifp); + + return 0; +} + +int +ripng_interface_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + return 0; +} + +int +ripng_interface_address_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + struct prefix *p; + char buf[INET6_ADDRSTRLEN]; + + c = zebra_interface_address_add_read (zclient->ibuf); + + if (c == NULL) + return 0; + + p = c->address; + + if (p->family == AF_INET6) + { + if (IS_RIPNG_DEBUG_ZEBRA) + zlog_info ("RIPng connected address %s/%d add", + inet_ntop (AF_INET6, &p->u.prefix6, buf, INET6_ADDRSTRLEN), + p->prefixlen); + + /* Check is this interface is RIP enabled or not.*/ + ripng_enable_apply (c->ifp); + } + + return 0; +} + +int +ripng_interface_address_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *ifc; + struct prefix *p; + char buf[INET6_ADDRSTRLEN]; + + ifc = zebra_interface_address_delete_read (zclient->ibuf); + + if (ifc) + { + p = ifc->address; + + if (p->family == AF_INET6) + { + if (IS_RIPNG_DEBUG_ZEBRA) + zlog_info ("RIPng connected address %s/%d delete", + inet_ntop (AF_INET6, &p->u.prefix6, buf, + INET6_ADDRSTRLEN), + p->prefixlen); + + /* Check is this interface is RIP enabled or not.*/ + ripng_enable_apply (ifc->ifp); + } + connected_free (ifc); + } + + return 0; +} + +/* RIPng enable interface vector. */ +vector ripng_enable_if; + +/* RIPng enable network table. */ +struct route_table *ripng_enable_network; + +/* Lookup RIPng enable network. */ +int +ripng_enable_network_lookup (struct interface *ifp) +{ + listnode listnode; + struct connected *connected; + + for (listnode = listhead (ifp->connected); listnode; nextnode (listnode)) + if ((connected = getdata (listnode)) != NULL) + { + struct prefix *p; + struct route_node *node; + + p = connected->address; + + if (p->family == AF_INET6) + { + node = route_node_match (ripng_enable_network, p); + if (node) + { + route_unlock_node (node); + return 1; + } + } + } + return -1; +} + +/* Add RIPng enable network. */ +int +ripng_enable_network_add (struct prefix *p) +{ + struct route_node *node; + + node = route_node_get (ripng_enable_network, p); + + if (node->info) + { + route_unlock_node (node); + return -1; + } + else + node->info = "enabled"; + + return 1; +} + +/* Delete RIPng enable network. */ +int +ripng_enable_network_delete (struct prefix *p) +{ + struct route_node *node; + + node = route_node_lookup (ripng_enable_network, p); + if (node) + { + node->info = NULL; + + /* Unlock info lock. */ + route_unlock_node (node); + + /* Unlock lookup lock. */ + route_unlock_node (node); + + return 1; + } + return -1; +} + +/* Lookup function. */ +int +ripng_enable_if_lookup (char *ifname) +{ + int i; + char *str; + + for (i = 0; i < vector_max (ripng_enable_if); i++) + if ((str = vector_slot (ripng_enable_if, i)) != NULL) + if (strcmp (str, ifname) == 0) + return i; + return -1; +} + +/* Add interface to ripng_enable_if. */ +int +ripng_enable_if_add (char *ifname) +{ + int ret; + + ret = ripng_enable_if_lookup (ifname); + if (ret >= 0) + return -1; + + vector_set (ripng_enable_if, strdup (ifname)); + + return 1; +} + +/* Delete interface from ripng_enable_if. */ +int +ripng_enable_if_delete (char *ifname) +{ + int index; + char *str; + + index = ripng_enable_if_lookup (ifname); + if (index < 0) + return -1; + + str = vector_slot (ripng_enable_if, index); + free (str); + vector_unset (ripng_enable_if, index); + + return 1; +} + +/* Wake up interface. */ +int +ripng_interface_wakeup (struct thread *t) +{ + struct interface *ifp; + struct ripng_interface *ri; + + /* Get interface. */ + ifp = THREAD_ARG (t); + + ri = ifp->info; + ri->t_wakeup = NULL; + + /* Join to multicast group. */ + ripng_multicast_join (ifp); + + /* Send RIP request to the interface. */ + ripng_request (ifp); + + return 0; +} + +/* Check RIPng is enabed on this interface. */ +void +ripng_enable_apply (struct interface *ifp) +{ + int ret; + struct ripng_interface *ri = NULL; + + /* Check interface. */ + if (if_is_loopback (ifp)) + return; + + if (! if_is_up (ifp)) + return; + + ri = ifp->info; + + /* Check network configuration. */ + ret = ripng_enable_network_lookup (ifp); + + /* If the interface is matched. */ + if (ret > 0) + ri->enable_network = 1; + else + ri->enable_network = 0; + + /* Check interface name configuration. */ + ret = ripng_enable_if_lookup (ifp->name); + if (ret >= 0) + ri->enable_interface = 1; + else + ri->enable_interface = 0; + + /* Update running status of the interface. */ + if (ri->enable_network || ri->enable_interface) + { + if (! ri->running) + { + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng turn on %s", ifp->name); + + /* Add interface wake up thread. */ + if (! ri->t_wakeup) + ri->t_wakeup = thread_add_timer (master, ripng_interface_wakeup, + ifp, 1); + ri->running = 1; + } + } + else + { + if (ri->running) + { + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng turn off %s", ifp->name); + + /* Leave from multicast group. */ + ripng_multicast_leave (ifp); + + ri->running = 0; + } + } +} + +/* Set distribute list to all interfaces. */ +static void +ripng_enable_apply_all () +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ripng_enable_apply (ifp); + } +} + +/* Vector to store passive-interface name. */ +vector Vripng_passive_interface; + +/* Utility function for looking up passive interface settings. */ +int +ripng_passive_interface_lookup (char *ifname) +{ + int i; + char *str; + + for (i = 0; i < vector_max (Vripng_passive_interface); i++) + if ((str = vector_slot (Vripng_passive_interface, i)) != NULL) + if (strcmp (str, ifname) == 0) + return i; + return -1; +} + +void +ripng_passive_interface_apply (struct interface *ifp) +{ + int ret; + struct ripng_interface *ri; + + ri = ifp->info; + + ret = ripng_passive_interface_lookup (ifp->name); + if (ret < 0) + ri->passive = 0; + else + ri->passive = 1; +} + +void +ripng_passive_interface_apply_all (void) +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ripng_passive_interface_apply (ifp); + } +} + +/* Passive interface. */ +int +ripng_passive_interface_set (struct vty *vty, char *ifname) +{ + if (ripng_passive_interface_lookup (ifname) >= 0) + return CMD_WARNING; + + vector_set (Vripng_passive_interface, strdup (ifname)); + + ripng_passive_interface_apply_all (); + + return CMD_SUCCESS; +} + +int +ripng_passive_interface_unset (struct vty *vty, char *ifname) +{ + int i; + char *str; + + i = ripng_passive_interface_lookup (ifname); + if (i < 0) + return CMD_WARNING; + + str = vector_slot (Vripng_passive_interface, i); + free (str); + vector_unset (Vripng_passive_interface, i); + + ripng_passive_interface_apply_all (); + + return CMD_SUCCESS; +} + +/* Free all configured RIP passive-interface settings. */ +void +ripng_passive_interface_clean (void) +{ + int i; + char *str; + + for (i = 0; i < vector_max (Vripng_passive_interface); i++) + if ((str = vector_slot (Vripng_passive_interface, i)) != NULL) + { + free (str); + vector_slot (Vripng_passive_interface, i) = NULL; + } + ripng_passive_interface_apply_all (); +} + +/* Write RIPng enable network and interface to the vty. */ +int +ripng_network_write (struct vty *vty) +{ + int i; + char *str; + char *ifname; + struct route_node *node; + char buf[BUFSIZ]; + + /* Write enable network. */ + for (node = route_top (ripng_enable_network); node; node = route_next (node)) + if (node->info) + { + struct prefix *p = &node->p; + vty_out (vty, " network %s/%d%s", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen, + VTY_NEWLINE); + + } + + /* Write enable interface. */ + for (i = 0; i < vector_max (ripng_enable_if); i++) + if ((str = vector_slot (ripng_enable_if, i)) != NULL) + vty_out (vty, " network %s%s", str, + VTY_NEWLINE); + + /* Write passive interface. */ + for (i = 0; i < vector_max (Vripng_passive_interface); i++) + if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL) + vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE); + + return 0; +} + +/* RIPng enable on specified interface or matched network. */ +DEFUN (ripng_network, + ripng_network_cmd, + "network IF_OR_ADDR", + "RIPng enable on specified interface or network.\n" + "Interface or address") +{ + int ret; + struct prefix p; + + ret = str2prefix (argv[0], &p); + + /* Given string is IPv6 network or interface name. */ + if (ret) + ret = ripng_enable_network_add (&p); + else + ret = ripng_enable_if_add (argv[0]); + + if (ret < 0) + { + vty_out (vty, "There is same network configuration %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + ripng_enable_apply_all (); + + return CMD_SUCCESS; +} + +/* RIPng enable on specified interface or matched network. */ +DEFUN (no_ripng_network, + no_ripng_network_cmd, + "no network IF_OR_ADDR", + NO_STR + "RIPng enable on specified interface or network.\n" + "Interface or address") +{ + int ret; + struct prefix p; + + ret = str2prefix (argv[0], &p); + + /* Given string is interface name. */ + if (ret) + ret = ripng_enable_network_delete (&p); + else + ret = ripng_enable_if_delete (argv[0]); + + if (ret < 0) + { + vty_out (vty, "can't find network %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + ripng_enable_apply_all (); + + return CMD_SUCCESS; +} + +DEFUN (ripng_passive_interface, + ripng_passive_interface_cmd, + "passive-interface IFNAME", + "Suppress routing updates on an interface\n" + "Interface name\n") +{ + return ripng_passive_interface_set (vty, argv[0]); +} + +DEFUN (no_ripng_passive_interface, + no_ripng_passive_interface_cmd, + "no passive-interface IFNAME", + NO_STR + "Suppress routing updates on an interface\n" + "Interface name\n") +{ + return ripng_passive_interface_unset (vty, argv[0]); +} + +struct ripng_interface * +ri_new () +{ + struct ripng_interface *ri; + ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface)); + return ri; +} + +int +ripng_if_new_hook (struct interface *ifp) +{ + ifp->info = ri_new (); + return 0; +} + +/* Configuration write function for ripngd. */ +int +interface_config_write (struct vty *vty) +{ + listnode node; + struct interface *ifp; + struct ripng_interface *ri; + int write = 0; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ri = ifp->info; + + vty_out (vty, "interface %s%s", ifp->name, + VTY_NEWLINE); + if (ifp->desc) + vty_out (vty, " description %s%s", ifp->desc, + VTY_NEWLINE); + + vty_out (vty, "!%s", VTY_NEWLINE); + + write++; + } + return write; +} + +/* ripngd's interface node. */ +struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", +}; + +/* Initialization of interface. */ +void +ripng_if_init () +{ + /* Interface initialize. */ + iflist = list_new (); + if_add_hook (IF_NEW_HOOK, ripng_if_new_hook); + + /* RIPng enable network init. */ + ripng_enable_network = route_table_init (); + + /* RIPng enable interface init. */ + ripng_enable_if = vector_init (1); + + /* RIPng passive interface. */ + Vripng_passive_interface = vector_init (1); + + /* Install interface node. */ + install_node (&interface_node, interface_config_write); + + install_element (CONFIG_NODE, &interface_cmd); + install_element (INTERFACE_NODE, &config_end_cmd); + install_element (INTERFACE_NODE, &config_exit_cmd); + install_element (INTERFACE_NODE, &config_help_cmd); + install_element (INTERFACE_NODE, &interface_desc_cmd); + install_element (INTERFACE_NODE, &no_interface_desc_cmd); + + install_element (RIPNG_NODE, &ripng_network_cmd); + install_element (RIPNG_NODE, &no_ripng_network_cmd); + install_element (RIPNG_NODE, &ripng_passive_interface_cmd); + install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd); +} diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c new file mode 100644 index 0000000..aec74bb --- /dev/null +++ b/ripngd/ripng_main.c @@ -0,0 +1,252 @@ +/* + * RIPngd main routine. + * Copyright (C) 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "version.h" +#include "getopt.h" +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "thread.h" +#include "log.h" +#include "prefix.h" +#include "if.h" + +#include "ripngd/ripngd.h" + +/* Configuration filename and directory. */ +char config_current[] = RIPNG_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR RIPNG_DEFAULT_CONFIG; + +/* RIPngd options. */ +struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "log_mode", no_argument, NULL, 'l'}, + { "help", no_argument, NULL, 'h'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "retain", no_argument, NULL, 'r'}, + { "version", no_argument, NULL, 'v'}, + { 0 } +}; + +/* RIPngd program name */ + +/* Route retain mode flag. */ +int retain_mode = 0; + +/* Master of threads. */ +struct thread_master *master; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_RIPNGD_PID; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\ +Daemon which manages RIPng.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-l. --log_mode Set verbose log mode flag\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-r, --retain When program terminates, retain added route by ripngd.\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + exit (status); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog (NULL, LOG_INFO, "SIGHUP received"); +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + zlog (NULL, LOG_INFO, "Terminating on signal"); + + if (! retain_mode) + ripng_terminate (); + + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_rotate (NULL); +} + +/* Signale wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigint); + signal_set (SIGPIPE, SIG_IGN); + signal_set (SIGUSR1, sigusr1); +} + +/* RIPngd main routine. */ +int +main (int argc, char **argv) +{ + char *p; + char *vty_addr = NULL; + int vty_port = 0; + int daemon_mode = 0; + char *config_file = NULL; + char *progname; + struct thread thread; + + /* Set umask before anything for security */ + umask (0027); + + /* get program name */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + zlog_default = openzlog(progname, ZLOG_NOLOG, ZLOG_RIPNG, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + while (1) + { + int opt; + + opt = getopt_long (argc, argv, "dlf:hA:P:v", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'd': + daemon_mode = 1; + break; + case 'l': + /* log_mode = 1; */ + break; + case 'f': + config_file = optarg; + break; + case 'A': + vty_addr = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'r': + retain_mode = 1; + break; + case 'v': + print_version (progname); + exit (0); + break; + case 'h': + usage (progname, 0); + break; + default: + usage (progname, 1); + break; + } + } + + master = thread_master_create (); + + /* Library inits. */ + signal_init (); + cmd_init (1); + vty_init (); + + /* RIPngd inits. */ + ripng_init (); + zebra_init (); + sort_node (); + + /* Get configuration file. */ + vty_read_config (config_file, config_current, config_default); + + /* Change to the daemon program. */ + if (daemon_mode) + daemon (0, 0); + + /* Create VTY socket */ + vty_serv_sock (vty_addr, + vty_port ? vty_port : RIPNG_VTY_PORT, RIPNG_VTYSH_PATH); + + /* Process id file create. */ + pid_output (pid_file); + + /* Fetch next active thread. */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Not reached. */ + exit (0); +} diff --git a/ripngd/ripng_route.c b/ripngd/ripng_route.c new file mode 100644 index 0000000..27475f0 --- /dev/null +++ b/ripngd/ripng_route.c @@ -0,0 +1,157 @@ +/* + * RIPng routes function. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "if.h" + +#include "ripngd/ripngd.h" +#include "ripngd/ripng_route.h" + +struct ripng_aggregate * +ripng_aggregate_new () +{ + struct ripng_aggregate *new; + + new = XCALLOC (MTYPE_RIPNG_AGGREGATE, sizeof (struct ripng_aggregate)); + return new; +} + +void +ripng_aggregate_free (struct ripng_aggregate *aggregate) +{ + XFREE (MTYPE_RIPNG_AGGREGATE, aggregate); +} + +/* Aggregate count increment check. */ +void +ripng_aggregate_increment (struct route_node *child, struct ripng_info *rinfo) +{ + struct route_node *np; + struct ripng_aggregate *aggregate; + + for (np = child; np; np = np->parent) + if ((aggregate = np->aggregate) != NULL) + { + aggregate->count++; + rinfo->suppress++; + } +} + +/* Aggregate count decrement check. */ +void +ripng_aggregate_decrement (struct route_node *child, struct ripng_info *rinfo) +{ + struct route_node *np; + struct ripng_aggregate *aggregate; + + for (np = child; np; np = np->parent) + if ((aggregate = np->aggregate) != NULL) + { + aggregate->count--; + rinfo->suppress--; + } +} + +/* RIPng routes treatment. */ +int +ripng_aggregate_add (struct prefix *p) +{ + struct route_node *top; + struct route_node *rp; + struct ripng_info *rinfo; + struct ripng_aggregate *aggregate; + struct ripng_aggregate *sub; + + /* Get top node for aggregation. */ + top = route_node_get (ripng->table, p); + + /* Allocate new aggregate. */ + aggregate = ripng_aggregate_new (); + aggregate->metric = 1; + + top->aggregate = aggregate; + + /* Suppress routes match to the aggregate. */ + for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top)) + { + /* Suppress normal route. */ + if ((rinfo = rp->info) != NULL) + { + aggregate->count++; + rinfo->suppress++; + } + /* Suppress aggregate route. This may not need. */ + if (rp != top && (sub = rp->aggregate) != NULL) + { + aggregate->count++; + sub->suppress++; + } + } + + return 0; +} + +/* Delete RIPng static route. */ +int +ripng_aggregate_delete (struct prefix *p) +{ + struct route_node *top; + struct route_node *rp; + struct ripng_info *rinfo; + struct ripng_aggregate *aggregate; + struct ripng_aggregate *sub; + + /* Get top node for aggregation. */ + top = route_node_get (ripng->table, p); + + /* Allocate new aggregate. */ + aggregate = top->aggregate; + + /* Suppress routes match to the aggregate. */ + for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top)) + { + /* Suppress normal route. */ + if ((rinfo = rp->info) != NULL) + { + aggregate->count--; + rinfo->suppress--; + } + + if (rp != top && (sub = rp->aggregate) != NULL) + { + aggregate->count--; + sub->suppress--; + } + } + + top->aggregate = NULL; + ripng_aggregate_free (aggregate); + + route_unlock_node (top); + route_unlock_node (top); + + return 0; +} diff --git a/ripngd/ripng_route.h b/ripngd/ripng_route.h new file mode 100644 index 0000000..283d826 --- /dev/null +++ b/ripngd/ripng_route.h @@ -0,0 +1,53 @@ +/* + * RIPng daemon + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RIPNG_ROUTE_H +#define _ZEBRA_RIPNG_ROUTE_H + +struct ripng_aggregate +{ + /* Aggregate route count. */ + unsigned int count; + + /* Suppressed route count. */ + unsigned int suppress; + + /* Metric of this route. */ + u_char metric; + + /* Tag field of RIPng packet.*/ + u_short tag; +}; + +void +ripng_aggregate_increment (struct route_node *rp, struct ripng_info *rinfo); + +void +ripng_aggregate_decrement (struct route_node *rp, struct ripng_info *rinfo); + +int +ripng_aggregate_add (struct prefix *p); + +int +ripng_aggregate_delete (struct prefix *p); + +#endif /* _ZEBRA_RIPNG_ROUTE_H */ diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c new file mode 100644 index 0000000..f0183e4 --- /dev/null +++ b/ripngd/ripng_routemap.c @@ -0,0 +1,354 @@ +/* RIPng routemap. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "memory.h" +#include "prefix.h" +#include "routemap.h" +#include "command.h" + +#include "ripngd/ripngd.h" + +#if 0 +/* `match interface IFNAME' */ +route_map_result_t +route_match_interface (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct ripng_info *rinfo; + struct interface *ifp; + char *ifname; + + if (type == ROUTE_MAP_RIPNG) + { + ifname = rule; + ifp = if_lookup_by_name(ifname); + + if (!ifp) + return RM_NOMATCH; + + rinfo = object; + + if (rinfo->ifindex == ifp->ifindex) + return RM_MATCH; + else + return RM_NOMATCH; + } + return RM_NOMATCH; +} + +void * +route_match_interface_compile (char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_interface_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_interface_cmd = +{ + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; +#endif /* 0 */ + +struct rip_metric_modifier +{ + enum + { + metric_increment, + metric_decrement, + metric_absolute + } type; + + u_char metric; +}; + +route_map_result_t +route_set_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + if (type == RMAP_RIPNG) + { + struct rip_metric_modifier *mod; + struct ripng_info *rinfo; + + mod = rule; + rinfo = object; + + if (mod->type == metric_increment) + rinfo->metric += mod->metric; + else if (mod->type == metric_decrement) + rinfo->metric -= mod->metric; + else if (mod->type == metric_absolute) + rinfo->metric = mod->metric; + + if (rinfo->metric < 1) + rinfo->metric = 1; + if (rinfo->metric > RIPNG_METRIC_INFINITY) + rinfo->metric = RIPNG_METRIC_INFINITY; + + rinfo->metric_set = 1; + } + return RMAP_OKAY; +} + +void * +route_set_metric_compile (char *arg) +{ + int len; + char *pnt; + int type; + long metric; + char *endptr = NULL; + struct rip_metric_modifier *mod; + + len = strlen (arg); + pnt = arg; + + if (len == 0) + return NULL; + + /* Examine first character. */ + if (arg[0] == '+') + { + type = metric_increment; + pnt++; + } + else if (arg[0] == '-') + { + type = metric_decrement; + pnt++; + } + else + type = metric_absolute; + + /* Check beginning with digit string. */ + if (*pnt < '0' || *pnt > '9') + return NULL; + + /* Convert string to integer. */ + metric = strtol (pnt, &endptr, 10); + + if (metric == LONG_MAX || *endptr != '\0') + return NULL; + /* Commented out by Hasso Tepper, to avoid problems in vtysh. */ + /* if (metric < 0 || metric > RIPNG_METRIC_INFINITY) */ + if (metric < 0) + return NULL; + + mod = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, + sizeof (struct rip_metric_modifier)); + mod->type = type; + mod->metric = metric; + + return mod; +} + +void +route_set_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_set_metric_cmd = +{ + "metric", + route_set_metric, + route_set_metric_compile, + route_set_metric_free, +}; + +int +ripng_route_match_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +int +ripng_route_match_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_match (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +int +ripng_route_set_add (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_add_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +int +ripng_route_set_delete (struct vty *vty, struct route_map_index *index, + char *command, char *arg) +{ + int ret; + + ret = route_map_delete_set (index, command, arg); + if (ret) + { + switch (ret) + { + case RMAP_RULE_MISSING: + vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + case RMAP_COMPILE_ERROR: + vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + break; + } + } + return CMD_SUCCESS; +} + +#if 0 +DEFUN (match_interface, + match_interface_cmd, + "match interface WORD", + "Match value\n" + "Interface\n" + "Interface name\n") +{ + return ripng_route_match_add (vty, vty->index, "interface", argv[0]); +} + +DEFUN (no_match_interface, + no_match_interface_cmd, + "no match interface WORD", + NO_STR + "Match value\n" + "Interface\n" + "Interface name\n") +{ + return ripng_route_match_delete (vty, vty->index, "interface", argv[0]); +} +#endif /* 0 */ + +DEFUN (set_metric, + set_metric_cmd, + "set metric <0-4294967295>", + "Set value\n" + "Metric\n" + "METRIC value\n") +{ + return ripng_route_set_add (vty, vty->index, "metric", argv[0]); +} + +DEFUN (no_set_metric, + no_set_metric_cmd, + "no set metric", + NO_STR + SET_STR + "Metric value for destination routing protocol\n") +{ + if (argc == 0) + return ripng_route_set_delete (vty, vty->index, "metric", NULL); + + return ripng_route_set_delete (vty, vty->index, "metric", argv[0]); +} + +ALIAS (no_set_metric, + no_set_metric_val_cmd, + "no set metric <0-4294967295>", + NO_STR + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n"); + +void +ripng_route_map_init () +{ + route_map_init (); + route_map_init_vty (); + + /* route_map_install_match (&route_match_interface_cmd); */ + route_map_install_set (&route_set_metric_cmd); + + /* + install_element (RMAP_NODE, &match_interface_cmd); + install_element (RMAP_NODE, &no_match_interface_cmd); + */ + + install_element (RMAP_NODE, &set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_cmd); +} diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c new file mode 100644 index 0000000..aa04ef9 --- /dev/null +++ b/ripngd/ripng_zebra.c @@ -0,0 +1,877 @@ +/* + * RIPngd and zebra interface. + * Copyright (C) 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "command.h" +#include "prefix.h" +#include "stream.h" +#include "routemap.h" +#include "zclient.h" +#include "log.h" + +#include "ripngd/ripngd.h" + +/* All information about zebra. */ +struct zclient *zclient = NULL; + +/* Callback prototypes for zebra client service. */ +int ripng_interface_up (int, struct zclient *, zebra_size_t); +int ripng_interface_down (int, struct zclient *, zebra_size_t); +int ripng_interface_add (int, struct zclient *, zebra_size_t); +int ripng_interface_delete (int, struct zclient *, zebra_size_t); +int ripng_interface_address_add (int, struct zclient *, zebra_size_t); +int ripng_interface_address_delete (int, struct zclient *, zebra_size_t); + +void +ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop, + unsigned int ifindex) +{ + struct zapi_ipv6 api; + + if (zclient->redist[ZEBRA_ROUTE_RIPNG]) + { + api.type = ZEBRA_ROUTE_RIPNG; + api.flags = 0; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &ifindex; + + zapi_ipv6_add (zclient, p, &api); + } +} + +void +ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, struct in6_addr *nexthop, + unsigned int ifindex) +{ + struct zapi_ipv6 api; + + if (zclient->redist[ZEBRA_ROUTE_RIPNG]) + { + api.type = ZEBRA_ROUTE_RIPNG; + api.flags = 0; + api.message = 0; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop; + SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &ifindex; + + zapi_ipv6_delete (zclient, p, &api); + } +} + +/* Zebra route add and delete treatment. */ +int +ripng_zebra_read_ipv6 (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv6 api; + unsigned long ifindex; + struct in6_addr nexthop; + struct prefix_ipv6 p; + + s = zclient->ibuf; + ifindex = 0; + memset (&nexthop, 0, sizeof (struct in6_addr)); + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv6 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + stream_get (&nexthop, s, 16); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + else + api.distance = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + if (command == ZEBRA_IPV6_ROUTE_ADD) + ripng_redistribute_add (api.type, 0, &p, ifindex); + else + ripng_redistribute_delete (api.type, 0, &p, ifindex); + + return 0; +} + +int +ripng_redistribute_unset (int type) +{ + if (! zclient->redist[type]) + return CMD_SUCCESS; + + zclient->redist[type] = 0; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type); + + ripng_redistribute_withdraw (type); + + return CMD_SUCCESS; +} + +void +ripng_redistribute_metric_set (int type, int metric) +{ + ripng->route_map[type].metric_config = 1; + ripng->route_map[type].metric = metric; +} + +void +ripng_redistribute_metric_unset (int type) +{ + ripng->route_map[type].metric_config = 0; + ripng->route_map[type].metric = 0; +} + +void +ripng_redistribute_routemap_set (int type, char *name) +{ + if (ripng->route_map[type].name) + free (ripng->route_map[type].name); + + ripng->route_map[type].name = strdup (name); + ripng->route_map[type].map = route_map_lookup_by_name (name); +} + +void +ripng_redistribute_routemap_unset (int type) +{ + if (ripng->route_map[type].name) + free (ripng->route_map[type].name); + + ripng->route_map[type].name = NULL; + ripng->route_map[type].map = NULL; +} + + +DEFUN (router_zebra, + router_zebra_cmd, + "router zebra", + "Enable a routing process\n" + "Make connection to zebra daemon\n") +{ + vty->node = ZEBRA_NODE; + zclient->enable = 1; + zclient_start (zclient); + return CMD_SUCCESS; +} + +DEFUN (no_router_zebra, + no_router_zebra_cmd, + "no router zebra", + NO_STR + "Disable a routing process\n" + "Stop connection to zebra daemon\n") +{ + zclient->enable = 0; + zclient_stop (zclient); + return CMD_SUCCESS; +} + +DEFUN (ripng_redistribute_ripng, + ripng_redistribute_ripng_cmd, + "redistribute ripng", + "Redistribute information from another routing protocol\n" + "RIPng route\n") +{ + zclient->redist[ZEBRA_ROUTE_RIPNG] = 1; + return CMD_SUCCESS; +} + +DEFUN (no_ripng_redistribute_ripng, + no_ripng_redistribute_ripng_cmd, + "no redistribute ripng", + NO_STR + "Redistribute information from another routing protocol\n" + "RIPng route\n") +{ + zclient->redist[ZEBRA_ROUTE_RIPNG] = 0; + return CMD_SUCCESS; +} + +DEFUN (ripng_redistribute_static, + ripng_redistribute_static_cmd, + "redistribute static", + "Redistribute information from another routing protocol\n" + "Static routes\n") +{ + zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC); + return CMD_SUCCESS; +} + +DEFUN (no_ripng_redistribute_static, + no_ripng_redistribute_static_cmd, + "no redistribute static", + NO_STR + "Redistribute information from another routing protocol\n" + "Static routes\n") +{ + ripng_redistribute_metric_unset (ZEBRA_ROUTE_STATIC); + ripng_redistribute_routemap_unset (ZEBRA_ROUTE_STATIC); + return ripng_redistribute_unset (ZEBRA_ROUTE_STATIC); +} + +DEFUN (ripng_redistribute_kernel, + ripng_redistribute_kernel_cmd, + "redistribute kernel", + "Redistribute information from another routing protocol\n" + "Kernel routes\n") +{ + zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL); + return CMD_SUCCESS; +} + +DEFUN (no_ripng_redistribute_kernel, + no_ripng_redistribute_kernel_cmd, + "no redistribute kernel", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n") +{ + ripng_redistribute_metric_unset (ZEBRA_ROUTE_KERNEL); + ripng_redistribute_routemap_unset (ZEBRA_ROUTE_KERNEL); + return ripng_redistribute_unset (ZEBRA_ROUTE_KERNEL); +} + +DEFUN (ripng_redistribute_connected, + ripng_redistribute_connected_cmd, + "redistribute connected", + "Redistribute information from another routing protocol\n" + "Connected\n") +{ + zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT); + return CMD_SUCCESS; +} + +DEFUN (no_ripng_redistribute_connected, + no_ripng_redistribute_connected_cmd, + "no redistribute connected", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n") +{ + ripng_redistribute_metric_unset (ZEBRA_ROUTE_CONNECT); + ripng_redistribute_routemap_unset (ZEBRA_ROUTE_CONNECT); + return ripng_redistribute_unset (ZEBRA_ROUTE_CONNECT); +} + +DEFUN (ripng_redistribute_bgp, + ripng_redistribute_bgp_cmd, + "redistribute bgp", + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n") +{ + zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP); + return CMD_SUCCESS; +} + +DEFUN (no_ripng_redistribute_bgp, + no_ripng_redistribute_bgp_cmd, + "no redistribute bgp", + NO_STR + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n") +{ + ripng_redistribute_metric_unset (ZEBRA_ROUTE_BGP); + ripng_redistribute_routemap_unset (ZEBRA_ROUTE_BGP); + return ripng_redistribute_unset (ZEBRA_ROUTE_BGP); +} + +DEFUN (ripng_redistribute_ospf6, + ripng_redistribute_ospf6_cmd, + "redistribute ospf6", + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n") +{ + zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6); + return CMD_SUCCESS; +} + +DEFUN (no_ripng_redistribute_ospf6, + no_ripng_redistribute_ospf6_cmd, + "no redistribute ospf6", + NO_STR + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n") +{ + ripng_redistribute_metric_unset (ZEBRA_ROUTE_OSPF6); + ripng_redistribute_routemap_unset (ZEBRA_ROUTE_OSPF6); + return ripng_redistribute_unset (ZEBRA_ROUTE_OSPF6); +} + +DEFUN (ripng_redistribute_kernel_metric, + ripng_redistribute_kernel_metric_cmd, + "redistribute kernel metric <0-16>", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n" + "Metric value\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_KERNEL, atoi (argv[0])); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_kernel, + no_ripng_redistribute_kernel_metric_cmd, + "no redistribute kernel metric", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n"); + +ALIAS (no_ripng_redistribute_kernel, + no_ripng_redistribute_kernel_metric_val_cmd, + "no redistribute kernel metric <0-16>", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n" + "Metric value\n"); + +DEFUN (ripng_redistribute_connected_metric, + ripng_redistribute_connected_metric_cmd, + "redistribute connected metric <0-16>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n" + "Metric value\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_CONNECT, atoi (argv[0])); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_connected, + no_ripng_redistribute_connected_metric_cmd, + "no redistribute connected metric", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n"); + +ALIAS (no_ripng_redistribute_connected, + no_ripng_redistribute_connected_metric_val_cmd, + "no redistribute connected metric <0-16>", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n" + "Metric value\n"); + +DEFUN (ripng_redistribute_static_metric, + ripng_redistribute_static_metric_cmd, + "redistribute static metric <0-16>", + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n" + "Metric value\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_STATIC, atoi (argv[0])); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_static, + no_ripng_redistribute_static_metric_cmd, + "no redistribute static metric", + NO_STR + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n"); + +ALIAS (no_ripng_redistribute_static, + no_ripng_redistribute_static_metric_val_cmd, + "no redistribute static metric <0-16>", + NO_STR + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n" + "Metric value\n"); + +DEFUN (ripng_redistribute_ospf6_metric, + ripng_redistribute_ospf6_metric_cmd, + "redistribute ospf6 metric <0-16>", + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n" + "Metric value\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_OSPF6, atoi (argv[0])); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_ospf6, + no_ripng_redistribute_ospf6_metric_cmd, + "no redistribute ospf6 metric", + NO_STR + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n"); + +ALIAS (no_ripng_redistribute_ospf6, + no_ripng_redistribute_ospf6_metric_val_cmd, + "no redistribute ospf6 metric <0-16>", + NO_STR + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n" + "Metric value\n"); + +DEFUN (ripng_redistribute_bgp_metric, + ripng_redistribute_bgp_metric_cmd, + "redistribute bgp metric <0-16>", + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_BGP, atoi (argv[0])); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_bgp, + no_ripng_redistribute_bgp_metric_cmd, + "no redistribute bgp metric", + NO_STR + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n"); + +ALIAS (no_ripng_redistribute_bgp, + no_ripng_redistribute_bgp_metric_val_cmd, + "no redistribute bgp metric <0-16>", + NO_STR + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n"); + +DEFUN (ripng_redistribute_kernel_routemap, + ripng_redistribute_kernel_routemap_cmd, + "redistribute kernel route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_routemap_set (ZEBRA_ROUTE_KERNEL, argv[0]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_kernel, + no_ripng_redistribute_kernel_routemap_cmd, + "no redistribute kernel route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Route map reference\n" + "Pointer to route-map entries\n"); + +DEFUN (ripng_redistribute_connected_routemap, + ripng_redistribute_connected_routemap_cmd, + "redistribute connected route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_routemap_set (ZEBRA_ROUTE_CONNECT, argv[0]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_connected, + no_ripng_redistribute_connected_routemap_cmd, + "no redistribute connected route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Route map reference\n" + "Pointer to route-map entries\n"); + +DEFUN (ripng_redistribute_static_routemap, + ripng_redistribute_static_routemap_cmd, + "redistribute static route-map WORD", + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_routemap_set (ZEBRA_ROUTE_STATIC, argv[0]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_static, + no_ripng_redistribute_static_routemap_cmd, + "no redistribute static route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n"); + +DEFUN (ripng_redistribute_ospf6_routemap, + ripng_redistribute_ospf6_routemap_cmd, + "redistribute ospf6 route-map WORD", + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_routemap_set (ZEBRA_ROUTE_OSPF6, argv[0]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_ospf6, + no_ripng_redistribute_ospf6_routemap_cmd, + "no redistribute ospf6 route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Route map reference\n" + "Pointer to route-map entries\n"); + +DEFUN (ripng_redistribute_bgp_routemap, + ripng_redistribute_bgp_routemap_cmd, + "redistribute bgp route-map WORD", + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_routemap_set (ZEBRA_ROUTE_BGP, argv[0]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_bgp, + no_ripng_redistribute_bgp_routemap_cmd, + "no redistribute bgp route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n"); + +DEFUN (ripng_redistribute_kernel_metric_routemap, + ripng_redistribute_kernel_metric_routemap_cmd, + "redistribute kernel metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_KERNEL, atoi (argv[0])); + ripng_redistribute_routemap_set (ZEBRA_ROUTE_KERNEL, argv[1]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_KERNEL); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_kernel, + no_ripng_redistribute_kernel_metric_routemap_cmd, + "no redistribute kernel metric <0-16> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n"); + +DEFUN (ripng_redistribute_connected_metric_routemap, + ripng_redistribute_connected_metric_routemap_cmd, + "redistribute connected metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_CONNECT, atoi (argv[0])); + ripng_redistribute_routemap_set (ZEBRA_ROUTE_CONNECT, argv[1]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_CONNECT); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_connected, + no_ripng_redistribute_connected_metric_routemap_cmd, + "no redistribute connected metric <0-16> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n"); + +DEFUN (ripng_redistribute_static_metric_routemap, + ripng_redistribute_static_metric_routemap_cmd, + "redistribute static metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_STATIC, atoi (argv[0])); + ripng_redistribute_routemap_set (ZEBRA_ROUTE_STATIC, argv[1]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_STATIC); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_static, + no_ripng_redistribute_static_metric_routemap_cmd, + "no redistribute static metric <0-16> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n"); + +DEFUN (ripng_redistribute_ospf6_metric_routemap, + ripng_redistribute_ospf6_metric_routemap_cmd, + "redistribute ospf6 metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_OSPF6, atoi (argv[0])); + ripng_redistribute_routemap_set (ZEBRA_ROUTE_OSPF6, argv[1]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_OSPF6); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_ospf6, + no_ripng_redistribute_ospf6_metric_routemap_cmd, + "no redistribute ospf6 metric <0-16> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n"); + +DEFUN (ripng_redistribute_bgp_metric_routemap, + ripng_redistribute_bgp_metric_routemap_cmd, + "redistribute bgp metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + ripng_redistribute_metric_set (ZEBRA_ROUTE_BGP, atoi (argv[0])); + ripng_redistribute_routemap_set (ZEBRA_ROUTE_BGP, argv[1]); + zclient_redistribute_set (zclient, ZEBRA_ROUTE_BGP); + return CMD_SUCCESS; +} + +ALIAS (no_ripng_redistribute_bgp, + no_ripng_redistribute_bgp_metric_routemap_cmd, + "no redistribute bgp metric <0-16> route-map WORD", + NO_STR + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n"); + +void +ripng_redistribute_write (struct vty *vty) +{ + int i; + char *str[] = { "system", "kernel", "connected", "static", "rip", + "ripng", "ospf", "ospf6", "bgp"}; + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (i != zclient->redist_default && zclient->redist[i]) + { + if (ripng->route_map[i].metric_config) + { + if (ripng->route_map[i].name) + vty_out (vty, " redistribute %s metric %d route-map %s%s", + str[i], ripng->route_map[i].metric, + ripng->route_map[i].name, VTY_NEWLINE); + else + vty_out (vty, " redistribute %s metric %d%s", + str[i], ripng->route_map[i].metric, VTY_NEWLINE); + } + else + { + if (ripng->route_map[i].name) + vty_out (vty, " redistribute %s route-map %s%s", + str[i], ripng->route_map[i].name, VTY_NEWLINE); + else + vty_out (vty, " redistribute %s%s", str[i], VTY_NEWLINE); + } + } +} + +/* RIPng configuration write function. */ +int +zebra_config_write (struct vty *vty) +{ + if (! zclient->enable) + { + vty_out (vty, "no router zebra%s", VTY_NEWLINE); + return 1; + } + else if (! zclient->redist[ZEBRA_ROUTE_RIPNG]) + { + vty_out (vty, "router zebra%s", VTY_NEWLINE); + vty_out (vty, " no redistribute ripng%s", VTY_NEWLINE); + return 1; + } + return 0; +} + +/* Zebra node structure. */ +struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "%s(config-router)# ", +}; + +/* Initialize zebra structure and it's commands. */ +void +zebra_init () +{ + /* Allocate zebra structure. */ + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_RIPNG); + + zclient->interface_up = ripng_interface_up; + zclient->interface_down = ripng_interface_down; + zclient->interface_add = ripng_interface_add; + zclient->interface_delete = ripng_interface_delete; + zclient->interface_address_add = ripng_interface_address_add; + zclient->interface_address_delete = ripng_interface_address_delete; + zclient->ipv6_route_add = ripng_zebra_read_ipv6; + zclient->ipv6_route_delete = ripng_zebra_read_ipv6; + + /* Install zebra node. */ + install_node (&zebra_node, zebra_config_write); + + /* Install command element for zebra node. */ + install_element (CONFIG_NODE, &router_zebra_cmd); + install_element (CONFIG_NODE, &no_router_zebra_cmd); + install_default (ZEBRA_NODE); + install_element (ZEBRA_NODE, &ripng_redistribute_ripng_cmd); + install_element (ZEBRA_NODE, &no_ripng_redistribute_ripng_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_static_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_static_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_kernel_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_connected_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_connected_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_bgp_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_ospf6_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_val_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_connected_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_connected_metric_cmd); + install_element (RIPNG_NODE, + &no_ripng_redistribute_connected_metric_val_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_static_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_val_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_val_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_val_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_kernel_routemap_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_connected_routemap_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_connected_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_static_routemap_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_static_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_ospf6_routemap_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_bgp_routemap_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_routemap_cmd); + install_element (RIPNG_NODE, + &no_ripng_redistribute_kernel_metric_routemap_cmd); + install_element (RIPNG_NODE, + &ripng_redistribute_connected_metric_routemap_cmd); + install_element (RIPNG_NODE, + &no_ripng_redistribute_connected_metric_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_static_metric_routemap_cmd); + install_element (RIPNG_NODE, + &no_ripng_redistribute_static_metric_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_routemap_cmd); + install_element (RIPNG_NODE, + &no_ripng_redistribute_ospf6_metric_routemap_cmd); + install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_routemap_cmd); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_routemap_cmd); +} diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c new file mode 100644 index 0000000..982e410 --- /dev/null +++ b/ripngd/ripngd.c @@ -0,0 +1,2404 @@ +/* RIPng daemon + * Copyright (C) 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +/* For struct udphdr. */ +#include + +#include "prefix.h" +#include "filter.h" +#include "log.h" +#include "thread.h" +#include "memory.h" +#include "if.h" +#include "stream.h" +#include "table.h" +#include "command.h" +#include "sockopt.h" +#include "distribute.h" +#include "plist.h" +#include "routemap.h" + +#include "ripngd/ripngd.h" +#include "ripngd/ripng_route.h" +#include "ripngd/ripng_debug.h" +#include "ripngd/ripng_ifrmap.h" + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +/* RIPng structure which includes many parameters related to RIPng + protocol. If ripng couldn't active or ripng doesn't configured, + ripng->fd must be negative value. */ +struct ripng *ripng = NULL; + +enum +{ + ripng_all_route, + ripng_changed_route, + ripng_split_horizon, + ripng_no_split_horizon +}; + +/* Prototypes. */ +void +ripng_output_process (struct interface *, struct sockaddr_in6 *, int, int); + +int +ripng_triggered_update (struct thread *); + +/* RIPng next hop specification. */ +struct ripng_nexthop +{ + enum ripng_nexthop_type + { + RIPNG_NEXTHOP_UNSPEC, + RIPNG_NEXTHOP_ADDRESS + } flag; + struct in6_addr address; +}; + +/* Utility function for making IPv6 address string. */ +const char * +inet6_ntop (struct in6_addr *p) +{ + static char buf[INET6_ADDRSTRLEN]; + + inet_ntop (AF_INET6, p, buf, INET6_ADDRSTRLEN); + + return buf; +} + +/* Allocate new ripng information. */ +struct ripng_info * +ripng_info_new () +{ + struct ripng_info *new; + + new = XCALLOC (MTYPE_RIPNG_ROUTE, sizeof (struct ripng_info)); + return new; +} + +/* Free ripng information. */ +void +ripng_info_free (struct ripng_info *rinfo) +{ + XFREE (MTYPE_RIPNG_ROUTE, rinfo); +} + +static int +setsockopt_so_recvbuf (int sock, int size) +{ + int ret; + + ret = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof (int)); + if (ret < 0) + zlog (NULL, LOG_ERR, "can't setsockopt SO_RCVBUF"); + return ret; +} + +/* Create ripng socket. */ +int +ripng_make_socket (void) +{ + int ret; + int sock; + struct sockaddr_in6 ripaddr; + + sock = socket (AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + zlog (NULL, LOG_ERR, "Can't make ripng socket"); + return sock; + } + + ret = setsockopt_so_recvbuf (sock, 8096); + if (ret < 0) + return ret; + ret = setsockopt_ipv6_pktinfo (sock, 1); + if (ret < 0) + return ret; + ret = setsockopt_ipv6_multicast_hops (sock, 255); + if (ret < 0) + return ret; + ret = setsockopt_ipv6_multicast_loop (sock, 0); + if (ret < 0) + return ret; + ret = setsockopt_ipv6_hoplimit (sock, 1); + if (ret < 0) + return ret; + + memset (&ripaddr, 0, sizeof (ripaddr)); + ripaddr.sin6_family = AF_INET6; +#ifdef SIN6_LEN + ripaddr.sin6_len = sizeof (struct sockaddr_in6); +#endif /* SIN6_LEN */ + ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT); + + ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr)); + if (ret < 0) + { + zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", strerror (errno)); + return ret; + } + return sock; +} + +/* Send RIPng packet. */ +int +ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to, + struct interface *ifp) +{ + int ret; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsgptr; + char adata [256]; + struct in6_pktinfo *pkt; + struct sockaddr_in6 addr; + +#ifdef DEBUG + if (to) + zlog_info ("DEBUG RIPng: send to %s", inet6_ntop (&to->sin6_addr)); + zlog_info ("DEBUG RIPng: send if %s", ifp->name); + zlog_info ("DEBUG RIPng: send packet size %d", bufsize); +#endif /* DEBUG */ + + memset (&addr, 0, sizeof (struct sockaddr_in6)); + addr.sin6_family = AF_INET6; +#ifdef SIN6_LEN + addr.sin6_len = sizeof (struct sockaddr_in6); +#endif /* SIN6_LEN */ + addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT); + + /* When destination is specified. */ + if (to != NULL) + { + addr.sin6_addr = to->sin6_addr; + addr.sin6_port = to->sin6_port; + } + else + { + inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr); + addr.sin6_port = htons (RIPNG_PORT_DEFAULT); + } + + msg.msg_name = (void *) &addr; + msg.msg_namelen = sizeof (struct sockaddr_in6); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = (void *) adata; + msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); + + iov.iov_base = buf; + iov.iov_len = bufsize; + + cmsgptr = (struct cmsghdr *)adata; + cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo)); + cmsgptr->cmsg_level = IPPROTO_IPV6; + cmsgptr->cmsg_type = IPV6_PKTINFO; + + pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr); + memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr)); + pkt->ipi6_ifindex = ifp->ifindex; + + ret = sendmsg (ripng->sock, &msg, 0); + + if (ret < 0) + zlog_warn ("RIPng send fail on %s: %s", ifp->name, strerror (errno)); + + return ret; +} + +/* Receive UDP RIPng packet from socket. */ +int +ripng_recv_packet (int sock, u_char *buf, int bufsize, + struct sockaddr_in6 *from, unsigned int *ifindex, + int *hoplimit) +{ + int ret; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsgptr; + struct in6_addr dst; + + /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this + point I can't determine size of cmsghdr */ + char adata[1024]; + + /* Fill in message and iovec. */ + msg.msg_name = (void *) from; + msg.msg_namelen = sizeof (struct sockaddr_in6); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = (void *) adata; + msg.msg_controllen = sizeof adata; + iov.iov_base = buf; + iov.iov_len = bufsize; + + /* If recvmsg fail return minus value. */ + ret = recvmsg (sock, &msg, 0); + if (ret < 0) + return ret; + + for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; + cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) + { + /* I want interface index which this packet comes from. */ + if (cmsgptr->cmsg_level == IPPROTO_IPV6 && + cmsgptr->cmsg_type == IPV6_PKTINFO) + { + struct in6_pktinfo *ptr; + + ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr); + *ifindex = ptr->ipi6_ifindex; + dst = ptr->ipi6_addr; + + if (*ifindex == 0) + zlog_warn ("Interface index returned by IPV6_PKTINFO is zero"); + } + + /* Incoming packet's multicast hop limit. */ + if (cmsgptr->cmsg_level == IPPROTO_IPV6 && + cmsgptr->cmsg_type == IPV6_HOPLIMIT) + *hoplimit = *((int *) CMSG_DATA (cmsgptr)); + } + + /* Hoplimit check shold be done when destination address is + multicast address. */ + if (! IN6_IS_ADDR_MULTICAST (&dst)) + *hoplimit = -1; + + return ret; +} + +/* Dump rip packet */ +void +ripng_packet_dump (struct ripng_packet *packet, int size, char *sndrcv) +{ + caddr_t lim; + struct rte *rte; + char *command_str; + + /* Set command string. */ + if (packet->command == RIPNG_REQUEST) + command_str = "request"; + else if (packet->command == RIPNG_RESPONSE) + command_str = "response"; + else + command_str = "unknown"; + + /* Dump packet header. */ + zlog_info ("%s %s version %d packet size %d", + sndrcv, command_str, packet->version, size); + + /* Dump each routing table entry. */ + rte = packet->rte; + + for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++) + { + if (rte->metric == RIPNG_METRIC_NEXTHOP) + zlog_info (" nexthop %s/%d", inet6_ntop (&rte->addr), rte->prefixlen); + else + zlog_info (" %s/%d metric %d tag %d", + inet6_ntop (&rte->addr), rte->prefixlen, + rte->metric, ntohs (rte->tag)); + } +} + +/* RIPng next hop address RTE (Route Table Entry). */ +void +ripng_nexthop_rte (struct rte *rte, + struct sockaddr_in6 *from, + struct ripng_nexthop *nexthop) +{ + char buf[INET6_BUFSIZ]; + + /* Logging before checking RTE. */ + if (IS_RIPNG_DEBUG_RECV) + zlog_info ("RIPng nexthop RTE address %s tag %d prefixlen %d", + inet6_ntop (&rte->addr), ntohs (rte->tag), rte->prefixlen); + + /* RFC2080 2.1.1 Next Hop: + The route tag and prefix length in the next hop RTE must be + set to zero on sending and ignored on receiption. */ + if (ntohs (rte->tag) != 0) + zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s", + ntohs (rte->tag), inet6_ntop (&from->sin6_addr)); + + if (rte->prefixlen != 0) + zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s", + rte->prefixlen, inet6_ntop (&from->sin6_addr)); + + /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a + next hop RTE indicates that the next hop address should be the + originator of the RIPng advertisement. An address specified as a + next hop must be a link-local address. */ + if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr)) + { + nexthop->flag = RIPNG_NEXTHOP_UNSPEC; + memset (&nexthop->address, 0, sizeof (struct in6_addr)); + return; + } + + if (IN6_IS_ADDR_LINKLOCAL (&rte->addr)) + { + nexthop->flag = RIPNG_NEXTHOP_ADDRESS; + IPV6_ADDR_COPY (&nexthop->address, &rte->addr); + return; + } + + /* The purpose of the next hop RTE is to eliminate packets being + routed through extra hops in the system. It is particularly useful + when RIPng is not being run on all of the routers on a network. + Note that next hop RTE is "advisory". That is, if the provided + information is ignored, a possibly sub-optimal, but absolutely + valid, route may be taken. If the received next hop address is not + a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */ + zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s", + inet6_ntop (&rte->addr), + inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ)); + + nexthop->flag = RIPNG_NEXTHOP_UNSPEC; + memset (&nexthop->address, 0, sizeof (struct in6_addr)); + + return; +} + +/* If ifp has same link-local address then return 1. */ +int +ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr) +{ + listnode listnode; + struct connected *connected; + struct prefix *p; + + for (listnode = listhead (ifp->connected); listnode; nextnode (listnode)) + if ((connected = getdata (listnode)) != NULL) + { + p = connected->address; + + if (p->family == AF_INET6 && + IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) && + IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr)) + return 1; + } + return 0; +} + +/* RIPng route garbage collect timer. */ +int +ripng_garbage_collect (struct thread *t) +{ + struct ripng_info *rinfo; + struct route_node *rp; + + rinfo = THREAD_ARG (t); + rinfo->t_garbage_collect = NULL; + + /* Off timeout timer. */ + RIPNG_TIMER_OFF (rinfo->t_timeout); + + /* Get route_node pointer. */ + rp = rinfo->rp; + + /* Delete this route from the kernel. */ + ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, + &rinfo->nexthop, rinfo->ifindex); + rinfo->flags &= ~RIPNG_RTF_FIB; + + /* Aggregate count decrement. */ + ripng_aggregate_decrement (rp, rinfo); + + /* Unlock route_node. */ + rp->info = NULL; + route_unlock_node (rp); + + /* Free RIPng routing information. */ + ripng_info_free (rinfo); + + return 0; +} + +/* Timeout RIPng routes. */ +int +ripng_timeout (struct thread *t) +{ + struct ripng_info *rinfo; + struct route_node *rp; + + rinfo = THREAD_ARG (t); + rinfo->t_timeout = NULL; + + /* Get route_node pointer. */ + rp = rinfo->rp; + + /* - The garbage-collection timer is set for 120 seconds. */ + RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, + ripng->garbage_time); + + /* - The metric for the route is set to 16 (infinity). This causes + the route to be removed from service. */ + rinfo->metric = RIPNG_METRIC_INFINITY; + + /* - The route change flag is to indicate that this entry has been + changed. */ + rinfo->flags |= RIPNG_RTF_CHANGED; + + /* - The output process is signalled to trigger a response. */ + ripng_event (RIPNG_TRIGGERED_UPDATE, 0); + + return 0; +} + +void +ripng_timeout_update (struct ripng_info *rinfo) +{ + if (rinfo->metric != RIPNG_METRIC_INFINITY) + { + RIPNG_TIMER_OFF (rinfo->t_timeout); + RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time); + } +} + +/* Process RIPng route according to RFC2080. */ +void +ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, + struct ripng_nexthop *ripng_nexthop, + struct interface *ifp) +{ + struct prefix_ipv6 p; + struct route_node *rp; + struct ripng_info *rinfo; + struct ripng_interface *ri; + struct in6_addr *nexthop; + u_char oldmetric; + int same = 0; + + /* Make prefix structure. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + /* p.prefix = rte->addr; */ + IPV6_ADDR_COPY (&p.prefix, &rte->addr); + p.prefixlen = rte->prefixlen; + + /* Make sure mask is applied. */ + /* XXX We have to check the prefix is valid or not before call + apply_mask_ipv6. */ + apply_mask_ipv6 (&p); + + /* Apply input filters. */ + ri = ifp->info; + + if (ri->list[RIPNG_FILTER_IN]) + { + if (access_list_apply (ri->list[RIPNG_FILTER_IN], &p) == FILTER_DENY) + { + if (IS_RIPNG_DEBUG_PACKET) + zlog_info ("RIPng %s/%d is filtered by distribute in", + inet6_ntop (&p.prefix), p.prefixlen); + return; + } + } + if (ri->prefix[RIPNG_FILTER_IN]) + { + if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN], &p) == PREFIX_DENY) + { + if (IS_RIPNG_DEBUG_PACKET) + zlog_info ("RIPng %s/%d is filtered by prefix-list in", + inet6_ntop (&p.prefix), p.prefixlen); + return; + } + } + + /* Modify entry. */ + if (ri->routemap[RIPNG_FILTER_IN]) + { + int ret; + struct ripng_info newinfo; + + memset (&newinfo, 0, sizeof (struct ripng_info)); + newinfo.metric = rte->metric; + + ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN], + (struct prefix *)&p, RMAP_RIPNG, &newinfo); + + if (ret == RMAP_DENYMATCH) + { + if (IS_RIPNG_DEBUG_PACKET) + zlog_info ("RIPng %s/%d is filtered by route-map in", + inet6_ntop (&p.prefix), p.prefixlen); + return; + } + + rte->metric = newinfo.metric; + } + + /* Set nexthop pointer. */ + if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) + nexthop = &ripng_nexthop->address; + else + nexthop = &from->sin6_addr; + + /* Lookup RIPng routing table. */ + rp = route_node_get (ripng->table, (struct prefix *) &p); + + if (rp->info == NULL) + { + /* Now, check to see whether there is already an explicit route + for the destination prefix. If there is no such route, add + this route to the routing table, unless the metric is + infinity (there is no point in adding a route which + unusable). */ + if (rte->metric != RIPNG_METRIC_INFINITY) + { + rinfo = ripng_info_new (); + + /* - Setting the destination prefix and length to those in + the RTE. */ + rp->info = rinfo; + rinfo->rp = rp; + + /* - Setting the metric to the newly calculated metric (as + described above). */ + rinfo->metric = rte->metric; + rinfo->tag = ntohs (rte->tag); + + /* - Set the next hop address to be the address of the router + from which the datagram came or the next hop address + specified by a next hop RTE. */ + IPV6_ADDR_COPY (&rinfo->nexthop, nexthop); + IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr); + rinfo->ifindex = ifp->ifindex; + + /* - Initialize the timeout for the route. If the + garbage-collection timer is running for this route, stop it. */ + ripng_timeout_update (rinfo); + + /* - Set the route change flag. */ + rinfo->flags |= RIPNG_RTF_CHANGED; + + /* - Signal the output process to trigger an update (see section + 2.5). */ + ripng_event (RIPNG_TRIGGERED_UPDATE, 0); + + /* Finally, route goes into the kernel. */ + rinfo->type = ZEBRA_ROUTE_RIPNG; + rinfo->sub_type = RIPNG_ROUTE_RTE; + + ripng_zebra_ipv6_add (&p, &rinfo->nexthop, rinfo->ifindex); + rinfo->flags |= RIPNG_RTF_FIB; + + /* Aggregate check. */ + ripng_aggregate_increment (rp, rinfo); + } + } + else + { + rinfo = rp->info; + + /* If there is an existing route, compare the next hop address + to the address of the router from which the datagram came. + If this datagram is from the same router as the existing + route, reinitialize the timeout. */ + same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr) + && (rinfo->ifindex == ifp->ifindex)); + + if (same) + ripng_timeout_update (rinfo); + + /* Next, compare the metrics. If the datagram is from the same + router as the existing route, and the new metric is different + than the old one; or, if the new metric is lower than the old + one; do the following actions: */ + if ((same && rinfo->metric != rte->metric) || + rte->metric < rinfo->metric) + { + /* - Adopt the route from the datagram. That is, put the + new metric in, and adjust the next hop address (if + necessary). */ + oldmetric = rinfo->metric; + rinfo->metric = rte->metric; + rinfo->tag = ntohs (rte->tag); + + if (! IN6_ARE_ADDR_EQUAL (&rinfo->nexthop, nexthop)) + { + ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex); + ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex); + rinfo->flags |= RIPNG_RTF_FIB; + + IPV6_ADDR_COPY (&rinfo->nexthop, nexthop); + } + IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr); + rinfo->ifindex = ifp->ifindex; + + /* - Set the route change flag and signal the output process + to trigger an update. */ + rinfo->flags |= RIPNG_RTF_CHANGED; + ripng_event (RIPNG_TRIGGERED_UPDATE, 0); + + /* - If the new metric is infinity, start the deletion + process (described above); */ + if (rinfo->metric == RIPNG_METRIC_INFINITY) + { + /* If the new metric is infinity, the deletion process + begins for the route, which is no longer used for + routing packets. Note that the deletion process is + started only when the metric is first set to + infinity. If the metric was already infinity, then a + new deletion process is not started. */ + if (oldmetric != RIPNG_METRIC_INFINITY) + { + /* - The garbage-collection timer is set for 120 seconds. */ + RIPNG_TIMER_ON (rinfo->t_garbage_collect, + ripng_garbage_collect, ripng->garbage_time); + RIPNG_TIMER_OFF (rinfo->t_timeout); + + /* - The metric for the route is set to 16 + (infinity). This causes the route to be removed + from service.*/ + /* - The route change flag is to indicate that this + entry has been changed. */ + /* - The output process is signalled to trigger a + response. */ + ; /* Above processes are already done previously. */ + } + } + else + { + /* otherwise, re-initialize the timeout. */ + ripng_timeout_update (rinfo); + + /* Should a new route to this network be established + while the garbage-collection timer is running, the + new route will replace the one that is about to be + deleted. In this case the garbage-collection timer + must be cleared. */ + RIPNG_TIMER_OFF (rinfo->t_garbage_collect); + } + } + /* Unlock tempolary lock of the route. */ + route_unlock_node (rp); + } +} + +/* Add redistributed route to RIPng table. */ +void +ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, + unsigned int ifindex) +{ + struct route_node *rp; + struct ripng_info *rinfo; + + /* Redistribute route */ + if (IN6_IS_ADDR_LINKLOCAL (&p->prefix)) + return; + if (IN6_IS_ADDR_LOOPBACK (&p->prefix)) + return; + + rp = route_node_get (ripng->table, (struct prefix *) p); + rinfo = rp->info; + + if (rinfo) + { + RIPNG_TIMER_OFF (rinfo->t_timeout); + RIPNG_TIMER_OFF (rinfo->t_garbage_collect); + route_unlock_node (rp); + } + else + { + rinfo = ripng_info_new (); + ripng_aggregate_increment (rp, rinfo); + } + + rinfo->type = type; + rinfo->sub_type = sub_type; + rinfo->ifindex = ifindex; + rinfo->metric = 1; + rinfo->flags |= RIPNG_RTF_FIB; + + rinfo->rp = rp; + rp->info = rinfo; +} + +/* Delete redistributed route to RIPng table. */ +void +ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p, + unsigned int ifindex) +{ + struct route_node *rp; + struct ripng_info *rinfo; + + if (IN6_IS_ADDR_LINKLOCAL (&p->prefix)) + return; + if (IN6_IS_ADDR_LOOPBACK (&p->prefix)) + return; + + rp = route_node_lookup (ripng->table, (struct prefix *) p); + + if (rp) + { + rinfo = rp->info; + + if (rinfo != NULL + && rinfo->type == type + && rinfo->sub_type == sub_type + && rinfo->ifindex == ifindex) + { + rp->info = NULL; + + RIPNG_TIMER_OFF (rinfo->t_timeout); + RIPNG_TIMER_OFF (rinfo->t_garbage_collect); + + ripng_info_free (rinfo); + + route_unlock_node (rp); + } + + /* For unlock route_node_lookup (). */ + route_unlock_node (rp); + } +} + +/* Withdraw redistributed route. */ +void +ripng_redistribute_withdraw (int type) +{ + struct route_node *rp; + struct ripng_info *rinfo; + + for (rp = route_top (ripng->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + { + if (rinfo->type == type) + { + rp->info = NULL; + + RIPNG_TIMER_OFF (rinfo->t_timeout); + RIPNG_TIMER_OFF (rinfo->t_garbage_collect); + + ripng_info_free (rinfo); + + route_unlock_node (rp); + } + } +} + +/* RIP routing information. */ +void +ripng_response_process (struct ripng_packet *packet, int size, + struct sockaddr_in6 *from, struct interface *ifp, + int hoplimit) +{ + caddr_t lim; + struct rte *rte; + struct ripng_nexthop nexthop; + + /* RFC2080 2.4.2 Response Messages: + The Response must be ignored if it is not from the RIPng port. */ + if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT) + { + zlog_warn ("RIPng packet comes from non RIPng port %d from %s", + ntohs (from->sin6_port), inet6_ntop (&from->sin6_addr)); + return; + } + + /* The datagram's IPv6 source address should be checked to see + whether the datagram is from a valid neighbor; the source of the + datagram must be a link-local address. */ + if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) + { + zlog_warn ("RIPng packet comes from non link local address %s", + inet6_ntop (&from->sin6_addr)); + return; + } + + /* It is also worth checking to see whether the response is from one + of the router's own addresses. Interfaces on broadcast networks + may receive copies of their own multicasts immediately. If a + router processes its own output as new input, confusion is likely, + and such datagrams must be ignored. */ + if (ripng_lladdr_check (ifp, &from->sin6_addr)) + { + zlog_warn ("RIPng packet comes from my own link local address %s", + inet6_ntop (&from->sin6_addr)); + return; + } + + /* As an additional check, periodic advertisements must have their + hop counts set to 255, and inbound, multicast packets sent from the + RIPng port (i.e. periodic advertisement or triggered update + packets) must be examined to ensure that the hop count is 255. */ + if (hoplimit >= 0 && hoplimit != 255) + { + zlog_warn ("RIPng packet comes with non 255 hop count %d from %s", + hoplimit, inet6_ntop (&from->sin6_addr)); + return; + } + + /* Reset nexthop. */ + memset (&nexthop, 0, sizeof (struct ripng_nexthop)); + nexthop.flag = RIPNG_NEXTHOP_UNSPEC; + + /* Set RTE pointer. */ + rte = packet->rte; + + for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++) + { + /* First of all, we have to check this RTE is next hop RTE or + not. Next hop RTE is completely different with normal RTE so + we need special treatment. */ + if (rte->metric == RIPNG_METRIC_NEXTHOP) + { + ripng_nexthop_rte (rte, from, &nexthop); + continue; + } + + /* RTE information validation. */ + + /* - is the destination prefix valid (e.g., not a multicast + prefix and not a link-local address) A link-local address + should never be present in an RTE. */ + if (IN6_IS_ADDR_MULTICAST (&rte->addr)) + { + zlog_warn ("Destination prefix is a multicast address %s/%d [%d]", + inet6_ntop (&rte->addr), rte->prefixlen, rte->metric); + continue; + } + if (IN6_IS_ADDR_LINKLOCAL (&rte->addr)) + { + zlog_warn ("Destination prefix is a link-local address %s/%d [%d]", + inet6_ntop (&rte->addr), rte->prefixlen, rte->metric); + continue; + } + if (IN6_IS_ADDR_LOOPBACK (&rte->addr)) + { + zlog_warn ("Destination prefix is a loopback address %s/%d [%d]", + inet6_ntop (&rte->addr), rte->prefixlen, rte->metric); + continue; + } + + /* - is the prefix length valid (i.e., between 0 and 128, + inclusive) */ + if (rte->prefixlen > 128) + { + zlog_warn ("Invalid prefix length %s/%d from %s%%%s", + inet6_ntop (&rte->addr), rte->prefixlen, + inet6_ntop (&from->sin6_addr), ifp->name); + continue; + } + + /* - is the metric valid (i.e., between 1 and 16, inclusive) */ + if (! (rte->metric >= 1 && rte->metric <= 16)) + { + zlog_warn ("Invalid metric %d from %s%%%s", rte->metric, + inet6_ntop (&from->sin6_addr), ifp->name); + continue; + } + + /* Metric calculation. */ + rte->metric += ifp->metric; + if (rte->metric > RIPNG_METRIC_INFINITY) + rte->metric = RIPNG_METRIC_INFINITY; + + /* Routing table updates. */ + ripng_route_process (rte, from, &nexthop, ifp); + } +} + +/* Response to request message. */ +void +ripng_request_process (struct ripng_packet *packet,int size, + struct sockaddr_in6 *from, struct interface *ifp) +{ + caddr_t lim; + struct rte *rte; + struct prefix_ipv6 p; + struct route_node *rp; + struct ripng_info *rinfo; + struct ripng_interface *ri; + + /* Check RIPng process is enabled on this interface. */ + ri = ifp->info; + if (! ri->running) + return; + + /* When passive interface is specified, suppress responses */ + if (ri->passive) + return; + + lim = ((caddr_t) packet) + size; + rte = packet->rte; + + /* The Request is processed entry by entry. If there are no + entries, no response is given. */ + if (lim == (caddr_t) rte) + return; + + /* There is one special case. If there is exactly one entry in the + request, and it has a destination prefix of zero, a prefix length + of zero, and a metric of infinity (i.e., 16), then this is a + request to send the entire routing table. In that case, a call + is made to the output process to send the routing table to the + requesting address/port. */ + if (lim == ((caddr_t) (rte + 1)) && + IN6_IS_ADDR_UNSPECIFIED (&rte->addr) && + rte->prefixlen == 0 && + rte->metric == RIPNG_METRIC_INFINITY) + { + /* All route with split horizon */ + ripng_output_process (ifp, from, ripng_all_route, ripng_split_horizon); + } + else + { + /* Except for this special case, processing is quite simple. + Examine the list of RTEs in the Request one by one. For each + entry, look up the destination in the router's routing + database and, if there is a route, put that route's metric in + the metric field of the RTE. If there is no explicit route + to the specified destination, put infinity in the metric + field. Once all the entries have been filled in, change the + command from Request to Response and send the datagram back + to the requestor. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + + for (; ((caddr_t) rte) < lim; rte++) + { + p.prefix = rte->addr; + p.prefixlen = rte->prefixlen; + apply_mask_ipv6 (&p); + + rp = route_node_lookup (ripng->table, (struct prefix *) &p); + + if (rp) + { + rinfo = rp->info; + rte->metric = rinfo->metric; + route_unlock_node (rp); + } + else + rte->metric = RIPNG_METRIC_INFINITY; + } + packet->command = RIPNG_RESPONSE; + + ripng_send_packet ((caddr_t) packet, size, from, ifp); + } +} + +/* First entry point of reading RIPng packet. */ +int +ripng_read (struct thread *thread) +{ + int len; + int sock; + struct sockaddr_in6 from; + struct ripng_packet *packet; + unsigned int ifindex; + struct interface *ifp; + int hoplimit = -1; + + /* Check ripng is active and alive. */ + assert (ripng != NULL); + assert (ripng->sock >= 0); + + /* Fetch thread data and set read pointer to empty for event + managing. `sock' sould be same as ripng->sock. */ + sock = THREAD_FD (thread); + ripng->t_read = NULL; + + /* Add myself to the next event. */ + ripng_event (RIPNG_READ, sock); + + /* Read RIPng packet. */ + len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf), + STREAM_SIZE (ripng->ibuf), &from, &ifindex, + &hoplimit); + if (len < 0) + { + zlog_warn ("RIPng recvfrom failed: %s.", strerror (errno)); + return len; + } + + /* Check RTE boundary. RTE size (Packet length - RIPng header size + (4)) must be multiple size of one RTE size (20). */ + if (((len - 4) % 20) != 0) + { + zlog_warn ("RIPng invalid packet size %d from %s", len, + inet6_ntop (&from.sin6_addr)); + return 0; + } + + packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf); + ifp = if_lookup_by_index (ifindex); + + /* RIPng packet received. */ + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng packet received from %s port %d on %s", + inet6_ntop (&from.sin6_addr), ntohs (from.sin6_port), + ifp ? ifp->name : "unknown"); + + /* Logging before packet checking. */ + if (IS_RIPNG_DEBUG_RECV) + ripng_packet_dump (packet, len, "RECV"); + + /* Packet comes from unknown interface. */ + if (ifp == NULL) + { + zlog_warn ("RIPng packet comes from unknown interface %d", ifindex); + return 0; + } + + /* Packet version mismatch checking. */ + if (packet->version != ripng->version) + { + zlog_warn ("RIPng packet version %d doesn't fit to my version %d", + packet->version, ripng->version); + return 0; + } + + /* Process RIPng packet. */ + switch (packet->command) + { + case RIPNG_REQUEST: + ripng_request_process (packet, len, &from, ifp); + break; + case RIPNG_RESPONSE: + ripng_response_process (packet, len, &from, ifp, hoplimit); + break; + default: + zlog_warn ("Invalid RIPng command %d", packet->command); + break; + } + return 0; +} + +/* Walk down the RIPng routing table then clear changed flag. */ +void +ripng_clear_changed_flag () +{ + struct route_node *rp; + struct ripng_info *rinfo; + + for (rp = route_top (ripng->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + if (rinfo->flags & RIPNG_RTF_CHANGED) + rinfo->flags &= ~RIPNG_RTF_CHANGED; +} + +/* Regular update of RIPng route. Send all routing formation to RIPng + enabled interface. */ +int +ripng_update (struct thread *t) +{ + listnode node; + struct interface *ifp; + struct ripng_interface *ri; + + /* Clear update timer thread. */ + ripng->t_update = NULL; + + /* Logging update event. */ + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng update timer expired!"); + + /* Supply routes to each interface. */ + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ri = ifp->info; + + if (if_is_loopback (ifp) || ! if_is_up (ifp)) + continue; + + if (! ri->running) + continue; + + /* When passive interface is specified, suppress announce to the + interface. */ + if (ri->passive) + continue; + +#if RIPNG_ADVANCED + if (ri->ri_send == RIPNG_SEND_OFF) + { + if (IS_RIPNG_DEBUG_EVENT) + zlog (NULL, LOG_INFO, + "[Event] RIPng send to if %d is suppressed by config", + ifp->ifindex); + continue; + } +#endif /* RIPNG_ADVANCED */ + + ripng_output_process (ifp, NULL, ripng_all_route, ripng_split_horizon); + } + + /* Triggered updates may be suppressed if a regular update is due by + the time the triggered update would be sent. */ + if (ripng->t_triggered_interval) + { + thread_cancel (ripng->t_triggered_interval); + ripng->t_triggered_interval = NULL; + } + ripng->trigger = 0; + + /* Reset flush event. */ + ripng_event (RIPNG_UPDATE_EVENT, 0); + + return 0; +} + +/* Triggered update interval timer. */ +int +ripng_triggered_interval (struct thread *t) +{ + ripng->t_triggered_interval = NULL; + + if (ripng->trigger) + { + ripng->trigger = 0; + ripng_triggered_update (t); + } + return 0; +} + +/* Execute triggered update. */ +int +ripng_triggered_update (struct thread *t) +{ + listnode node; + struct interface *ifp; + struct ripng_interface *ri; + int interval; + + ripng->t_triggered_update = NULL; + + /* Cancel interval timer. */ + if (ripng->t_triggered_interval) + { + thread_cancel (ripng->t_triggered_interval); + ripng->t_triggered_interval = NULL; + } + ripng->trigger = 0; + + /* Logging triggered update. */ + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng triggered update!"); + + /* Split Horizon processing is done when generating triggered + updates as well as normal updates (see section 2.6). */ + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ri = ifp->info; + + if (if_is_loopback (ifp) || ! if_is_up (ifp)) + continue; + + if (! ri->running) + continue; + + /* When passive interface is specified, suppress announce to the + interface. */ + if (ri->passive) + continue; + + ripng_output_process (ifp, NULL, ripng_changed_route, + ripng_split_horizon); + } + + /* Once all of the triggered updates have been generated, the route + change flags should be cleared. */ + ripng_clear_changed_flag (); + + /* After a triggered update is sent, a timer should be set for a + random interval between 1 and 5 seconds. If other changes that + would trigger updates occur before the timer expires, a single + update is triggered when the timer expires. */ + interval = (random () % 5) + 1; + + ripng->t_triggered_interval = + thread_add_timer (master, ripng_triggered_interval, NULL, interval); + + return 0; +} + +/* Write routing table entry to the stream and return next index of + the routing table entry in the stream. */ +int +ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p, + u_int16_t tag, u_char metric) +{ + /* RIPng packet header. */ + if (num == 0) + { + stream_putc (s, RIPNG_RESPONSE); + stream_putc (s, RIPNG_V1); + stream_putw (s, 0); + } + + /* Write routing table entry. */ + stream_write (s, (caddr_t) &p->prefix, sizeof (struct in6_addr)); + stream_putw (s, tag); + stream_putc (s, p->prefixlen); + stream_putc (s, metric); + + return ++num; +} + +/* Send RESPONSE message to specified destination. */ +void +ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to, + int route_type, int split_horizon) +{ + int ret; + struct stream *s; + struct route_node *rp; + struct ripng_info *rinfo; + struct ripng_interface *ri; + struct ripng_aggregate *aggregate; + struct prefix_ipv6 *p; + int num; + int mtu; + int rtemax; + u_char metric; + u_char metric_set; + + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng update routes on interface %s", ifp->name); + + /* Output stream get from ripng structre. XXX this should be + interface structure. */ + s = ripng->obuf; + + /* Reset stream and RTE counter. */ + stream_reset (s); + num = 0; + + mtu = ifp->mtu; + if (mtu < 0) + mtu = IFMINMTU; + + rtemax = (min (mtu, RIPNG_MAX_PACKET_SIZE) - + IPV6_HDRLEN - + sizeof (struct udphdr) - + sizeof (struct ripng_packet) + + sizeof (struct rte)) / sizeof (struct rte); + +#ifdef DEBUG + zlog_info ("DEBUG RIPng: ifmtu is %d", ifp->mtu); + zlog_info ("DEBUG RIPng: rtemax is %d", rtemax); +#endif /* DEBUG */ + + /* Get RIPng interface. */ + ri = ifp->info; + + for (rp = route_top (ripng->table); rp; rp = route_next (rp)) + { + if ((rinfo = rp->info) != NULL && rinfo->suppress == 0) + { + p = (struct prefix_ipv6 *) &rp->p; + metric = rinfo->metric; + + /* Changed route only output. */ + if (route_type == ripng_changed_route && + (! (rinfo->flags & RIPNG_RTF_CHANGED))) + continue; + + /* Split horizon. */ + if (split_horizon == ripng_split_horizon && + rinfo->ifindex == ifp->ifindex) + continue; + + /* Apply output filters.*/ + if (ri->list[RIPNG_FILTER_OUT]) + { + if (access_list_apply (ri->list[RIPNG_FILTER_OUT], + (struct prefix *) p) == FILTER_DENY) + { + if (IS_RIPNG_DEBUG_PACKET) + zlog_info ("RIPng %s/%d is filtered by distribute out", + inet6_ntop (&p->prefix), p->prefixlen); + continue; + } + } + if (ri->prefix[RIPNG_FILTER_OUT]) + { + if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT], + (struct prefix *) p) == PREFIX_DENY) + { + if (IS_RIPNG_DEBUG_PACKET) + zlog_info ("RIPng %s/%d is filtered by prefix-list out", + inet6_ntop (&p->prefix), p->prefixlen); + continue; + } + } + + /* Preparation for route-map. */ + metric_set = 0; + + /* Route-map */ + if (ri->routemap[RIPNG_FILTER_OUT]) + { + int ret; + struct ripng_info newinfo; + + memset (&newinfo, 0, sizeof (struct ripng_info)); + newinfo.metric = metric; + + ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT], + (struct prefix *) p, RMAP_RIPNG, + &newinfo); + + if (ret == RMAP_DENYMATCH) + { + if (IS_RIPNG_DEBUG_PACKET) + zlog_info ("RIPng %s/%d is filtered by route-map out", + inet6_ntop (&p->prefix), p->prefixlen); + return; + } + + metric = newinfo.metric; + metric_set = newinfo.metric_set; + } + + /* When the interface route-map does not set metric */ + if (! metric_set) + { + /* and the redistribute route-map is set. */ + if (ripng->route_map[rinfo->type].name) + { + int ret; + struct ripng_info newinfo; + + memset (&newinfo, 0, sizeof (struct ripng_info)); + newinfo.metric = metric; + + ret = route_map_apply (ripng->route_map[rinfo->type].map, + (struct prefix *) p, RMAP_RIPNG, + &newinfo); + + if (ret == RMAP_DENYMATCH) + { + if (IS_RIPNG_DEBUG_PACKET) + zlog_info ("RIPng %s/%d is filtered by route-map", + inet6_ntop (&p->prefix), p->prefixlen); + continue; + } + + metric = newinfo.metric; + metric_set = newinfo.metric_set; + } + + /* When the redistribute route-map does not set metric. */ + if (! metric_set) + { + /* If the redistribute metric is set. */ + if (ripng->route_map[rinfo->type].metric_config + && rinfo->metric != RIPNG_METRIC_INFINITY) + { + metric = ripng->route_map[rinfo->type].metric; + } + else + { + /* If the route is not connected or localy generated + one, use default-metric value */ + if (rinfo->type != ZEBRA_ROUTE_RIPNG + && rinfo->type != ZEBRA_ROUTE_CONNECT + && rinfo->metric != RIPNG_METRIC_INFINITY) + metric = ripng->default_metric; + } + } + } + + /* Write RTE to the stream. */ + num = ripng_write_rte (num, s, p, rinfo->tag, metric); + if (num == rtemax) + { + ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s), + to, ifp); + + if (ret >= 0 && IS_RIPNG_DEBUG_SEND) + ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s), + stream_get_endp(s), "SEND"); + num = 0; + stream_reset (s); + } + } + if ((aggregate = rp->aggregate) != NULL && + aggregate->count > 0 && + aggregate->suppress == 0) + { + p = (struct prefix_ipv6 *) &rp->p; + metric = aggregate->metric; + + /* Apply output filters.*/ + if (ri->list[RIPNG_FILTER_OUT]) + { + if (access_list_apply (ri->list[RIPNG_FILTER_OUT], + (struct prefix *) p) == FILTER_DENY) + { + if (IS_RIPNG_DEBUG_PACKET) + zlog_info ("RIPng %s/%d is filtered by distribute out", + inet6_ntop (&p->prefix), p->prefixlen); + continue; + } + } + if (ri->prefix[RIPNG_FILTER_OUT]) + { + if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT], + (struct prefix *) p) == PREFIX_DENY) + { + if (IS_RIPNG_DEBUG_PACKET) + zlog_info ("RIPng %s/%d is filtered by prefix-list out", + inet6_ntop (&p->prefix), p->prefixlen); + continue; + } + } + + /* Route-map */ + if (ri->routemap[RIPNG_FILTER_OUT]) + { + int ret; + struct ripng_info newinfo; + + memset (&newinfo, 0, sizeof (struct ripng_info)); + newinfo.metric = metric; + + ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT], + (struct prefix *) p, RMAP_RIPNG, + &newinfo); + + if (ret == RMAP_DENYMATCH) + { + if (IS_RIPNG_DEBUG_PACKET) + zlog_info ("RIPng %s/%d is filtered by route-map out", + inet6_ntop (&p->prefix), p->prefixlen); + return; + } + + metric = newinfo.metric; + } + + /* Changed route only output. */ + if (route_type == ripng_changed_route) + continue; + + /* Write RTE to the stream. */ + num = ripng_write_rte (num, s, p, aggregate->tag, metric); + if (num == rtemax) + { + ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s), + to, ifp); + + if (ret >= 0 && IS_RIPNG_DEBUG_SEND) + ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s), + stream_get_endp(s), "SEND"); + num = 0; + stream_reset (s); + } + } + + } + + /* If unwritten RTE exist, flush it. */ + if (num != 0) + { + ret = ripng_send_packet (STREAM_DATA (s), stream_get_endp (s), + to, ifp); + + if (ret >= 0 && IS_RIPNG_DEBUG_SEND) + ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s), + stream_get_endp (s), "SEND"); + num = 0; + stream_reset (s); + } +} + +/* Create new RIPng instance and set it to global variable. */ +int +ripng_create () +{ + /* ripng should be NULL. */ + assert (ripng == NULL); + + /* Allocaste RIPng instance. */ + ripng = XMALLOC (0, sizeof (struct ripng)); + memset (ripng, 0, sizeof (struct ripng)); + + /* Default version and timer values. */ + ripng->version = RIPNG_V1; + ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT; + ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT; + ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT; + ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT; + + /* Make buffer. */ + ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5); + ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE); + + /* Initialize RIPng routig table. */ + ripng->table = route_table_init (); + ripng->route = route_table_init (); + ripng->aggregate = route_table_init (); + + /* Make socket. */ + ripng->sock = ripng_make_socket (); + if (ripng->sock < 0) + return ripng->sock; + + /* Threads. */ + ripng_event (RIPNG_READ, ripng->sock); + ripng_event (RIPNG_UPDATE_EVENT, 1); + + return 0; +} + +/* Sned RIPng request to the interface. */ +int +ripng_request (struct interface *ifp) +{ + struct rte *rte; + struct ripng_packet ripng_packet; + + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng send request to %s", ifp->name); + + memset (&ripng_packet, 0, sizeof (ripng_packet)); + ripng_packet.command = RIPNG_REQUEST; + ripng_packet.version = RIPNG_V1; + rte = ripng_packet.rte; + rte->metric = RIPNG_METRIC_INFINITY; + + return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet), + NULL, ifp); +} + +/* Clean up installed RIPng routes. */ +void +ripng_terminate () +{ + struct route_node *rp; + struct ripng_info *rinfo; + + for (rp = route_top (ripng->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + { + if (rinfo->type == ZEBRA_ROUTE_RIPNG && + rinfo->sub_type == RIPNG_ROUTE_RTE) + ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, + &rinfo->nexthop, rinfo->ifindex); + } +} + +int +ripng_update_jitter (int time) +{ + return ((rand () % (time + 1)) - (time / 2)); +} + +void +ripng_event (enum ripng_event event, int sock) +{ + int ripng_request_all (struct thread *); + int jitter = 0; + + switch (event) + { + case RIPNG_READ: + if (!ripng->t_read) + ripng->t_read = thread_add_read (master, ripng_read, NULL, sock); + break; + case RIPNG_UPDATE_EVENT: + if (ripng->t_update) + { + thread_cancel (ripng->t_update); + ripng->t_update = NULL; + } + /* Update timer jitter. */ + jitter = ripng_update_jitter (ripng->update_time); + + ripng->t_update = + thread_add_timer (master, ripng_update, NULL, + sock ? 2 : ripng->update_time + jitter); + break; + case RIPNG_TRIGGERED_UPDATE: + if (ripng->t_triggered_interval) + ripng->trigger = 1; + else if (! ripng->t_triggered_update) + ripng->t_triggered_update = + thread_add_event (master, ripng_triggered_update, NULL, 0); + break; + default: + break; + } +} + +/* Each route type's strings and default preference. */ +struct +{ + int key; + char *str; + char *str_long; + int distance; +} route_info[] = +{ + { ZEBRA_ROUTE_SYSTEM, "X", "system", 10}, + { ZEBRA_ROUTE_KERNEL, "K", "kernel", 20}, + { ZEBRA_ROUTE_CONNECT, "C", "connected", 30}, + { ZEBRA_ROUTE_STATIC, "S", "static", 40}, + { ZEBRA_ROUTE_RIP, "R", "rip", 50}, + { ZEBRA_ROUTE_RIPNG, "R", "ripng", 50}, + { ZEBRA_ROUTE_OSPF, "O", "ospf", 60}, + { ZEBRA_ROUTE_OSPF6, "O", "ospf6", 60}, + { ZEBRA_ROUTE_BGP, "B", "bgp", 70}, +}; + +/* For messages. */ +struct message ripng_route_info[] = +{ + { RIPNG_ROUTE_RTE, " "}, + { RIPNG_ROUTE_STATIC, "S"}, + { RIPNG_ROUTE_AGGREGATE, "a"} +}; + +/* Print out routes update time. */ +static void +ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo) +{ + struct timeval timer_now; + time_t clock; + struct tm *tm; +#define TIME_BUF 25 + char timebuf [TIME_BUF]; + struct thread *thread; + + gettimeofday (&timer_now, NULL); + + if ((thread = rinfo->t_timeout) != NULL) + { + clock = thread->u.sands.tv_sec - timer_now.tv_sec; + tm = gmtime (&clock); + strftime (timebuf, TIME_BUF, "%M:%S", tm); + vty_out (vty, "%5s", timebuf); + } + else if ((thread = rinfo->t_garbage_collect) != NULL) + { + clock = thread->u.sands.tv_sec - timer_now.tv_sec; + tm = gmtime (&clock); + strftime (timebuf, TIME_BUF, "%M:%S", tm); + vty_out (vty, "%5s", timebuf); + } +} + +DEFUN (show_ipv6_ripng, + show_ipv6_ripng_cmd, + "show ipv6 ripng", + SHOW_STR + IP_STR + "Show RIPng routes\n") +{ + struct route_node *rp; + struct ripng_info *rinfo; + struct ripng_aggregate *aggregate; + struct prefix_ipv6 *p; + int len; + + /* Header of display. */ + vty_out (vty, "%sCodes: R - RIPng%s%s" + " Network " + "Next Hop If Met Tag Time%s", VTY_NEWLINE, + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + for (rp = route_top (ripng->table); rp; rp = route_next (rp)) + { + if ((aggregate = rp->aggregate) != NULL) + { + p = (struct prefix_ipv6 *) &rp->p; + +#ifdef DEBUG + len = vty_out (vty, "Ra %d/%d %s/%d ", + aggregate->count, aggregate->suppress, + inet6_ntop (&p->prefix), p->prefixlen); +#else + len = vty_out (vty, "Ra %s/%d ", + inet6_ntop (&p->prefix), p->prefixlen); +#endif /* DEBUG */ + + len = 37 - len; + if (len > 0) + vty_out (vty, "%*s", len, " "); + + vty_out (vty, "%*s", 26, " "); + vty_out (vty, "%4d %3d%s", aggregate->metric, + aggregate->tag, + VTY_NEWLINE); + } + + if ((rinfo = rp->info) != NULL) + { + p = (struct prefix_ipv6 *) &rp->p; + +#ifdef DEBUG + len = vty_out (vty, "%s%s 0/%d %s/%d ", + route_info[rinfo->type].str, + rinfo->suppress ? "s" : " ", + rinfo->suppress, + inet6_ntop (&p->prefix), p->prefixlen); +#else + len = vty_out (vty, "%s%s %s/%d ", + route_info[rinfo->type].str, + rinfo->suppress ? "s" : " ", + inet6_ntop (&p->prefix), p->prefixlen); +#endif /* DEBUG */ + len = 37 - len; + if (len > 0) + vty_out (vty, "%*s", len, " "); + + len = vty_out (vty, "%s", inet6_ntop (&rinfo->nexthop)); + + len = 26 - len; + if (len > 0) + vty_out (vty, "%*s", len, " "); + + vty_out (vty, "%2d %2d %3d ", + rinfo->ifindex, rinfo->metric, rinfo->tag); + + if (rinfo->sub_type == RIPNG_ROUTE_RTE) + ripng_vty_out_uptime (vty, rinfo); + + vty_out (vty, "%s", VTY_NEWLINE); + } + } + + return CMD_SUCCESS; +} + +DEFUN (router_ripng, + router_ripng_cmd, + "router ripng", + "Enable a routing process\n" + "Make RIPng instance command\n") +{ + int ret; + + vty->node = RIPNG_NODE; + + if (!ripng) + { + ret = ripng_create (); + + /* Notice to user we couldn't create RIPng. */ + if (ret < 0) + { + zlog_warn ("can't create RIPng"); + return CMD_WARNING; + } + } + + return CMD_SUCCESS; +} + +DEFUN (ripng_route, + ripng_route_cmd, + "route IPV6ADDR", + "Static route setup\n" + "Set static RIPng route announcement\n") +{ + int ret; + struct prefix_ipv6 p; + struct route_node *rp; + + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p); + if (ret <= 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask_ipv6 (&p); + + rp = route_node_get (ripng->route, (struct prefix *) &p); + if (rp->info) + { + vty_out (vty, "There is already same static route.%s", VTY_NEWLINE); + route_unlock_node (rp); + return CMD_WARNING; + } + rp->info = (void *)1; + + ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0); + + return CMD_SUCCESS; +} + +DEFUN (no_ripng_route, + no_ripng_route_cmd, + "no route IPV6ADDR", + NO_STR + "Static route setup\n" + "Delete static RIPng route announcement\n") +{ + int ret; + struct prefix_ipv6 p; + struct route_node *rp; + + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p); + if (ret <= 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + apply_mask_ipv6 (&p); + + rp = route_node_lookup (ripng->route, (struct prefix *) &p); + if (! rp) + { + vty_out (vty, "Can't find static route.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0); + route_unlock_node (rp); + + rp->info = NULL; + route_unlock_node (rp); + + return CMD_SUCCESS; +} + +DEFUN (ripng_aggregate_address, + ripng_aggregate_address_cmd, + "aggregate-address X:X::X:X/M", + "Set aggregate RIPng route announcement\n" + "Aggregate network\n") +{ + int ret; + struct prefix p; + struct route_node *node; + + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p); + if (ret <= 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check aggregate alredy exist or not. */ + node = route_node_get (ripng->aggregate, &p); + if (node->info) + { + vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE); + route_unlock_node (node); + return CMD_WARNING; + } + node->info = (void *)1; + + ripng_aggregate_add (&p); + + return CMD_SUCCESS; +} + +DEFUN (no_ripng_aggregate_address, + no_ripng_aggregate_address_cmd, + "no aggregate-address X:X::X:X/M", + NO_STR + "Delete aggregate RIPng route announcement\n" + "Aggregate network") +{ + int ret; + struct prefix p; + struct route_node *rn; + + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p); + if (ret <= 0) + { + vty_out (vty, "Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rn = route_node_lookup (ripng->aggregate, &p); + if (! rn) + { + vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE); + return CMD_WARNING; + } + route_unlock_node (rn); + rn->info = NULL; + route_unlock_node (rn); + + ripng_aggregate_delete (&p); + + return CMD_SUCCESS; +} + +DEFUN (ripng_default_metric, + ripng_default_metric_cmd, + "default-metric <1-16>", + "Set a metric of redistribute routes\n" + "Default metric\n") +{ + if (ripng) + { + ripng->default_metric = atoi (argv[0]); + } + return CMD_SUCCESS; +} + +DEFUN (no_ripng_default_metric, + no_ripng_default_metric_cmd, + "no default-metric", + NO_STR + "Set a metric of redistribute routes\n" + "Default metric\n") +{ + if (ripng) + { + ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT; + } + return CMD_SUCCESS; +} + +ALIAS (no_ripng_default_metric, + no_ripng_default_metric_val_cmd, + "no default-metric <1-16>", + NO_STR + "Set a metric of redistribute routes\n" + "Default metric\n"); + +DEFUN (ripng_timers, + ripng_timers_cmd, + "timers basic <0-65535> <0-65535> <0-65535>", + "RIPng timers setup\n" + "Basic timer\n" + "Routing table update timer value in second. Default is 30.\n" + "Routing information timeout timer. Default is 180.\n" + "Garbage collection timer. Default is 120.\n") +{ + unsigned long update; + unsigned long timeout; + unsigned long garbage; + char *endptr = NULL; + + update = strtoul (argv[0], &endptr, 10); + if (update == ULONG_MAX || *endptr != '\0') + { + vty_out (vty, "update timer value error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + timeout = strtoul (argv[1], &endptr, 10); + if (timeout == ULONG_MAX || *endptr != '\0') + { + vty_out (vty, "timeout timer value error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + garbage = strtoul (argv[2], &endptr, 10); + if (garbage == ULONG_MAX || *endptr != '\0') + { + vty_out (vty, "garbage timer value error%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Set each timer value. */ + ripng->update_time = update; + ripng->timeout_time = timeout; + ripng->garbage_time = garbage; + + /* Reset update timer thread. */ + ripng_event (RIPNG_UPDATE_EVENT, 0); + + return CMD_SUCCESS; +} + +DEFUN (no_ripng_timers, + no_ripng_timers_cmd, + "no timers basic", + NO_STR + "RIPng timers setup\n" + "Basic timer\n") +{ + /* Set each timer value to the default. */ + ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT; + ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT; + ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT; + + /* Reset update timer thread. */ + ripng_event (RIPNG_UPDATE_EVENT, 0); + + return CMD_SUCCESS; +} + + +DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd, + "show ipv6 protocols", + SHOW_STR + IP_STR + "Routing protocol information") +{ + if (! ripng) + return CMD_SUCCESS; + + vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE); + + vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s", + ripng->update_time, 0, + VTY_NEWLINE); + + vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s", + ripng->timeout_time, + ripng->garbage_time, + VTY_NEWLINE); + + vty_out (vty, "Outgoing update filter list for all interfaces is not set"); + vty_out (vty, "Incoming update filter list for all interfaces is not set"); + + return CMD_SUCCESS; +} + +/* Please be carefull to use this command. */ +DEFUN (ripng_default_information_originate, + ripng_default_information_originate_cmd, + "default-information originate", + "Default route information\n" + "Distribute default route\n") +{ + struct prefix_ipv6 p; + + ripng->default_information = 1; + + str2prefix_ipv6 ("::/0", &p); + ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0); + + return CMD_SUCCESS; +} + +DEFUN (no_ripng_default_information_originate, + no_ripng_default_information_originate_cmd, + "no default-information originate", + NO_STR + "Default route information\n" + "Distribute default route\n") +{ + struct prefix_ipv6 p; + + ripng->default_information = 0; + + str2prefix_ipv6 ("::/0", &p); + ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0); + + return CMD_SUCCESS; +} + +/* RIPng configuration write function. */ +int +ripng_config_write (struct vty *vty) +{ + int ripng_network_write (struct vty *); + void ripng_redistribute_write (struct vty *); + int write = 0; + struct route_node *rp; + + if (ripng) + { + + /* RIPng router. */ + vty_out (vty, "router ripng%s", VTY_NEWLINE); + + if (ripng->default_information) + vty_out (vty, " default-information originate%s", VTY_NEWLINE); + + ripng_network_write (vty); + + /* RIPng default metric configuration */ + if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT) + vty_out (vty, " default-metric %d%s", + ripng->default_metric, VTY_NEWLINE); + + ripng_redistribute_write (vty); + + /* RIPng aggregate routes. */ + for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp)) + if (rp->info != NULL) + vty_out (vty, " aggregate-address %s/%d%s", + inet6_ntop (&rp->p.u.prefix6), + rp->p.prefixlen, + + VTY_NEWLINE); + + /* RIPng static routes. */ + for (rp = route_top (ripng->route); rp; rp = route_next (rp)) + if (rp->info != NULL) + vty_out (vty, " route %s/%d%s", inet6_ntop (&rp->p.u.prefix6), + rp->p.prefixlen, + VTY_NEWLINE); + + /* RIPng timers configuration. */ + if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT || + ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT || + ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT) + { + vty_out (vty, " timers basic %ld %ld %ld%s", + ripng->update_time, + ripng->timeout_time, + ripng->garbage_time, + VTY_NEWLINE); + } + + write += config_write_distribute (vty); + + write += config_write_if_rmap (vty); + + write++; + } + return write; +} + +/* RIPng node structure. */ +struct cmd_node cmd_ripng_node = +{ + RIPNG_NODE, + "%s(config-router)# ", + 1, +}; + +void +ripng_distribute_update (struct distribute *dist) +{ + struct interface *ifp; + struct ripng_interface *ri; + struct access_list *alist; + struct prefix_list *plist; + + if (! dist->ifname) + return; + + ifp = if_lookup_by_name (dist->ifname); + if (ifp == NULL) + return; + + ri = ifp->info; + + if (dist->list[DISTRIBUTE_IN]) + { + alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]); + if (alist) + ri->list[RIPNG_FILTER_IN] = alist; + else + ri->list[RIPNG_FILTER_IN] = NULL; + } + else + ri->list[RIPNG_FILTER_IN] = NULL; + + if (dist->list[DISTRIBUTE_OUT]) + { + alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]); + if (alist) + ri->list[RIPNG_FILTER_OUT] = alist; + else + ri->list[RIPNG_FILTER_OUT] = NULL; + } + else + ri->list[RIPNG_FILTER_OUT] = NULL; + + if (dist->prefix[DISTRIBUTE_IN]) + { + plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]); + if (plist) + ri->prefix[RIPNG_FILTER_IN] = plist; + else + ri->prefix[RIPNG_FILTER_IN] = NULL; + } + else + ri->prefix[RIPNG_FILTER_IN] = NULL; + + if (dist->prefix[DISTRIBUTE_OUT]) + { + plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]); + if (plist) + ri->prefix[RIPNG_FILTER_OUT] = plist; + else + ri->prefix[RIPNG_FILTER_OUT] = NULL; + } + else + ri->prefix[RIPNG_FILTER_OUT] = NULL; +} +void +ripng_distribute_update_interface (struct interface *ifp) +{ + struct distribute *dist; + + dist = distribute_lookup (ifp->name); + if (dist) + ripng_distribute_update (dist); +} + +/* Update all interface's distribute list. */ +void +ripng_distribute_update_all () +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ripng_distribute_update_interface (ifp); + } +} + +void +ripng_if_rmap_update (struct if_rmap *if_rmap) +{ + struct interface *ifp; + struct ripng_interface *ri; + struct route_map *rmap; + + ifp = if_lookup_by_name (if_rmap->ifname); + if (ifp == NULL) + return; + + ri = ifp->info; + + if (if_rmap->routemap[IF_RMAP_IN]) + { + rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]); + if (rmap) + ri->routemap[IF_RMAP_IN] = rmap; + else + ri->routemap[IF_RMAP_IN] = NULL; + } + else + ri->routemap[RIPNG_FILTER_IN] = NULL; + + if (if_rmap->routemap[IF_RMAP_OUT]) + { + rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]); + if (rmap) + ri->routemap[IF_RMAP_OUT] = rmap; + else + ri->routemap[IF_RMAP_OUT] = NULL; + } + else + ri->routemap[RIPNG_FILTER_OUT] = NULL; +} + +void +ripng_if_rmap_update_interface (struct interface *ifp) +{ + struct if_rmap *if_rmap; + + if_rmap = if_rmap_lookup (ifp->name); + if (if_rmap) + ripng_if_rmap_update (if_rmap); +} + +void +ripng_routemap_update_redistribute (void) +{ + int i; + + if (ripng) + { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (ripng->route_map[i].name) + ripng->route_map[i].map = + route_map_lookup_by_name (ripng->route_map[i].name); + } + } +} + +void +ripng_routemap_update () +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ripng_if_rmap_update_interface (ifp); + } + + ripng_routemap_update_redistribute (); +} + +/* Initialize ripng structure and set commands. */ +void +ripng_init () +{ + /* Randomize. */ + srand (time (NULL)); + + /* Install RIPNG_NODE. */ + install_node (&cmd_ripng_node, ripng_config_write); + + /* Install ripng commands. */ + install_element (VIEW_NODE, &show_ipv6_ripng_cmd); + + install_element (ENABLE_NODE, &show_ipv6_ripng_cmd); + + install_element (CONFIG_NODE, &router_ripng_cmd); + + install_default (RIPNG_NODE); + install_element (RIPNG_NODE, &ripng_route_cmd); + install_element (RIPNG_NODE, &no_ripng_route_cmd); + install_element (RIPNG_NODE, &ripng_aggregate_address_cmd); + install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd); + + install_element (RIPNG_NODE, &ripng_default_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_default_metric_cmd); + install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd); + + install_element (RIPNG_NODE, &ripng_timers_cmd); + install_element (RIPNG_NODE, &no_ripng_timers_cmd); + + install_element (RIPNG_NODE, &ripng_default_information_originate_cmd); + install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd); + + ripng_if_init (); + ripng_debug_init (); + + /* Access list install. */ + access_list_init (); + access_list_add_hook (ripng_distribute_update_all); + access_list_delete_hook (ripng_distribute_update_all); + + /* Prefix list initialize.*/ + prefix_list_init (); + prefix_list_add_hook (ripng_distribute_update_all); + prefix_list_delete_hook (ripng_distribute_update_all); + + /* Distribute list install. */ + distribute_list_init (RIPNG_NODE); + distribute_list_add_hook (ripng_distribute_update); + distribute_list_delete_hook (ripng_distribute_update); + + /* Route-map for interface. */ + ripng_route_map_init (); + route_map_add_hook (ripng_routemap_update); + route_map_delete_hook (ripng_routemap_update); + + if_rmap_init (); + if_rmap_hook_add (ripng_if_rmap_update); + if_rmap_hook_delete (ripng_if_rmap_update); +} diff --git a/ripngd/ripngd.conf.sample b/ripngd/ripngd.conf.sample new file mode 100644 index 0000000..00c4b46 --- /dev/null +++ b/ripngd/ripngd.conf.sample @@ -0,0 +1,22 @@ +! -*- rip -*- +! +! RIPngd sample configuration file +! +! $Id: ripngd.conf.sample,v 1.12 1999/02/19 17:35:39 developer Exp $ +! +hostname ripngd +password zebra +! +! debug ripng events +! debug ripng packet +! +! +router ripng +! network sit1 +! route 3ffe:506::0/32 +! distribute-list local-only out sit1 +! +!ipv6 access-list local-only permit 3ffe:506::0/32 +!ipv6 access-list local-only deny any +! +log stdout diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h new file mode 100644 index 0000000..2509bdd --- /dev/null +++ b/ripngd/ripngd.h @@ -0,0 +1,318 @@ +/* + * RIPng related value and structure. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RIPNG_RIPNGD_H +#define _ZEBRA_RIPNG_RIPNGD_H + +/* RIPng version and port number. */ +#define RIPNG_V1 1 +#define RIPNG_PORT_DEFAULT 521 +#define RIPNG_VTY_PORT 2603 +#define RIPNG_VTYSH_PATH "/tmp/.ripngd" +#define RIPNG_MAX_PACKET_SIZE 1500 +#define RIPNG_PRIORITY_DEFAULT 0 + +/* RIPng commands. */ +#define RIPNG_REQUEST 1 +#define RIPNG_RESPONSE 2 + +/* RIPng metric and multicast group address. */ +#define RIPNG_METRIC_INFINITY 16 +#define RIPNG_METRIC_NEXTHOP 0xff +#define RIPNG_GROUP "ff02::9" + +/* RIPng timers. */ +#define RIPNG_UPDATE_TIMER_DEFAULT 30 +#define RIPNG_TIMEOUT_TIMER_DEFAULT 180 +#define RIPNG_GARBAGE_TIMER_DEFAULT 120 + +/* Default config file name. */ +#define RIPNG_DEFAULT_CONFIG "ripngd.conf" + +/* RIPng route types. */ +#define RIPNG_ROUTE_RTE 0 +#define RIPNG_ROUTE_STATIC 1 +#define RIPNG_ROUTE_AGGREGATE 2 + +/* Interface send/receive configuration. */ +#define RIPNG_SEND_UNSPEC 0 +#define RIPNG_SEND_OFF 1 +#define RIPNG_RECEIVE_UNSPEC 0 +#define RIPNG_RECEIVE_OFF 1 + +/* Split horizon definitions. */ +#define RIPNG_SPLIT_HORIZON_UNSPEC 0 +#define RIPNG_SPLIT_HORIZON_NONE 1 +#define RIPNG_SPLIT_HORIZON 2 +#define RIPNG_SPLIT_HORIZON_POISONED 3 + +/* RIP default route's accept/announce methods. */ +#define RIPNG_DEFAULT_ADVERTISE_UNSPEC 0 +#define RIPNG_DEFAULT_ADVERTISE_NONE 1 +#define RIPNG_DEFAULT_ADVERTISE 2 + +#define RIPNG_DEFAULT_ACCEPT_UNSPEC 0 +#define RIPNG_DEFAULT_ACCEPT_NONE 1 +#define RIPNG_DEFAULT_ACCEPT 2 + +/* Default value for "default-metric" command. */ +#define RIPNG_DEFAULT_METRIC_DEFAULT 1 + +/* For max RTE calculation. */ +#ifndef IPV6_HDRLEN +#define IPV6_HDRLEN 40 +#endif /* IPV6_HDRLEN */ + +#ifndef IFMINMTU +#define IFMINMTU 576 +#endif /* IFMINMTU */ + +/* RIPng structure. */ +struct ripng +{ + /* RIPng socket. */ + int sock; + + /* RIPng Parameters.*/ + u_char command; + u_char version; + unsigned long update_time; + unsigned long timeout_time; + unsigned long garbage_time; + int max_mtu; + int default_metric; + int default_information; + + /* Input/output buffer of RIPng. */ + struct stream *ibuf; + struct stream *obuf; + + /* RIPng routing information base. */ + struct route_table *table; + + /* RIPng only static route information. */ + struct route_table *route; + + /* RIPng aggregate route information. */ + struct route_table *aggregate; + + /* RIPng threads. */ + struct thread *t_read; + struct thread *t_write; + struct thread *t_update; + struct thread *t_garbage; + struct thread *t_zebra; + + /* Triggered update hack. */ + int trigger; + struct thread *t_triggered_update; + struct thread *t_triggered_interval; + + /* For redistribute route map. */ + struct + { + char *name; + struct route_map *map; + int metric_config; + u_int32_t metric; + } route_map[ZEBRA_ROUTE_MAX]; +}; + +/* Routing table entry. */ +struct rte +{ + struct in6_addr addr; + u_short tag; + u_char prefixlen; + u_char metric; +}; + +/* RIPNG send packet. */ +struct ripng_packet +{ + u_char command; + u_char version; + u_int16_t zero; + struct rte rte[1]; +}; + +/* Each route's information. */ +struct ripng_info +{ + /* This route's type. Static, ripng or aggregate. */ + u_char type; + + /* Sub type for static route. */ + u_char sub_type; + + /* RIPng specific information */ + struct in6_addr nexthop; + struct in6_addr from; + + /* Which interface does this route come from. */ + unsigned int ifindex; + + /* Metric of this route. */ + u_char metric; + + /* Tag field of RIPng packet.*/ + u_int16_t tag; + + /* For aggregation. */ + unsigned int suppress; + + /* Flags of RIPng route. */ +#define RIPNG_RTF_FIB 1 +#define RIPNG_RTF_CHANGED 2 + u_char flags; + + /* Garbage collect timer. */ + struct thread *t_timeout; + struct thread *t_garbage_collect; + + /* Route-map features - this variables can be changed. */ + u_char metric_set; + + struct route_node *rp; +}; + +/* RIPng tag structure. */ +struct ripng_tag +{ + /* Tag value. */ + u_int16_t tag; + + /* Port. */ + u_int16_t port; + + /* Multicast group. */ + struct in6_addr maddr; + + /* Table number. */ + int table; + + /* Distance. */ + int distance; + + /* Split horizon. */ + u_char split_horizon; + + /* Poison reverse. */ + u_char poison_reverse; +}; + +/* RIPng specific interface configuration. */ +struct ripng_interface +{ + /* RIPng is enabled on this interface. */ + int enable_network; + int enable_interface; + + /* RIPng is running on this interface. */ + int running; + + /* For filter type slot. */ +#define RIPNG_FILTER_IN 0 +#define RIPNG_FILTER_OUT 1 +#define RIPNG_FILTER_MAX 2 + + /* Access-list. */ + struct access_list *list[RIPNG_FILTER_MAX]; + + /* Prefix-list. */ + struct prefix_list *prefix[RIPNG_FILTER_MAX]; + + /* Route-map. */ + struct route_map *routemap[RIPNG_FILTER_MAX]; + + /* RIPng tag configuration. */ + struct ripng_tag *rtag; + + /* Default information originate. */ + u_char default_originate; + + /* Default information only. */ + u_char default_only; + + /* Wake up thread. */ + struct thread *t_wakeup; + + /* Passive interface. */ + int passive; +}; + +/* All RIPng events. */ +enum ripng_event +{ + RIPNG_READ, + RIPNG_ZEBRA, + RIPNG_REQUEST_EVENT, + RIPNG_UPDATE_EVENT, + RIPNG_TRIGGERED_UPDATE, +}; + +/* RIPng timer on/off macro. */ +#define RIPNG_TIMER_ON(T,F,V) \ +do { \ + if (!(T)) \ + (T) = thread_add_timer (master, (F), rinfo, (V)); \ +} while (0) + +#define RIPNG_TIMER_OFF(T) \ +do { \ + if (T) \ + { \ + thread_cancel(T); \ + (T) = NULL; \ + } \ +} while (0) + +/* Count prefix size from mask length */ +#define PSIZE(a) (((a) + 7) / (8)) + +/* Extern variables. */ +extern struct ripng *ripng; + +extern struct thread_master *master; + +/* Prototypes. */ +void ripng_init (); +void ripng_if_init (); +void ripng_terminate (); +void ripng_zclient_start (); +void zebra_init (); +struct ripng_info * ripng_info_new (); +void ripng_info_free (struct ripng_info *rinfo); +void ripng_event (enum ripng_event, int); +int ripng_request (struct interface *ifp); +void ripng_redistribute_add (int, int, struct prefix_ipv6 *, unsigned int); +void ripng_redistribute_delete (int, int, struct prefix_ipv6 *, unsigned int); +void ripng_redistribute_withdraw (int type); + +void ripng_distribute_update_interface (struct interface *); +void ripng_if_rmap_update_interface (struct interface *); + +void ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex); +void ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex); +void ripng_route_map_init (); + +#endif /* _ZEBRA_RIPNG_RIPNGD_H */ diff --git a/tools/mrlg.cgi b/tools/mrlg.cgi new file mode 100755 index 0000000..ac468ee --- /dev/null +++ b/tools/mrlg.cgi @@ -0,0 +1,395 @@ +#!/usr/bin/perl +## +## Zebra Looking Glass version 1.0 +## 01 FEB 2000 +## Copyright (C) 2000 John W. Fraizer III +## *All* copyright notices must remain in place to use this code. +## +## The latest version of this code is available at: +## ftp://ftp.enterzone.net/looking-glass/ +## +## +## This file is part of GNU Zebra. +## +## GNU Zebra 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, or (at your option) any +## later version. +## +## GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the +## Free Software Foundation, Inc., 59 Temple Place - Suite 330, +## Boston, MA 02111-1307, USA. + +require 5.002; +use POSIX; +use Net::Telnet (); + + + +## Set the URL for your site. +$url="http://www.sample.com/mrlg.cgi"; + +## Set your router variables in sub set_router and modify the selections in Main to match. + + +############################################################ +#Main +############################################################ +{ + +## Set the router default +@Form{'router'} = "router1"; + +## Get the form results now so we can override the default router +get_form(); + +print "Content-type: text/html\n\n"; + +print ' + + +Multi-Router Looking Glass for Zebra + + + + +

Multi-Router Looking Glass for Zebra

+Copyright 2000 - John Fraizer, EnterZone Inc. +
+'; + +print ' + +'; +print "
\n"; +print "Router: +

+Query: +
+show ip bgp
+show ip bgp summary
+show ip route
+show interface
+show ipv6 bgp
+show ipv6 bgp summary
+show ipv6 route
+
+Argument: +
+'; + +## Set up the address, pw and ports, etc for the selected router. +set_router(); + +## Set up which command is to be executed (and then execute it!) +set_command(); + + +print ' +

+
+ +Multi-Router Looking Glass for Zebra version 1.0
+Written by: John Fraizer - +EnterZone, Inc
+Source code: ftp://ftp.enterzone.net/looking-glass/ + + +'; + +## All done! + +exit (0); +} + + +############################################################ +sub get_form +############################################################ +{ + + #read STDIN + read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); + + # Split the name-value pairs + @pairs = split(/&/, $buffer); + + # For each name-value pair: + foreach $pair (@pairs) + { + + # Split the pair up into individual variables. + local($name, $value) = split(/=/, $pair); + + # Decode the form encoding on the name and value variables. + $name =~ tr/+/ /; + $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; + + $value =~ tr/+/ /; + $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; + + # If they try to include server side includes, erase them, so they + # aren't a security risk if the html gets returned. Another + # security hole plugged up. + $value =~ s///g; + + @Form{$name} = $value ; + + } + +} + +############################################################ +sub set_router +############################################################ + +## $server is the IP address of the router running zebra +## $login_pass is the password of the router +## $bgpd is the port that bgpd will answer on +## $zebra is the port that zebra will answer on +## if $zebra is "", it will disable sh ip route and sh int for that router. +## if $full_tables is set to "1" for a router, full BGP and IP ROUTE table dumps will be allowed via the looking glass. +## This is a BAD thing to do if you have multiple full views on a router. That's why the option is there. + +{ +if ($Form{'router'} eq 'router1') + { +$server = '10.1.1.1'; +$login_pass = 'zebra'; +$bgpd = "2605"; +$zebra = ""; +$full_tables=1; + + } + +elsif ($Form{'router'} eq 'router2') + { +$server = '10.1.1.2'; +$login_pass = 'zebra'; +$bgpd = "2605"; +$zebra = "2601"; + } + +elsif ($Form{'router'} eq 'router3') + { +$server = '10.1.1.3'; +$login_pass = 'zebra'; +$bgpd = "2605"; +$zebra = "2601"; +$full_tables=1; + } + +elsif ($Form{'router'} eq 'router4') + { +$server = '10.1.1.4'; +$login_pass = 'zebra'; +$bgpd = "2605"; +$zebra = "2601"; + } + + +} + + +############################################################ +sub set_command +############################################################ +{ +if ($Form{'query'} eq '1') + { + sh_ip_bgp('ip'); + } + +elsif ($Form{'query'} eq '2') + { + sh_ip_bgp_sum('ip'); + } + +if ($Form{'query'} eq '3') + { + sh_ip_route('ip'); + } + +if ($Form{'query'} eq '4') + { + sh_int(); + } +if ($Form{'query'} eq '5') + { + sh_ip_bgp('ipv6'); + } +if ($Form{'query'} eq '6') + { + sh_ip_bgp_sum('ipv6'); + } +if ($Form{'query'} eq '7') + { + sh_ip_route('ipv6'); + } +} +############################################################ +sub sh_ip_bgp +############################################################ +{ +my $protocol = shift(@_); +$port = $bgpd; +if ($protocol ne 'ip' && $protocol ne 'ipv6') + { + print "Invalid protocol: $protocol\n"; + print "protocol must be 'ip' or 'ipv6'\n\n"; + return; + } +$command = "show $protocol bgp $Form{'arg'}"; +if ($Form{'arg'} eq '') + { + if ($full_tables eq '1') + { + execute_command(); + } + else + { + print "Sorry. Displaying the FULL routing table would put too much load on the router!\n\n"; + } + } +else + { + execute_command(); + } +} + +############################################################ +sub sh_ip_bgp_sum +############################################################ +{ + my $protocol = shift(@_); + $port = $bgpd; + if ($protocol ne 'ip' && $protocol ne 'ipv6') + { + print "Invalid protocol: $protocol\n"; + print "protocol must be 'ip' or 'ipv6'\n\n"; + return; + } + $command = "show $protocol bgp summary"; + execute_command(); +} + +############################################################ +sub sh_ip_route +############################################################ +{ + +if ($zebra eq '') + { + print "Sorry. The show ip route command is disabled for this router." + } +else + { + + $port = $zebra; + my $protocol = shift(@_); + if ($protocol ne 'ip' && $protocol ne 'ipv6') + { + print "Invalid protocol: $protocol\n"; + print "protocol must be 'ip' or 'ipv6'\n\n"; + return; + } + $command = "show $protocol route $Form{'arg'}"; + if ($Form{'arg'} eq '') + { + if ($full_tables eq '1') + { + execute_command(); + } + else + { + print "Sorry. Displaying the FULL routing table would put too much load on the router!\n\n"; + } + } + else + { + execute_command(); + } + } +} + +############################################################ +sub sh_int +############################################################ +{ +if ($zebra eq '') + { + print "Sorry. The show interface command is disabled for this router." + } +else + { + $port = $zebra; + $command = "show interface $Form{'arg'}"; + execute_command(); + } +} + + + +############################################################ +sub execute_command +############################################################ +## This code is based on: +## +## Zebra interactive console +## Copyright (C) 2000 Vladimir B. Grebenschikov +## + + +{ + +print "Executing command = $command"; + +# my $port = ($opt_z ? 'zebra' : 0) || +# ($opt_b ? 'bgpd' : 0) || +# ($opt_o ? 'ospfd' : 0) || +# ($opt_r ? 'ripd' : 0) || 'bgpd'; + +my $cmd = $command; + + + my $t = new Net::Telnet (Timeout => 10, + Prompt => '/[\>\#] $/', + Port => $port); + + $t->open ($server); + + $t->cmd ($login_pass); + + if ($cmd) + { + docmd ($t, $cmd); + } + +} + +############################################################ +sub docmd +############################################################ +{ + my ($t, $cmd) = @_; + my @lines = $t->cmd ($cmd); + print "
\n";
+  print join ('', grep (!/[\>\#] $/, @lines)), "\n";
+  print "
"; +} + + + diff --git a/tools/rrcheck.pl b/tools/rrcheck.pl new file mode 100644 index 0000000..5e5a983 --- /dev/null +++ b/tools/rrcheck.pl @@ -0,0 +1,135 @@ +#! /bin/perl +## +## Read BGPd logfile and lookup RR's whois database. +## +## Copyright (c) 1997 Kunihiro Ishiguro +## +use Socket; + +## Configuration variables +$whois_host = "whois.jpix.ad.jp"; + +#$logfile = "/usr/local/sbin/logfile" +$logfile = shift || die "Please specify filename"; + +## mail routine +{ + local ($prefix, $origin); + + open (LOG, $logfile) || die "can't open $logfile"; + + $index = ''; + while ($index) { + $index = ; + if ($index =~ /[bgpd]/) { + break; + } + } + + while () { + if (/([\d\.\/]+)\s+([\d\.]+)\s+(\d+)\s+(\d+)\s+([\d ]+)\s+[ie\?]/) { + $prefix = $1; + $nexthop = $2; + $med = $3; + $dummy = $4; + $aspath = $5; + ($origin) = ($aspath =~ /([\d]+)$/); + + print "$nexthop [$origin] $prefix $aspath "; + + $ret = &whois_check ($prefix, $origin); + if ($ret == 0) { + print "Check OK\n"; + } elsif ($ret == 1){ + print "AS orgin mismatch\n"; + } else { + print "prefix doesn't exist \n"; + } + } + } +} + +sub whois_check +{ + local ($prefix, $origin) = @_; + local ($rr_prefix, $rr_origin) = (); + local (@result); + + $origin = "AS" . $origin; + + @result = &whois ($prefix); + + $prefix_match = 0; + foreach (@result) { + if (/^route:.*\s([\d\.\/]+)$/) { + $rr_prefix = $1; + } + if (/^origin:.*\s(AS[\d]+)$/) { + $rr_origin = $1; + + if ($prefix eq $rr_prefix and $origin eq $rr_origin) { + return 0; + } elsif ($prefix eq $rr_prefix) { + $prefix_match = 1; + } + } + } +# alarm_mail ($prefix, $origin, @result); + if ($prefix_match) { + return 1; + } else { + return 2; + } +} + +## get port of whois +sub get_whois_port +{ + local ($name, $aliases, $port, $proto) = getservbyname ("whois", "tcp"); + return ($port, $proto); +} + +## whois lookup +sub whois +{ + local ($query) = @_; + local ($port, $proto) = &get_whois_port; + local (@result); + + if ($whois_host=~ /^\s*\d+\.\d+\.\d+\.\d+\s*$/) { + $address = pack ("C4",split(/\./,$host)); + } else { + $address = (gethostbyname ($whois_host))[4]; + } + + socket (SOCKET, PF_INET, SOCK_STREAM, $proto); + + if (connect (SOCKET, sockaddr_in ($port, $address))) { + local ($oldhandle) = select (SOCKET); + $| = 1; + select($oldhandle); + + print SOCKET "$query\r\n"; + + @result = ; + return @result; + } +} + +## +sub alarm_mail +{ + local ($prefix, $origin, @result) = @_; + + open (MAIL, "|$mailer -t $mail_address") || die "can't open $mailer"; + + print MAIL "From: root\@rr1.jpix.ad.jp\n"; + print MAIL "Subject: RR $origin $prefix\n"; + print MAIL "MIME-Version: 1.0\n"; + print MAIL "Content-Type: text/plain; charset=us-ascii \n\n"; + print MAIL "RR Lookup Error Report\n"; + print MAIL "======================\n"; + print MAIL "Announced route : $prefix from $origin\n\n"; + print MAIL "@result"; + close MAIL; +} diff --git a/tools/rrlookup.pl b/tools/rrlookup.pl new file mode 100644 index 0000000..2c14e73 --- /dev/null +++ b/tools/rrlookup.pl @@ -0,0 +1,123 @@ +#! /usr/local/bin/perl +## +## Read BGPd logfile and lookup RR's whois database. +## +## Copyright (c) 1997 Kunihiro Ishiguro +## +use Socket; + +## Configuration variables +$whois_host = "whois.jpix.ad.jp"; + +#$mail_address = "toshio\@iri.co.jp"; +$mail_address = "kunihiro\@zebra.org"; +$mailer = "/usr/sbin/sendmail -oi"; + +#$logfile = "/usr/local/sbin/logfile" +$logfile = "logfile"; +$lookuplog = "lookuplog"; + +## mail routine +{ + local ($prefix, $origin); + + open (LOG, $logfile) || die "can't open $logfile"; + open (LOOKUP, ">$lookuplog") || die "can't open $lookuplog"; + + for (;;) { + while () { + if (/Update\S+ ([\d\.\/]+) .* (\d+) [ie\?]/) { + $prefix = $1; + $origin = $2; + $ret = &whois_check ($prefix, $origin); + if ($ret) { + print LOOKUP "$prefix AS$origin : Check OK\n"; + } else { + print LOOKUP "$prefix AS$origin : Error\n"; + } +# fflush (LOOKUP); + } + } + sleep (3); + } +} + +sub whois_check +{ + local ($prefix, $origin) = @_; + local ($rr_prefix, $rr_origin) = (); + local (@result); + + $origin = "AS" . $origin; + +# print "$prefix $origin\n"; + + @result = &whois ($prefix); + + foreach (@result) { + if (/^route:.*\s([\d\.\/]+)$/) { + $rr_prefix = $1; + } + if (/^origin:.*\s(AS[\d]+)$/) { + $rr_origin = $1; + + if ($prefix eq $rr_prefix and $origin eq $rr_origin) { + return 1; + } + } + } + alarm_mail ($prefix, $origin, @result); + return 0; +} + +## get port of whois +sub get_whois_port +{ + local ($name, $aliases, $port, $proto) = getservbyname ("whois", "tcp"); + return ($port, $proto); +} + +## whois lookup +sub whois +{ + local ($query) = @_; + local ($port, $proto) = &get_whois_port; + local (@result); + + if ($whois_host=~ /^\s*\d+\.\d+\.\d+\.\d+\s*$/) { + $address = pack ("C4",split(/\./,$host)); + } else { + $address = (gethostbyname ($whois_host))[4]; + } + + socket (SOCKET, PF_INET, SOCK_STREAM, $proto); + + if (connect (SOCKET, sockaddr_in ($port, $address))) { + local ($oldhandle) = select (SOCKET); + $| = 1; + select($oldhandle); + + print SOCKET "$query\r\n"; + + @result = ; + return @result; + } +} + +## +sub alarm_mail +{ + local ($prefix, $origin, @result) = @_; + + open (MAIL, "|$mailer -t $mail_address") || die "can't open $mailer"; + + print MAIL "From: root\@rr1.jpix.ad.jp\n"; + print MAIL "Subject: RR $origin $prefix\n"; + print MAIL "MIME-Version: 1.0\n"; + print MAIL "Content-Type: text/plain; charset=us-ascii \n\n"; + print MAIL "RR Lookup Error Report\n"; + print MAIL "======================\n"; + print MAIL "Announced route : $prefix from $origin\n\n"; + print MAIL "@result"; + close MAIL; +} diff --git a/tools/zc.pl b/tools/zc.pl new file mode 100755 index 0000000..026e8fe --- /dev/null +++ b/tools/zc.pl @@ -0,0 +1,111 @@ +#! /usr/bin/perl +## +## Zebra interactive console +## Copyright (C) 2000 Vladimir B. Grebenschikov +## +## This file is part of GNU Zebra. +## +## GNU Zebra 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, or (at your option) any +## later version. +## +## GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the +## Free Software Foundation, Inc., 59 Temple Place - Suite 330, +## Boston, MA 02111-1307, USA. + +use Net::Telnet (); +use Getopt::Std; + +#use strict; + +my $host = `hostname -s`; $host =~ s/\s//g; +my $port = 'zebra'; +my $server = 'localhost'; + +# Check arguments +&getopts ('l:e:czborh'); + +&usage () if $opt_h; + +# main +{ + my $login_pass = $opt_l || $ENV{ZEBRA_PASSWORD} || 'zebra'; + my $enable_pass = $opt_e || $ENV{ZEBRA_ENABLE} || ''; + + my $port = ($opt_z ? 'zebra' : 0) || + ($opt_b ? 'bgpd' : 0) || + ($opt_o ? 'ospfd' : 0) || + ($opt_r ? 'ripd' : 0) || 'zebra'; + + my $cmd = join (' ', @ARGV); + + my $t = new Net::Telnet (Timeout => 10, + Prompt => '/[\>\#] $/', + Port => $port); + + $t->open ($server); + + $t->cmd ($login_pass); + if ($enable_pass) { + $t->cmd (String => 'en', + Prompt => '/Password: /'); + $t->cmd ($enable_pass); + } + $t->cmd ('conf t') if "$opt_c"; + + if ($cmd) + { + docmd ($t, $cmd); + exit (0); + } + + my $prompt = sprintf ("%s%s# ", $host, + ($port eq 'zebra') ? '' : "/$port"); + + print "\nZEBRA interactive console ($port)\n\n" if -t STDIN; + + while (1) + { + $| = 1; + print $prompt if -t STDIN; + chomp ($cmd = <>); + if (!defined ($cmd)) + { + print "\n" if -t STDIN; + exit(0); + } + exit (0) if ($cmd eq 'q' || $cmd eq 'quit'); + + docmd ($t, $cmd) if $cmd !~ /^\s*$/; + } + + exit(0); +} + +sub docmd +{ + my ($t, $cmd) = @_; + my @lines = $t->cmd ($cmd); + print join ('', grep (!/[\>\#] $/, @lines)), "\n"; +} + +sub usage +{ + print "USAGE: $0 [-l LOGIN_PASSWORD] [-e ENABLE_PASSWORD] [-z|-b|-o|-r|-h] []\n", + "\t-l - specify login password\n", + "\t-e - specify enable password\n", + "\t-c - execute command in configure mode\n", + "\t-z - connect to zebra daemon\n", + "\t-b - connect to bgpd daemon\n", + "\t-o - connect to ospfd daemon\n", + "\t-r - connect to ripd daemon\n", + "\t-h - help\n"; + exit (1); +} diff --git a/tools/zebra.el b/tools/zebra.el new file mode 100644 index 0000000..01ff09f --- /dev/null +++ b/tools/zebra.el @@ -0,0 +1,108 @@ +;; -*- lisp -*- +;;; zebra-mode.el -- major mode for editing zebra configuration file. + +;; Copyright (C) 1998 Kunihiro Ishiguro + +;; Author: 1998 Kunihiro Ishiguro +;; SeonMeyong HEO +;; Maintainer: kunihiro@zebra.org +;; seirios@Matrix.IRI.Co.JP +;; Created: Jan 28 1998 +;; Version: Alpha 0.2 +;; Keywords: zebra bgpd ripd ripngd languages + +;; You can get the latest version of zebra from +;; +;; http://www.zebra.org/ +;; +;; Install this Emacs Lisp code +;; +;; Compile zebra.el +;; % $(EMACS) -batch -f batch-byte-compile zebra.el +;; Install zebra.el,zebra.elc to Emacs-load-path +;; % cp zebra.el zebra.elc $(emacs-load-path) +;; Add .emacs or (site-load.el | site-start.el) +;; (auto-load 'zebra-mode "zebra" nil t) +;; (auto-load 'bgp-mode "zebra" nil t) +;; (auto-load 'rip-mode "zebra" nil t) +;; + +;;; Code: + +;; Set keywords + +(defvar zebra-font-lock-keywords + (list + '("#.*$" . font-lock-comment-face) + '("!.*$" . font-lock-comment-face) + '("no\\|interface" . font-lock-type-face) + '("ip6\\|ip\\|route\\|address" . font-lock-function-name-face) + '("ipforward\\|ipv6forward" . font-lock-keyword-face) + '("hostname\\|password\\|enable\\|logfile\\|no" . font-lock-keyword-face)) + "Default value to highlight in zebra mode.") + +(defvar bgp-font-lock-keywords + (list + '("#.*$" . font-lock-comment-face) + '("!.*$" . font-lock-comment-face) + '("no\\|router" . font-lock-type-face) + '("bgp\\|router-id\\|neighbor\\|network" . font-lock-function-name-face) + '("ebgp\\|multihop\\|next\\|zebra\\|remote-as" . font-lock-keyword-face) + '("hostname\\|password\\|enable\\|logfile\\|no" . font-lock-keyword-face)) + "Default value to highlight in bgp mode.") + +(defvar rip-font-lock-keywords + (list + '("#.*$" . font-lock-comment-face) + '("!.*$" . font-lock-comment-face) + '("no\\|router\\|interface\\|ipv6\\|ip6\\|ip" . font-lock-type-face) + '("ripng\\|rip\\|recive\\|advertize\\|accept" . font-lock-function-name-face) + '("version\\|network" . font-lock-function-name-face) + '("default\\|none\\|zebra" . font-lock-keyword-face) + '("hostname\\|password\\|enable\\|logfile\\|no" . font-lock-keyword-face)) + "Default value to highlight in bgp mode.") + +;; set font-lock-mode + +(defun zebra-font-lock () + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults '(zebra-font-lock-keywords nil t))) + +(defun bgp-font-lock () + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults '(bgp-font-lock-keywords nil t))) + +(defun rip-font-lock () + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults '(rip-font-lock-keywords nil t))) + +;; define Major mode + +(defun major-mode-define () + (interactive) + (progn + (setq comment-start "[#!]" + comment-end "" + comment-start-skip "!+ ") + (run-hooks 'zebra-mode-hook) + (cond + ((string< "20" emacs-version) + (font-lock-mode))))) + +(defun zebra-mode () + (progn + (setq mode-name "zebra") + (zebra-font-lock)) + (major-mode-define)) + +(defun bgp-mode () + (progn + (setq mode-name "bgp") + (bgp-font-lock)) + (major-mode-define)) + +(defun rip-mode () + (progn + (setq mode-name "rip") + (rip-font-lock)) + (major-mode-define)) diff --git a/update-autotools b/update-autotools new file mode 100755 index 0000000..1eaeb39 --- /dev/null +++ b/update-autotools @@ -0,0 +1,14 @@ +#! /bin/sh +# +# When local system does not have the latest autoconf/automake +# -- Kunihiro Ishiguro +# +rm -f config.cache +rm -f Makefile.in +rm -f aclocal.m4 +rm -f config.h.in +rm -f configure +aclocal +autoheader +autoconf +automake --foreign diff --git a/vtysh/ChangeLog b/vtysh/ChangeLog new file mode 100644 index 0000000..6f95086 --- /dev/null +++ b/vtysh/ChangeLog @@ -0,0 +1,179 @@ +2003-08-23 Hasso Tepper + + * extract.pl: IPv6 treatment. + Route-map and distribute modification for vtysh. + All protocol module consistency for vtysh. + +2002-07-07 Kunihiro Ishiguro + + * zebra-0.93 released. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-02-20 Kunihiro Ishiguro + + * vtysh.c (vtysh_client_config): Do not set bufsz to 120. + Suggested by: Matthew Grant . + +2001-02-15 Hideto Yamakawa + + * vtysh.c (vtysh_client_execute): Call fflush after fprintf. + + * vtysh_config.c (vtysh_config_dump): Use VTYSH_PAGER if defined. + +2001-02-14 Kunihiro Ishiguro + + * vtysh.c (vtysh_execute_func): Add fflush before pclose. + +2001-02-10 Kunihiro Ishiguro + + * vtysh.c: VTY shell pager name. When environment variable + VTYSH_PAGER is defined, use it as VTY shell pager. + +2001-02-09 Kunihiro Ishiguro + + * vtysh.c (vtysh_execute_func): Add pager argument for test of + pager invocation. + +2001-02-08 Kunihiro Ishiguro + + * extract.pl: Add -DHAVE_CONFIG_H option to cpp. + +2001-02-08 Matthew Grant + + * vtysh.c (vtysh_client_config): Use sysconf to determine output + buffer size. + (vtysh_write_memory): Set umask 0077. + (vtysh_connect): Check permission to the socket. + +2001-02-01 Kunihiro Ishiguro + + * zebra-0.91 is released. + +2001-01-31 Michael Rozhavsky + + * vtysh.c (new_completion): Fix problem of appending space when + completion is executed. + +2001-01-23 Akihiro Mizutani + + * vtysh.c (vtysh_write_terminal): "write terminal" to all node. + +2001-01-15 Kunihiro Ishiguro + + * vtysh.c (vtysh_execute): Fix unconditional lock by other VTY. + Suggested by Hideto Yamakawa . + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + +2001-01-07 Kunihiro Ishiguro + + * vtysh.h (ZEBRA_PATH): Fix new vtysh path. Reported by "Matt + Ranney" + +2000-11-06 Kunihiro Ishiguro + + * vtysh.c (DEFUNSH): Add "address-family vpnv4" DEFUNSH. + +2000-10-23 Kunihiro Ishiguro + + * vtysh.c (execute_command): Add two arguemnt support for + executing child process. + (vtysh_telnet_port): New command "telnet WORD PORT" is added. + +2000-10-23 Akihiro Mizutani + + * vtysh.c (vtysh_write_memory): Display [OK] when configuration is + saved without problem. + +2000-10-20 Kunihiro Ishiguro + + * vtysh.c (vtysh_config_from_file): "key chain" command with -b + flag problem is fixed. + +2000-10-17 Kunihiro Ishiguro + + * vtysh_user.c: Change to use linklist.c. + +2000-10-02 Kunihiro Ishiguro + + * Makefile.am (noinst_HEADERS): Add vtysh_user.h. + + * zebra-0.89 is released. + +2000-09-22 Kunihiro Ishiguro + + * vtysh_main.c: Declare thread master. + +2000-08-25 Kunihiro Ishiguro + + * vtysh_main.c (main): Add missing --help procudure. Reported by + Patrick Rother . + +2000-08-22 Kunihiro Ishiguro + + * vtysh.c (DEFUNSH): "interface IFNAME" works. + +2000-08-20 Kunihiro Ishiguro + + * vtysh_user.c: Change name from vtysh_pam.c. + + * vtysh.conf.sample: New file for vtysh configuration. + +2000-08-19 Kunihiro Ishiguro + + * vtysh_pam.c (vtysh_pam): New file for PAM. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +2000-08-02 Kunihiro Ishiguro + + * Makefile.am (vtysh_LDADD): Remove -lreadline and -lncurses. + + * vtysh.c (vtysh_connect): Use AF_UNIX instead of AF_LOCAL for + backward compatibility. + +2000-07-09 Kunihiro Ishiguro + + * extract.pl: Change regexp to match DEFUN and ALIAS at the same + time. + +2000-07-05 Kunihiro Ishiguro + + * vtysh.c (signal_init): Ignore SIGPIPE signal. + +2000-07-04 Kunihiro Ishiguro + + * extract.pl: ALIAS command can be extracted by extract.pl. + +2000-07-03 Kunihiro Ishiguro + + * extract.pl: Fix scalar and array semantics. + + * vtysh.c (vtysh_telnet): Add "telnet" client command. + +2000-07-02 Kunihiro Ishiguro + + * vtysh.c (main): Add -e flag for passing command from arugment. + (vtysh_ping): Add "ping" command for test of command execution. + (init_node): Add "traceroute" command. + (vtysh_start_shell): Add "start-shell", "start-shell bash", + "start-shell zsh". + (sigint): Add check for execute_flag for avoid duplicate prompt. + +2000-06-28 Kunihiro Ishiguro + + * vtysh.c: New file for vty shell. + * vtysh.h: Likewise. + * extract.pl: Likewise. + * vtysh_cmd.c: Generate by extract.pl. diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am new file mode 100644 index 0000000..c8010a9 --- /dev/null +++ b/vtysh/Makefile.am @@ -0,0 +1,22 @@ +## Process this file with Automake to create Makefile.in + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" + +LIBS = @LIBS@ @CURSES@ @LIBPAM@ + +bin_PROGRAMS = vtysh + +vtysh_SOURCES = vtysh_main.c vtysh.c vtysh_cmd.c vtysh_user.c vtysh_config.c +noinst_HEADERS = vtysh.h vtysh_user.h +vtysh_LDADD = ../lib/libzebra.a + +sysconf_DATA = vtysh.conf.sample + +EXTRA_DIST = extract.pl vtysh.conf.sample + +rebuild4: + ./extract.pl ../zebra/*.c ../ripd/*.c ../ospfd/*.c ../bgpd/*.c ../lib/keychain.c ../lib/routemap.c ../lib/filter.c ../lib/plist.c ../lib/distribute.c > vtysh_cmd.c + +rebuild: + ./extract.pl ../zebra/*.c ../ripd/*.c ../ripngd/*.c ../ospfd/*.c ../ospf6d/*.c ../bgpd/*.c ../lib/keychain.c ../lib/routemap.c ../lib/filter.c ../lib/plist.c ../lib/distribute.c > vtysh_cmd.c diff --git a/vtysh/Makefile.in b/vtysh/Makefile.in new file mode 100644 index 0000000..d59e2fa --- /dev/null +++ b/vtysh/Makefile.in @@ -0,0 +1,382 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CPP = @CPP@ +CURSES = @CURSES@ +DEPDIR = @DEPDIR@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LIBPAM = @LIBPAM@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" + +LIBS = @LIBS@ @CURSES@ @LIBPAM@ + +bin_PROGRAMS = vtysh + +vtysh_SOURCES = vtysh_main.c vtysh.c vtysh_cmd.c vtysh_user.c vtysh_config.c +noinst_HEADERS = vtysh.h vtysh_user.h +vtysh_LDADD = ../lib/libzebra.a + +sysconf_DATA = vtysh.conf.sample + +EXTRA_DIST = extract.pl vtysh.conf.sample +subdir = vtysh +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +bin_PROGRAMS = vtysh$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) + +am_vtysh_OBJECTS = vtysh_main.$(OBJEXT) vtysh.$(OBJEXT) \ + vtysh_cmd.$(OBJEXT) vtysh_user.$(OBJEXT) vtysh_config.$(OBJEXT) +vtysh_OBJECTS = $(am_vtysh_OBJECTS) +vtysh_DEPENDENCIES = ../lib/libzebra.a +vtysh_LDFLAGS = +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/vtysh.Po ./$(DEPDIR)/vtysh_cmd.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/vtysh_config.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/vtysh_main.Po ./$(DEPDIR)/vtysh_user.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CFLAGS = @CFLAGS@ +DIST_SOURCES = $(vtysh_SOURCES) +DATA = $(sysconf_DATA) + +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in +SOURCES = $(vtysh_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign vtysh/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +vtysh$(EXEEXT): $(vtysh_OBJECTS) $(vtysh_DEPENDENCIES) + @rm -f vtysh$(EXEEXT) + $(LINK) $(vtysh_LDFLAGS) $(vtysh_OBJECTS) $(vtysh_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vtysh.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vtysh_cmd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vtysh_config.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vtysh_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vtysh_user.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `cygpath -w $<` +CCDEPMODE = @CCDEPMODE@ +uninstall-info-am: +sysconfDATA_INSTALL = $(INSTALL_DATA) +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(sysconfDATA_INSTALL) $$d$$p $(DESTDIR)$(sysconfdir)/$$f"; \ + $(sysconfDATA_INSTALL) $$d$$p $(DESTDIR)$(sysconfdir)/$$f; \ + done + +uninstall-sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(sysconf_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \ + rm -f $(DESTDIR)$(sysconfdir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(DATA) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(sysconfdir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS install-sysconfDATA + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am \ + uninstall-sysconfDATA + +.PHONY: GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic distclean distclean-compile distclean-depend \ + distclean-generic distclean-tags distdir dvi dvi-am info \ + info-am install install-am install-binPROGRAMS install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip install-sysconfDATA \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-info-am uninstall-sysconfDATA + + +rebuild4: + ./extract.pl ../zebra/*.c ../ripd/*.c ../ospfd/*.c ../bgpd/*.c ../lib/keychain.c ../lib/routemap.c ../lib/filter.c ../lib/plist.c ../lib/distribute.c > vtysh_cmd.c + +rebuild: + ./extract.pl ../zebra/*.c ../ripd/*.c ../ripngd/*.c ../ospfd/*.c ../ospf6d/*.c ../bgpd/*.c ../lib/keychain.c ../lib/routemap.c ../lib/filter.c ../lib/plist.c ../lib/distribute.c > vtysh_cmd.c +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/vtysh/extract.pl b/vtysh/extract.pl new file mode 100755 index 0000000..514fe5e --- /dev/null +++ b/vtysh/extract.pl @@ -0,0 +1,186 @@ +#! /usr/bin/perl +## +## Virtual terminal interface shell command extractor. +## Copyright (C) 2000 Kunihiro Ishiguro +## +## This file is part of GNU Zebra. +## +## GNU Zebra 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, or (at your option) any +## later version. +## +## GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +## 02111-1307, USA. +## + +print < +#include "command.h" +#include "vtysh.h" + +EOF + +$ignore{'"interface IFNAME"'} = "ignore"; +$ignore{'"ip vrf NAME"'} = "ignore"; +$ignore{'"router rip"'} = "ignore"; +$ignore{'"router ripng"'} = "ignore"; +$ignore{'"router ospf"'} = "ignore"; +$ignore{'"router ospf <0-65535>"'} = "ignore"; +$ignore{'"router ospf6"'} = "ignore"; +$ignore{'"router bgp <1-65535>"'} = "ignore"; +$ignore{'"router bgp <1-65535> view WORD"'} = "ignore"; +$ignore{'"address-family ipv4"'} = "ignore"; +$ignore{'"address-family ipv4 (unicast|multicast)"'} = "ignore"; +$ignore{'"address-family ipv6"'} = "ignore"; +$ignore{'"address-family ipv6 unicast"'} = "ignore"; +$ignore{'"address-family vpnv4"'} = "ignore"; +$ignore{'"address-family vpnv4 unicast"'} = "ignore"; +$ignore{'"address-family ipv4 vrf NAME"'} = "ignore"; +$ignore{'"exit-address-family"'} = "ignore"; +$ignore{'"key chain WORD"'} = "ignore"; +$ignore{'"key <0-2147483647>"'} = "ignore"; +$ignore{'"route-map WORD (deny|permit) <1-65535>"'} = "ignore"; +$ignore{'"show route-map"'} = "ignore"; + +foreach (@ARGV) { + $file = $_; + + open (FH, "cpp -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -I. -I.. -I../lib $file |"); + local $/; undef $/; + $line = ; + close (FH); + + @defun = ($line =~ /(?:DEFUN|ALIAS)\s*\((.+?)\);?\s?\s?\n/sg); + @install = ($line =~ /install_element \(\s*[0-9A-Z_]+,\s*&[^;]*;\s*\n/sg); + + # DEFUN process + foreach (@defun) { + my (@defun_array); + @defun_array = split (/,/); + $defun_array[0] = ''; + + + # Actual input command string. + $str = "$defun_array[2]"; + $str =~ s/^\s+//g; + $str =~ s/\s+$//g; + + # Get VTY command structure. This is needed for searching + # install_element() command. + $cmd = "$defun_array[1]"; + $cmd =~ s/^\s+//g; + $cmd =~ s/\s+$//g; + + # $protocol is VTYSH_PROTO format for redirection of user input + if ($file =~ /lib/) { + if ($file =~ /keychain.c/) { + $protocol = "VTYSH_RIPD"; + } + if ($file =~ /routemap.c/) { + $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD"; + } + if ($file =~ /filter.c/) { + if ($defun_array[1] =~ m/ipv6/) { + $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD"; + } else { + $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD"; + } + } + if ($file =~ /plist.c/) { + if ($defun_array[1] =~ m/ipv6/) { + $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD"; + } else { + $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD"; + } + } + if ($file =~ /distribute.c/) { + if ($defun_array[1] =~ m/ipv6/) { + $protocol = "VTYSH_RIPNGD"; + } else { + $protocol = "VTYSH_RIPD"; + } + } + } else { + ($protocol) = ($file =~ /\/([a-z0-9]+)/); + $protocol = "VTYSH_" . uc $protocol; + } + + # Append _vtysh to structure then build DEFUN again + $defun_array[1] = $cmd . "_vtysh"; + $defun_body = join (", ", @defun_array); + + # $cmd -> $str hash for lookup + $cmd2str{$cmd} = $str; + $cmd2defun{$cmd} = $defun_body; + $cmd2proto{$cmd} = $protocol; + } + + # install_element() process + foreach (@install) { + my (@element_array); + @element_array = split (/,/); + + # Install node + $enode = $element_array[0]; + $enode =~ s/^\s+//g; + $enode =~ s/\s+$//g; + ($enode) = ($enode =~ /([0-9A-Z_]+)$/); + + # VTY command structure. + ($ecmd) = ($element_array[1] =~ /&([^\)]+)/); + $ecmd =~ s/^\s+//g; + $ecmd =~ s/\s+$//g; + + # Register $ecmd + if (defined ($cmd2str{$ecmd}) + && ! defined ($ignore{$cmd2str{$ecmd}})) { + my ($key); + $key = $enode . "," . $cmd2str{$ecmd}; + $ocmd{$key} = $ecmd; + $odefun{$key} = $cmd2defun{$ecmd}; + push (@{$oproto{$key}}, $cmd2proto{$ecmd}); + } + } +} + +# Check finaly alive $cmd; +foreach (keys %odefun) { + my ($node, $str) = (split (/,/)); + my ($cmd) = $ocmd{$_}; + $live{$cmd} = $_; +} + +# Output DEFSH +foreach (keys %live) { + my ($proto); + my ($key); + $key = $live{$_}; + $proto = join ("|", @{$oproto{$key}}); + printf "DEFSH ($proto$odefun{$key})\n\n"; +} + +# Output install_element +print < + +#include +#include +#include +#include +#include + +#include +#include + +#include "command.h" +#include "memory.h" +#include "vtysh/vtysh.h" + +/* Struct VTY. */ +struct vty *vty; + +/* VTY shell pager name. */ +char *vtysh_pager_name = NULL; + +/* VTY shell client structure. */ +struct vtysh_client +{ + int fd; +} vtysh_client[VTYSH_INDEX_MAX]; + +/* When '^Z' is received from vty, move down to the enable mode. */ +int +vtysh_end () +{ + switch (vty->node) + { + case VIEW_NODE: + case ENABLE_NODE: + /* Nothing to do. */ + break; + default: + vty->node = ENABLE_NODE; + break; + } + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + vtysh_end_all, + vtysh_end_all_cmd, + "end", + "End current mode and down to previous mode\n") +{ + return vtysh_end (vty); +} + +DEFUNSH (VTYSH_ALL, + vtysh_log_stdout, + vtysh_log_stdout_cmd, + "log stdout", + "Logging control\n" + "Logging goes to stdout\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + no_vtysh_log_stdout, + no_vtysh_log_stdout_cmd, + "no log stdout", + NO_STR + "Logging control\n" + "Logging goes to stdout\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + vtysh_log_file, + vtysh_log_file_cmd, + "log file FILENAME", + "Logging control\n" + "Logging to file\n" + "Logging filename\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + no_vtysh_log_file, + no_vtysh_log_file_cmd, + "no log file [FILENAME]", + NO_STR + "Logging control\n" + "Cancel logging to file\n" + "Logging file name\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + vtysh_log_syslog, + vtysh_log_syslog_cmd, + "log syslog", + "Logging control\n" + "Logging goes to syslog\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + no_vtysh_log_syslog, + no_vtysh_log_syslog_cmd, + "no log syslog", + NO_STR + "Logging control\n" + "Cancel logging to syslog\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + vtysh_log_trap, + vtysh_log_trap_cmd, + "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)", + "Logging control\n" + "Limit logging to specifed level\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + no_vtysh_log_trap, + no_vtysh_log_trap_cmd, + "no log trap", + NO_STR + "Logging control\n" + "Permit all logging information\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + vtysh_log_record_priority, + vtysh_log_record_priority_cmd, + "log record-priority", + "Logging control\n" + "Log the priority of the message within the message\n") +{ + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + no_vtysh_log_record_priority, + no_vtysh_log_record_priority_cmd, + "no log record-priority", + NO_STR + "Logging control\n" + "Do not log the priority of the message within the message\n") +{ + return CMD_SUCCESS; +} + +void +vclient_close (struct vtysh_client *vclient) +{ + if (vclient->fd > 0) + close (vclient->fd); + vclient->fd = -1; +} + + +/* Following filled with debug code to trace a problematic condition + under load - it SHOULD handle it. +*/ +#define ERR_WHERE_STRING "vtysh(): vtysh_client_config(): " +int +vtysh_client_config (struct vtysh_client *vclient, char *line) +{ + int ret; + char *buf; + size_t bufsz; + char *pbuf; + size_t left; + char *eoln; + int nbytes; + int i; + int readln; + + if (vclient->fd < 0) + return CMD_SUCCESS; + + ret = write (vclient->fd, line, strlen (line) + 1); + if (ret <= 0) + { + vclient_close (vclient); + return CMD_SUCCESS; + } + + /* Allow enough room for buffer to read more than a few pages from socket + */ + bufsz = 5 * sysconf(_SC_PAGESIZE) + 1; + buf = XMALLOC(MTYPE_TMP, bufsz); + memset(buf, 0, bufsz); + pbuf = buf; + + while (1) + { + if (pbuf >= ((buf + bufsz) -1)) + { + fprintf (stderr, ERR_WHERE_STRING \ + "warning - pbuf beyond buffer end.\n"); + return CMD_WARNING; + } + + readln = (buf + bufsz) - pbuf - 1; + nbytes = read (vclient->fd, pbuf, readln); + + if (nbytes <= 0) + { + + if (errno == EINTR) + continue; + + fprintf(stderr, ERR_WHERE_STRING "(%u)", errno); + perror(""); + + if (errno == EAGAIN || errno == EIO) + continue; + + vclient_close (vclient); + XFREE(MTYPE_TMP, buf); + return CMD_SUCCESS; + } + + pbuf[nbytes] = '\0'; + + if (nbytes >= 4) + { + i = nbytes - 4; + if (pbuf[i] == '\0' && pbuf[i + 1] == '\0' && pbuf[i + 2] == '\0') + { + ret = pbuf[i + 3]; + break; + } + } + pbuf += nbytes; + + /* See if a line exists in buffer, if so parse and consume it, and + reset read position */ + if ((eoln = strrchr(buf, '\n')) == NULL) + continue; + + if (eoln >= ((buf + bufsz) - 1)) + { + fprintf (stderr, ERR_WHERE_STRING \ + "warning - eoln beyond buffer end.\n"); + } + vtysh_config_parse(buf); + + eoln++; + left = (size_t)(buf + bufsz - eoln); + memmove(buf, eoln, left); + buf[bufsz-1] = '\0'; + pbuf = buf + strlen(buf); + } + + /* parse anything left in the buffer */ + vtysh_config_parse (buf); + + XFREE(MTYPE_TMP, buf); + return ret; +} + +int +vtysh_client_execute (struct vtysh_client *vclient, char *line, FILE *fp) +{ + int ret; + char buf[1001]; + int nbytes; + int i; + + if (vclient->fd < 0) + return CMD_SUCCESS; + + ret = write (vclient->fd, line, strlen (line) + 1); + if (ret <= 0) + { + vclient_close (vclient); + return CMD_SUCCESS; + } + + while (1) + { + nbytes = read (vclient->fd, buf, sizeof(buf)-1); + + if (nbytes <= 0 && errno != EINTR) + { + vclient_close (vclient); + return CMD_SUCCESS; + } + + if (nbytes > 0) + { + buf[nbytes] = '\0'; + fprintf (fp, "%s", buf); + fflush (fp); + + if (nbytes >= 4) + { + i = nbytes - 4; + if (buf[i] == '\0' && buf[i + 1] == '\0' && buf[i + 2] == '\0') + { + ret = buf[i + 3]; + break; + } + } + } + } + return ret; +} + +void +vtysh_exit_ripd_only () +{ + vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], "exit", stdout); +} + + +void +vtysh_pager_init () +{ + vtysh_pager_name = getenv ("VTYSH_PAGER"); + if (! vtysh_pager_name) + vtysh_pager_name = "more"; +} + +/* Command execution over the vty interface. */ +void +vtysh_execute_func (char *line, int pager) +{ + int ret, cmd_stat; + vector vline; + struct cmd_element *cmd; + FILE *fp = NULL; + + /* Split readline string up into the vector */ + vline = cmd_make_strvec (line); + + if (vline == NULL) + return; + + ret = cmd_execute_command (vline, vty, &cmd); + + cmd_free_strvec (vline); + + switch (ret) + { + case CMD_WARNING: + if (vty->type == VTY_FILE) + printf ("Warning...\n"); + break; + case CMD_ERR_AMBIGUOUS: + printf ("%% Ambiguous command.\n"); + break; + case CMD_ERR_NO_MATCH: + printf ("%% Unknown command.\n"); + break; + case CMD_ERR_INCOMPLETE: + printf ("%% Command incomplete.\n"); + break; + case CMD_SUCCESS_DAEMON: + { + if (pager && vtysh_pager_name) + { + fp = popen ("more", "w"); + if (fp == NULL) + { + perror ("popen"); + exit (1); + } + } + else + fp = stdout; + + if (! strcmp(cmd->string,"configure terminal")) + { + cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_ZEBRA], + line, fp); + if (cmd_stat != CMD_WARNING) + cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], + line, fp); + if (cmd_stat != CMD_WARNING) + cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIPNG], line, fp); + if (cmd_stat != CMD_WARNING) + cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF], + line, fp); + if (cmd_stat != CMD_WARNING) + cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF6], line, fp); + if (cmd_stat != CMD_WARNING) + cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_BGP], + line, fp); + if (cmd_stat) + { + line = "end"; + vline = cmd_make_strvec (line); + + if (vline == NULL) + { + if (pager && vtysh_pager_name && fp) + { + if (pclose (fp) == -1) + { + perror ("pclose"); + exit (1); + } + fp = NULL; + } + return; + } + + ret = cmd_execute_command (vline, vty, &cmd); + cmd_free_strvec (vline); + if (ret != CMD_SUCCESS_DAEMON) + break; + } + else + if (cmd->func) + { + (*cmd->func) (cmd, vty, 0, NULL); + break; + } + } + + if (cmd->daemon & VTYSH_ZEBRA) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_ZEBRA], line, fp) + != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_RIPD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], line, fp) + != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_RIPNGD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIPNG], line, fp) + != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_OSPFD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF], line, fp) + != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_OSPF6D) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF6], line, fp) + != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_BGPD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_BGP], line, fp) + != CMD_SUCCESS) + break; + if (cmd->func) + (*cmd->func) (cmd, vty, 0, NULL); + } + } + if (pager && vtysh_pager_name && fp) + { + if (pclose (fp) == -1) + { + perror ("pclose"); + exit (1); + } + fp = NULL; + } +} + +void +vtysh_execute_no_pager (char *line) +{ + vtysh_execute_func (line, 0); +} + +void +vtysh_execute (char *line) +{ + vtysh_execute_func (line, 1); +} + +/* Configration make from file. */ +int +vtysh_config_from_file (struct vty *vty, FILE *fp) +{ + int ret; + vector vline; + struct cmd_element *cmd; + + while (fgets (vty->buf, VTY_BUFSIZ, fp)) + { + if (vty->buf[0] == '!' || vty->buf[1] == '#') + continue; + + vline = cmd_make_strvec (vty->buf); + + /* In case of comment line */ + if (vline == NULL) + continue; + + /* Execute configuration command : this is strict match */ + ret = cmd_execute_command_strict (vline, vty, &cmd); + + /* Try again with setting node to CONFIG_NODE */ + if (ret != CMD_SUCCESS + && ret != CMD_SUCCESS_DAEMON + && ret != CMD_WARNING) + { + if (vty->node == KEYCHAIN_KEY_NODE) + { + vty->node = KEYCHAIN_NODE; + vtysh_exit_ripd_only (); + ret = cmd_execute_command_strict (vline, vty, &cmd); + + if (ret != CMD_SUCCESS + && ret != CMD_SUCCESS_DAEMON + && ret != CMD_WARNING) + { + vtysh_exit_ripd_only (); + vty->node = CONFIG_NODE; + ret = cmd_execute_command_strict (vline, vty, &cmd); + } + } + else + { + vtysh_execute ("end"); + vtysh_execute ("configure terminal"); + vty->node = CONFIG_NODE; + ret = cmd_execute_command_strict (vline, vty, &cmd); + } + } + + cmd_free_strvec (vline); + + switch (ret) + { + case CMD_WARNING: + if (vty->type == VTY_FILE) + printf ("Warning...\n"); + break; + case CMD_ERR_AMBIGUOUS: + printf ("%% Ambiguous command.\n"); + break; + case CMD_ERR_NO_MATCH: + printf ("%% Unknown command: %s", vty->buf); + break; + case CMD_ERR_INCOMPLETE: + printf ("%% Command incomplete.\n"); + break; + case CMD_SUCCESS_DAEMON: + { + if (cmd->daemon & VTYSH_ZEBRA) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_ZEBRA], + vty->buf, stdout) != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_RIPD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], + vty->buf, stdout) != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_RIPNGD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIPNG], + vty->buf, stdout) != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_OSPFD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF], + vty->buf, stdout) != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_OSPF6D) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF6], + vty->buf, stdout) != CMD_SUCCESS) + break; + if (cmd->daemon & VTYSH_BGPD) + if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_BGP], + vty->buf, stdout) != CMD_SUCCESS) + break; + if (cmd->func) + (*cmd->func) (cmd, vty, 0, NULL); + } + } + } + return CMD_SUCCESS; +} + +/* We don't care about the point of the cursor when '?' is typed. */ +int +vtysh_rl_describe () +{ + int ret; + int i; + vector vline; + vector describe; + int width; + struct desc *desc; + + vline = cmd_make_strvec (rl_line_buffer); + + /* In case of '> ?'. */ + if (vline == NULL) + { + vline = vector_init (1); + vector_set (vline, '\0'); + } + else + if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1])) + vector_set (vline, '\0'); + + describe = cmd_describe_command (vline, vty, &ret); + + printf ("\n"); + + /* Ambiguous and no match error. */ + switch (ret) + { + case CMD_ERR_AMBIGUOUS: + cmd_free_strvec (vline); + printf ("%% Ambiguous command.\n"); + rl_on_new_line (); + return 0; + break; + case CMD_ERR_NO_MATCH: + cmd_free_strvec (vline); + printf ("%% There is no matched command.\n"); + rl_on_new_line (); + return 0; + break; + } + + /* Get width of command string. */ + width = 0; + for (i = 0; i < vector_max (describe); i++) + if ((desc = vector_slot (describe, i)) != NULL) + { + int len; + + if (desc->cmd[0] == '\0') + continue; + + len = strlen (desc->cmd); + if (desc->cmd[0] == '.') + len--; + + if (width < len) + width = len; + } + + for (i = 0; i < vector_max (describe); i++) + if ((desc = vector_slot (describe, i)) != NULL) + { + if (desc->cmd[0] == '\0') + continue; + + if (! desc->str) + printf (" %-s\n", + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd); + else + printf (" %-*s %s\n", + width, + desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, + desc->str); + } + + cmd_free_strvec (vline); + vector_free (describe); + + rl_on_new_line(); + + return 0; +} + +/* result of cmd_complete_command() call will be stored here + and used in new_completion() in order to put the space in + correct places only */ +int complete_status; + +char * +command_generator (char *text, int state) +{ + vector vline; + static char **matched = NULL; + static int index = 0; + + /* First call. */ + if (! state) + { + index = 0; + + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + return NULL; + + vline = cmd_make_strvec (rl_line_buffer); + if (vline == NULL) + return NULL; + + if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1])) + vector_set (vline, '\0'); + + matched = cmd_complete_command (vline, vty, &complete_status); + } + + if (matched && matched[index]) + return matched[index++]; + + return NULL; +} + +char ** +new_completion (char *text, int start, int end) +{ + char **matches; + + matches = completion_matches (text, command_generator); + + if (matches) + { + rl_point = rl_end; + if (complete_status == CMD_COMPLETE_FULL_MATCH) + rl_pending_input = ' '; + } + + return matches; +} + +char ** +vtysh_completion (char *text, int start, int end) +{ + int ret; + vector vline; + char **matched = NULL; + + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + return NULL; + + vline = cmd_make_strvec (rl_line_buffer); + if (vline == NULL) + return NULL; + + /* In case of 'help \t'. */ + if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1])) + vector_set (vline, '\0'); + + matched = cmd_complete_command (vline, vty, &ret); + + cmd_free_strvec (vline); + + return (char **) matched; +} + +/* BGP node structure. */ +struct cmd_node bgp_node = +{ + BGP_NODE, + "%s(config-router)# ", +}; + +/* BGP node structure. */ +struct cmd_node rip_node = +{ + RIP_NODE, + "%s(config-router)# ", +}; + +struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", +}; + +DEFUNSH (VTYSH_BGPD, + router_bgp, + router_bgp_cmd, + "router bgp <1-65535>", + ROUTER_STR + BGP_STR + AS_STR) +{ + vty->node = BGP_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_vpnv4, + address_family_vpnv4_cmd, + "address-family vpnv4", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_VPNV4_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_vpnv4_unicast, + address_family_vpnv4_unicast_cmd, + "address-family vpnv4 unicast", + "Enter Address Family command mode\n" + "Address family\n" + "Address Family Modifier\n") +{ + vty->node = BGP_VPNV4_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_ipv4_unicast, + address_family_ipv4_unicast_cmd, + "address-family ipv4 unicast", + "Enter Address Family command mode\n" + "Address family\n" + "Address Family Modifier\n") +{ + vty->node = BGP_IPV4_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_ipv4, + address_family_ipv4_cmd, + "address-family ipv4", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_IPV4_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_ipv4_multicast, + address_family_ipv4_multicast_cmd, + "address-family ipv4 multicast", + "Enter Address Family command mode\n" + "Address family\n" + "Address Family Modifier\n") +{ + vty->node = BGP_IPV4M_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_ipv6, + address_family_ipv6_cmd, + "address-family ipv6", + "Enter Address Family command mode\n" + "Address family\n") +{ + vty->node = BGP_IPV6_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_BGPD, + address_family_ipv6_unicast, + address_family_ipv6_unicast_cmd, + "address-family ipv6 unicast", + "Enter Address Family command mode\n" + "Address family\n" + "Address Family Modifier\n") +{ + vty->node = BGP_IPV6_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_RIPD, + key_chain, + key_chain_cmd, + "key chain WORD", + "Authentication key management\n" + "Key-chain management\n" + "Key-chain name\n") +{ + vty->node = KEYCHAIN_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_RIPD, + key, + key_cmd, + "key <0-2147483647>", + "Configure a key\n" + "Key identifier number\n") +{ + vty->node = KEYCHAIN_KEY_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_RIPD, + router_rip, + router_rip_cmd, + "router rip", + ROUTER_STR + "RIP") +{ + vty->node = RIP_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_RIPNGD, + router_ripng, + router_ripng_cmd, + "router ripng", + ROUTER_STR + "RIPng") +{ + vty->node = RIPNG_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_OSPFD, + router_ospf, + router_ospf_cmd, + "router ospf", + "Enable a routing process\n" + "Start OSPF configuration\n") +{ + vty->node = OSPF_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_OSPF6D, + router_ospf6, + router_ospf6_cmd, + "router ospf6", + OSPF6_ROUTER_STR + OSPF6_STR) +{ + vty->node = OSPF6_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_RMAP, + route_map, + route_map_cmd, + "route-map WORD (deny|permit) <1-65535>", + "Create route-map or enter route-map command mode\n" + "Route map tag\n" + "Route map denies set operations\n" + "Route map permits set operations\n" + "Sequence to insert to/delete from existing route-map entry\n") +{ + vty->node = RMAP_NODE; + return CMD_SUCCESS; +} + +/* Enable command */ +DEFUNSH (VTYSH_ALL, + vtysh_enable, + vtysh_enable_cmd, + "enable", + "Turn on privileged mode command\n") +{ + vty->node = ENABLE_NODE; + return CMD_SUCCESS; +} + +/* Disable command */ +DEFUNSH (VTYSH_ALL, + vtysh_disable, + vtysh_disable_cmd, + "disable", + "Turn off privileged mode command\n") +{ + if (vty->node == ENABLE_NODE) + vty->node = VIEW_NODE; + return CMD_SUCCESS; +} + +/* Configration from terminal */ +DEFUNSH (VTYSH_ALL, + vtysh_config_terminal, + vtysh_config_terminal_cmd, + "configure terminal", + "Configuration from vty interface\n" + "Configuration terminal\n") +{ + vty->node = CONFIG_NODE; + return CMD_SUCCESS; +} + +int +vtysh_exit (struct vty *vty) +{ + switch (vty->node) + { + case VIEW_NODE: + case ENABLE_NODE: + exit (0); + break; + case CONFIG_NODE: + vty->node = ENABLE_NODE; + break; + case INTERFACE_NODE: + case ZEBRA_NODE: + case BGP_NODE: + case RIP_NODE: + case RIPNG_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case MASC_NODE: + case RMAP_NODE: + case VTY_NODE: + case KEYCHAIN_NODE: + vty->node = CONFIG_NODE; + break; + case BGP_VPNV4_NODE: + case BGP_IPV4_NODE: + case BGP_IPV4M_NODE: + case BGP_IPV6_NODE: + vty->node = BGP_NODE; + break; + case KEYCHAIN_KEY_NODE: + vty->node = KEYCHAIN_NODE; + break; + default: + break; + } + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ALL, + vtysh_exit_all, + vtysh_exit_all_cmd, + "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit (vty); +} + +ALIAS (vtysh_exit_all, + vtysh_quit_all_cmd, + "quit", + "Exit current mode and down to previous mode\n"); + +DEFUNSH (VTYSH_BGPD, + exit_address_family, + exit_address_family_cmd, + "exit-address-family", + "Exit from Address Family configuration mode\n") +{ + if (vty->node == BGP_IPV4_NODE + || vty->node == BGP_IPV4M_NODE + || vty->node == BGP_VPNV4_NODE + || vty->node == BGP_IPV6_NODE) + vty->node = BGP_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ZEBRA, + vtysh_exit_zebra, + vtysh_exit_zebra_cmd, + "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit (vty); +} + +ALIAS (vtysh_exit_zebra, + vtysh_quit_zebra_cmd, + "quit", + "Exit current mode and down to previous mode\n"); + +DEFUNSH (VTYSH_RIPD, + vtysh_exit_ripd, + vtysh_exit_ripd_cmd, + "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit (vty); +} + +ALIAS (vtysh_exit_ripd, + vtysh_quit_ripd_cmd, + "quit", + "Exit current mode and down to previous mode\n"); + +DEFUNSH (VTYSH_RIPNGD, + vtysh_exit_ripngd, + vtysh_exit_ripngd_cmd, + "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit (vty); +} + +ALIAS (vtysh_exit_ripngd, + vtysh_quit_ripngd_cmd, + "quit", + "Exit current mode and down to previous mode\n"); + +DEFUNSH (VTYSH_RMAP, + vtysh_exit_rmap, + vtysh_exit_rmap_cmd, + "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit (vty); +} + +ALIAS (vtysh_exit_rmap, + vtysh_quit_rmap_cmd, + "quit", + "Exit current mode and down to previous mode\n"); + +DEFUNSH (VTYSH_BGPD, + vtysh_exit_bgpd, + vtysh_exit_bgpd_cmd, + "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit (vty); +} + +ALIAS (vtysh_exit_bgpd, + vtysh_quit_bgpd_cmd, + "quit", + "Exit current mode and down to previous mode\n"); + +DEFUNSH (VTYSH_OSPFD, + vtysh_exit_ospfd, + vtysh_exit_ospfd_cmd, + "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit (vty); +} + +ALIAS (vtysh_exit_ospfd, + vtysh_quit_ospfd_cmd, + "quit", + "Exit current mode and down to previous mode\n"); + +DEFUNSH (VTYSH_OSPF6D, + vtysh_exit_ospf6d, + vtysh_exit_ospf6d_cmd, + "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit (vty); +} + +ALIAS (vtysh_exit_ospf6d, + vtysh_quit_ospf6d_cmd, + "quit", + "Exit current mode and down to previous mode\n"); + +DEFUNSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D, + vtysh_interface, + vtysh_interface_cmd, + "interface IFNAME", + "Select an interface to configure\n" + "Interface's name\n") +{ + vty->node = INTERFACE_NODE; + return CMD_SUCCESS; +} + +DEFUNSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D, + vtysh_exit_interface, + vtysh_exit_interface_cmd, + "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit (vty); +} + +ALIAS (vtysh_exit_interface, + vtysh_quit_interface_cmd, + "quit", + "Exit current mode and down to previous mode\n"); + +DEFUN (vtysh_write_terminal, + vtysh_write_terminal_cmd, + "write terminal", + "Write running configuration to memory, network, or terminal\n" + "Write to terminal\n") +{ + int ret; + char line[] = "write terminal\n"; + FILE *fp = NULL; + + if (vtysh_pager_name) + { + fp = popen ("more", "w"); + if (fp == NULL) + { + perror ("popen"); + exit (1); + } + } + else + fp = stdout; + + vty_out (vty, "Building configuration...%s", VTY_NEWLINE); + vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE, + VTY_NEWLINE); + + vtysh_config_write (fp); + + ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_ZEBRA], line); + ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_RIP], line); + ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_RIPNG], line); + ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_OSPF], line); + ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_OSPF6], line); + ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_BGP], line); + + vtysh_config_dump (fp); + + if (vtysh_pager_name && fp) + { + fflush (fp); + if (pclose (fp) == -1) + { + perror ("pclose"); + exit (1); + } + fp = NULL; + } + + return CMD_SUCCESS; +} + +DEFUN (vtysh_write_memory, + vtysh_write_memory_cmd, + "write memory", + "Write running configuration to memory, network, or terminal\n" + "Write configuration to the file (same as write file)\n") +{ + int ret; + mode_t old_umask; + char line[] = "write terminal\n"; + FILE *fp; + char *integrate_sav = NULL; + + /* config files have 0600 perms... */ + old_umask = umask (0077); + + integrate_sav = malloc (strlen (integrate_default) + + strlen (CONF_BACKUP_EXT) + 1); + strcpy (integrate_sav, integrate_default); + strcat (integrate_sav, CONF_BACKUP_EXT); + + + printf ("Building Configuration...\n"); + + /* Move current configuration file to backup config file */ + unlink (integrate_sav); + rename (integrate_default, integrate_sav); + + fp = fopen (integrate_default, "w"); + if (fp == NULL) + { + printf ("%% Can't open configuration file %s.\n", integrate_default); + umask (old_umask); + return CMD_SUCCESS; + } + else + printf ("[OK]\n"); + + + vtysh_config_write (fp); + + ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_ZEBRA], line); + ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_RIP], line); + ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_RIPNG], line); + ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_OSPF], line); + ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_OSPF6], line); + ret = vtysh_client_config (&vtysh_client[VTYSH_INDEX_BGP], line); + + vtysh_config_dump (fp); + + fclose (fp); + + umask (old_umask); + return CMD_SUCCESS; +} + +ALIAS (vtysh_write_memory, + vtysh_copy_runningconfig_startupconfig_cmd, + "copy running-config startup-config", + "Copy from one file to another\n" + "Copy from current system configuration\n" + "Copy to startup configuration\n"); + +ALIAS (vtysh_write_memory, + vtysh_write_file_cmd, + "write file", + "Write running configuration to memory, network, or terminal\n" + "Write configuration to the file (same as write memory)\n"); + +ALIAS (vtysh_write_terminal, + vtysh_show_running_config_cmd, + "show running-config", + SHOW_STR + "Current operating configuration\n"); + +/* Execute command in child process. */ +int +execute_command (char *command, int argc, char *arg1, char *arg2) +{ + int ret; + pid_t pid; + int status; + + /* Call fork(). */ + pid = fork (); + + if (pid < 0) + { + /* Failure of fork(). */ + fprintf (stderr, "Can't fork: %s\n", strerror (errno)); + exit (1); + } + else if (pid == 0) + { + /* This is child process. */ + switch (argc) + { + case 0: + ret = execlp (command, command, NULL); + break; + case 1: + ret = execlp (command, command, arg1, NULL); + break; + case 2: + ret = execlp (command, command, arg1, arg2, NULL); + break; + } + + /* When execlp suceed, this part is not executed. */ + fprintf (stderr, "Can't execute %s: %s\n", command, strerror (errno)); + exit (1); + } + else + { + /* This is parent. */ + execute_flag = 1; + ret = wait4 (pid, &status, 0, NULL); + execute_flag = 0; + } + return 0; +} + +DEFUN (vtysh_ping, + vtysh_ping_cmd, + "ping WORD", + "send echo messages\n" + "Ping destination address or hostname\n") +{ + execute_command ("ping", 1, argv[0], NULL); + return CMD_SUCCESS; +} + +DEFUN (vtysh_traceroute, + vtysh_traceroute_cmd, + "traceroute WORD", + "Trace route to destination\n" + "Trace route to destination address or hostname\n") +{ + execute_command ("traceroute", 1, argv[0], NULL); + return CMD_SUCCESS; +} + +DEFUN (vtysh_telnet, + vtysh_telnet_cmd, + "telnet WORD", + "Open a telnet connection\n" + "IP address or hostname of a remote system\n") +{ + execute_command ("telnet", 1, argv[0], NULL); + return CMD_SUCCESS; +} + +DEFUN (vtysh_telnet_port, + vtysh_telnet_port_cmd, + "telnet WORD PORT", + "Open a telnet connection\n" + "IP address or hostname of a remote system\n" + "TCP Port number\n") +{ + execute_command ("telnet", 2, argv[0], argv[1]); + return CMD_SUCCESS; +} + +DEFUN (vtysh_start_shell, + vtysh_start_shell_cmd, + "start-shell", + "Start UNIX shell\n") +{ + execute_command ("sh", 0, NULL, NULL); + return CMD_SUCCESS; +} + +DEFUN (vtysh_start_bash, + vtysh_start_bash_cmd, + "start-shell bash", + "Start UNIX shell\n" + "Start bash\n") +{ + execute_command ("bash", 0, NULL, NULL); + return CMD_SUCCESS; +} + +DEFUN (vtysh_start_zsh, + vtysh_start_zsh_cmd, + "start-shell zsh", + "Start UNIX shell\n" + "Start Z shell\n") +{ + execute_command ("zsh", 0, NULL, NULL); + return CMD_SUCCESS; +} + +/* Route map node structure. */ +struct cmd_node rmap_node = +{ + RMAP_NODE, + "%s(config-route-map)# " +}; + +/* Zebra node structure. */ +struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "%s(config-router)# " +}; + +struct cmd_node bgp_vpnv4_node = +{ + BGP_VPNV4_NODE, + "%s(config-router-af)# " +}; + +struct cmd_node bgp_ipv4_node = +{ + BGP_IPV4_NODE, + "%s(config-router-af)# " +}; + +struct cmd_node bgp_ipv4m_node = +{ + BGP_IPV4M_NODE, + "%s(config-router-af)# " +}; + +struct cmd_node bgp_ipv6_node = +{ + BGP_IPV6_NODE, + "%s(config-router-af)# " +}; + +struct cmd_node ospf_node = +{ + OSPF_NODE, + "%s(config-router)# " +}; + +/* RIPng node structure. */ +struct cmd_node ripng_node = +{ + RIPNG_NODE, + "%s(config-router)# " +}; + +/* OSPF6 node structure. */ +struct cmd_node ospf6_node = +{ + OSPF6_NODE, + "%s(config-ospf6)# " +}; + +struct cmd_node keychain_node = +{ + KEYCHAIN_NODE, + "%s(config-keychain)# " +}; + +struct cmd_node keychain_key_node = +{ + KEYCHAIN_KEY_NODE, + "%s(config-keychain-key)# " +}; + +void +vtysh_install_default (enum node_type node) +{ + install_element (node, &config_list_cmd); +} + +/* Making connection to protocol daemon. */ +int +vtysh_connect (struct vtysh_client *vclient, char *path) +{ + int ret; + int sock, len; + struct sockaddr_un addr; + struct stat s_stat; + uid_t euid; + gid_t egid; + + memset (vclient, 0, sizeof (struct vtysh_client)); + vclient->fd = -1; + + /* Stat socket to see if we have permission to access it. */ + euid = geteuid(); + egid = getegid(); + ret = stat (path, &s_stat); + if (ret < 0 && errno != ENOENT) + { + fprintf (stderr, "vtysh_connect(%s): stat = %s\n", + path, strerror(errno)); + exit(1); + } + + if (ret >= 0) + { + if (! S_ISSOCK(s_stat.st_mode)) + { + fprintf (stderr, "vtysh_connect(%s): Not a socket\n", + path); + exit (1); + } + + if (euid != s_stat.st_uid + || !(s_stat.st_mode & S_IWUSR) + || !(s_stat.st_mode & S_IRUSR)) + { + fprintf (stderr, "vtysh_connect(%s): No permission to access socket\n", + path); + exit (1); + } + } + + sock = socket (AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + { +#ifdef DEBUG + fprintf(stderr, "vtysh_connect(%s): socket = %s\n", path, strerror(errno)); +#endif /* DEBUG */ + return -1; + } + + memset (&addr, 0, sizeof (struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy (addr.sun_path, path, strlen (path)); +#ifdef HAVE_SUN_LEN + len = addr.sun_len = SUN_LEN(&addr); +#else + len = sizeof (addr.sun_family) + strlen (addr.sun_path); +#endif /* HAVE_SUN_LEN */ + + ret = connect (sock, (struct sockaddr *) &addr, len); + if (ret < 0) + { +#ifdef DEBUG + fprintf(stderr, "vtysh_connect(%s): connect = %s\n", path, strerror(errno)); +#endif /* DEBUG */ + close (sock); + return -1; + } + vclient->fd = sock; + + return 0; +} + +void +vtysh_connect_all() +{ + /* Clear each daemons client structure. */ + vtysh_connect (&vtysh_client[VTYSH_INDEX_ZEBRA], ZEBRA_PATH); + vtysh_connect (&vtysh_client[VTYSH_INDEX_RIP], RIP_PATH); + vtysh_connect (&vtysh_client[VTYSH_INDEX_RIPNG], RIPNG_PATH); + vtysh_connect (&vtysh_client[VTYSH_INDEX_OSPF], OSPF_PATH); + vtysh_connect (&vtysh_client[VTYSH_INDEX_OSPF6], OSPF6_PATH); + vtysh_connect (&vtysh_client[VTYSH_INDEX_BGP], BGP_PATH); +} + + +/* To disable readline's filename completion */ +int +vtysh_completion_entry_function (int ignore, int invoking_key) +{ + return 0; +} + +void +vtysh_readline_init () +{ + /* readline related settings. */ + rl_bind_key ('?', vtysh_rl_describe); + rl_completion_entry_function = vtysh_completion_entry_function; + rl_attempted_completion_function = (CPPFunction *)new_completion; + /* do not append space after completion. It will be appended + in new_completion() function explicitly */ + rl_completion_append_character = '\0'; +} + +char * +vtysh_prompt () +{ + struct utsname names; + static char buf[100]; + const char*hostname; + extern struct host host; + + hostname = host.name; + + if (!hostname) + { + uname (&names); + hostname = names.nodename; + } + + snprintf (buf, sizeof buf, cmd_prompt (vty->node), hostname); + + return buf; +} + +void +vtysh_init_vty () +{ + /* Make vty structure. */ + vty = vty_new (); + vty->type = VTY_SHELL; + vty->node = VIEW_NODE; + + /* Initialize commands. */ + cmd_init (0); + + /* Install nodes. */ + install_node (&bgp_node, NULL); + install_node (&rip_node, NULL); + install_node (&interface_node, NULL); + install_node (&rmap_node, NULL); + install_node (&zebra_node, NULL); + install_node (&bgp_vpnv4_node, NULL); + install_node (&bgp_ipv4_node, NULL); + install_node (&bgp_ipv4m_node, NULL); +/* #ifdef HAVE_IPV6 */ + install_node (&bgp_ipv6_node, NULL); +/* #endif */ + install_node (&ospf_node, NULL); +/* #ifdef HAVE_IPV6 */ + install_node (&ripng_node, NULL); + install_node (&ospf6_node, NULL); +/* #endif */ + install_node (&keychain_node, NULL); + install_node (&keychain_key_node, NULL); + + vtysh_install_default (VIEW_NODE); + vtysh_install_default (ENABLE_NODE); + vtysh_install_default (CONFIG_NODE); + vtysh_install_default (BGP_NODE); + vtysh_install_default (RIP_NODE); + vtysh_install_default (INTERFACE_NODE); + vtysh_install_default (RMAP_NODE); + vtysh_install_default (ZEBRA_NODE); + vtysh_install_default (BGP_VPNV4_NODE); + vtysh_install_default (BGP_IPV4_NODE); + vtysh_install_default (BGP_IPV4M_NODE); + vtysh_install_default (BGP_IPV6_NODE); + vtysh_install_default (OSPF_NODE); + vtysh_install_default (RIPNG_NODE); + vtysh_install_default (OSPF6_NODE); + vtysh_install_default (KEYCHAIN_NODE); + vtysh_install_default (KEYCHAIN_KEY_NODE); + + install_element (VIEW_NODE, &vtysh_enable_cmd); + install_element (ENABLE_NODE, &vtysh_config_terminal_cmd); + install_element (ENABLE_NODE, &vtysh_disable_cmd); + + /* "exit" command. */ + install_element (VIEW_NODE, &vtysh_exit_all_cmd); + install_element (VIEW_NODE, &vtysh_quit_all_cmd); + install_element (CONFIG_NODE, &vtysh_exit_all_cmd); + /* install_element (CONFIG_NODE, &vtysh_quit_all_cmd); */ + install_element (ENABLE_NODE, &vtysh_exit_all_cmd); + install_element (ENABLE_NODE, &vtysh_quit_all_cmd); + install_element (RIP_NODE, &vtysh_exit_ripd_cmd); + install_element (RIP_NODE, &vtysh_quit_ripd_cmd); + install_element (RIPNG_NODE, &vtysh_exit_ripngd_cmd); + install_element (RIPNG_NODE, &vtysh_quit_ripngd_cmd); + install_element (OSPF_NODE, &vtysh_exit_ospfd_cmd); + install_element (OSPF_NODE, &vtysh_quit_ospfd_cmd); + install_element (OSPF6_NODE, &vtysh_exit_ospf6d_cmd); + install_element (OSPF6_NODE, &vtysh_quit_ospf6d_cmd); + install_element (BGP_NODE, &vtysh_exit_bgpd_cmd); + install_element (BGP_NODE, &vtysh_quit_bgpd_cmd); + install_element (BGP_VPNV4_NODE, &vtysh_exit_bgpd_cmd); + install_element (BGP_VPNV4_NODE, &vtysh_quit_bgpd_cmd); + install_element (BGP_IPV4_NODE, &vtysh_exit_bgpd_cmd); + install_element (BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd); + install_element (BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd); + install_element (BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd); + install_element (BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd); + install_element (BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd); + install_element (KEYCHAIN_NODE, &vtysh_exit_ripd_cmd); + install_element (KEYCHAIN_NODE, &vtysh_quit_ripd_cmd); + install_element (KEYCHAIN_KEY_NODE, &vtysh_exit_ripd_cmd); + install_element (KEYCHAIN_KEY_NODE, &vtysh_quit_ripd_cmd); + install_element (RMAP_NODE, &vtysh_exit_rmap_cmd); + install_element (RMAP_NODE, &vtysh_quit_rmap_cmd); + + /* "end" command. */ + install_element (CONFIG_NODE, &vtysh_end_all_cmd); + install_element (ENABLE_NODE, &vtysh_end_all_cmd); + install_element (RIP_NODE, &vtysh_end_all_cmd); + install_element (RIPNG_NODE, &vtysh_end_all_cmd); + install_element (OSPF_NODE, &vtysh_end_all_cmd); + install_element (OSPF6_NODE, &vtysh_end_all_cmd); + install_element (BGP_NODE, &vtysh_end_all_cmd); + install_element (BGP_IPV4_NODE, &vtysh_end_all_cmd); + install_element (BGP_IPV4M_NODE, &vtysh_end_all_cmd); + install_element (BGP_VPNV4_NODE, &vtysh_end_all_cmd); + install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd); + install_element (KEYCHAIN_NODE, &vtysh_end_all_cmd); + install_element (KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd); + install_element (RMAP_NODE, &vtysh_end_all_cmd); + + install_element (INTERFACE_NODE, &vtysh_end_all_cmd); + install_element (INTERFACE_NODE, &vtysh_exit_interface_cmd); + install_element (INTERFACE_NODE, &vtysh_quit_interface_cmd); + install_element (CONFIG_NODE, &router_rip_cmd); +#ifdef HAVE_IPV6 + install_element (CONFIG_NODE, &router_ripng_cmd); +#endif + install_element (CONFIG_NODE, &router_ospf_cmd); +#ifdef HAVE_IPV6 + install_element (CONFIG_NODE, &router_ospf6_cmd); +#endif + install_element (CONFIG_NODE, &router_bgp_cmd); + install_element (BGP_NODE, &address_family_vpnv4_cmd); + install_element (BGP_NODE, &address_family_vpnv4_unicast_cmd); + install_element (BGP_NODE, &address_family_ipv4_cmd); + install_element (BGP_NODE, &address_family_ipv4_unicast_cmd); + install_element (BGP_NODE, &address_family_ipv4_multicast_cmd); +#ifdef HAVE_IPV6 + install_element (BGP_NODE, &address_family_ipv6_cmd); + install_element (BGP_NODE, &address_family_ipv6_unicast_cmd); +#endif + install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); + install_element (BGP_IPV4_NODE, &exit_address_family_cmd); + install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); + install_element (BGP_IPV6_NODE, &exit_address_family_cmd); + install_element (CONFIG_NODE, &key_chain_cmd); + install_element (CONFIG_NODE, &route_map_cmd); + install_element (KEYCHAIN_NODE, &key_cmd); + install_element (KEYCHAIN_NODE, &key_chain_cmd); + install_element (KEYCHAIN_KEY_NODE, &key_chain_cmd); + install_element (CONFIG_NODE, &vtysh_interface_cmd); + install_element (ENABLE_NODE, &vtysh_show_running_config_cmd); + install_element (ENABLE_NODE, &vtysh_copy_runningconfig_startupconfig_cmd); + install_element (ENABLE_NODE, &vtysh_write_file_cmd); + + /* write terminal command */ + install_element (ENABLE_NODE, &vtysh_write_terminal_cmd); + install_element (CONFIG_NODE, &vtysh_write_terminal_cmd); + install_element (BGP_NODE, &vtysh_write_terminal_cmd); + install_element (BGP_VPNV4_NODE, &vtysh_write_terminal_cmd); + install_element (BGP_IPV4_NODE, &vtysh_write_terminal_cmd); + install_element (BGP_IPV4M_NODE, &vtysh_write_terminal_cmd); + install_element (BGP_IPV6_NODE, &vtysh_write_terminal_cmd); + install_element (RIP_NODE, &vtysh_write_terminal_cmd); + install_element (RIPNG_NODE, &vtysh_write_terminal_cmd); + install_element (OSPF_NODE, &vtysh_write_terminal_cmd); + install_element (OSPF6_NODE, &vtysh_write_terminal_cmd); + install_element (INTERFACE_NODE, &vtysh_write_terminal_cmd); + install_element (RMAP_NODE, &vtysh_write_terminal_cmd); + install_element (KEYCHAIN_NODE, &vtysh_write_terminal_cmd); + install_element (KEYCHAIN_KEY_NODE, &vtysh_write_terminal_cmd); + + /* write memory command */ + install_element (ENABLE_NODE, &vtysh_write_memory_cmd); + install_element (CONFIG_NODE, &vtysh_write_memory_cmd); + install_element (BGP_NODE, &vtysh_write_memory_cmd); + install_element (BGP_VPNV4_NODE, &vtysh_write_memory_cmd); + install_element (BGP_IPV4_NODE, &vtysh_write_memory_cmd); + install_element (BGP_IPV4M_NODE, &vtysh_write_memory_cmd); + install_element (BGP_IPV6_NODE, &vtysh_write_memory_cmd); + install_element (RIP_NODE, &vtysh_write_memory_cmd); + install_element (RIPNG_NODE, &vtysh_write_memory_cmd); + install_element (OSPF_NODE, &vtysh_write_memory_cmd); + install_element (OSPF6_NODE, &vtysh_write_memory_cmd); + install_element (INTERFACE_NODE, &vtysh_write_memory_cmd); + install_element (RMAP_NODE, &vtysh_write_memory_cmd); + install_element (KEYCHAIN_NODE, &vtysh_write_memory_cmd); + install_element (KEYCHAIN_KEY_NODE, &vtysh_write_memory_cmd); + + install_element (VIEW_NODE, &vtysh_ping_cmd); + install_element (VIEW_NODE, &vtysh_traceroute_cmd); + install_element (VIEW_NODE, &vtysh_telnet_cmd); + install_element (VIEW_NODE, &vtysh_telnet_port_cmd); + install_element (ENABLE_NODE, &vtysh_ping_cmd); + install_element (ENABLE_NODE, &vtysh_traceroute_cmd); + install_element (ENABLE_NODE, &vtysh_telnet_cmd); + install_element (ENABLE_NODE, &vtysh_telnet_port_cmd); + install_element (ENABLE_NODE, &vtysh_start_shell_cmd); + install_element (ENABLE_NODE, &vtysh_start_bash_cmd); + install_element (ENABLE_NODE, &vtysh_start_zsh_cmd); + + install_element (CONFIG_NODE, &vtysh_log_stdout_cmd); + install_element (CONFIG_NODE, &no_vtysh_log_stdout_cmd); + install_element (CONFIG_NODE, &vtysh_log_file_cmd); + install_element (CONFIG_NODE, &no_vtysh_log_file_cmd); + install_element (CONFIG_NODE, &vtysh_log_syslog_cmd); + install_element (CONFIG_NODE, &no_vtysh_log_syslog_cmd); + install_element (CONFIG_NODE, &vtysh_log_trap_cmd); + install_element (CONFIG_NODE, &no_vtysh_log_trap_cmd); + install_element (CONFIG_NODE, &vtysh_log_record_priority_cmd); + install_element (CONFIG_NODE, &no_vtysh_log_record_priority_cmd); +} diff --git a/vtysh/vtysh.conf.sample b/vtysh/vtysh.conf.sample new file mode 100644 index 0000000..29d6808 --- /dev/null +++ b/vtysh/vtysh.conf.sample @@ -0,0 +1,4 @@ +! +! vtysh sample configuratin file +! +!username kunihiro nopassword diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h new file mode 100644 index 0000000..d60bf8f --- /dev/null +++ b/vtysh/vtysh.h @@ -0,0 +1,83 @@ +/* Virtual terminal interface shell. + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef VTYSH_H +#define VTYSH_H + +#define VTYSH_ZEBRA 0x01 +#define VTYSH_RIPD 0x02 +#define VTYSH_RIPNGD 0x04 +#define VTYSH_OSPFD 0x08 +#define VTYSH_OSPF6D 0x10 +#define VTYSH_BGPD 0x20 +#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD +#define VTYSH_RMAP VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD + +#define VTYSH_INDEX_ZEBRA 0 +#define VTYSH_INDEX_RIP 1 +#define VTYSH_INDEX_RIPNG 2 +#define VTYSH_INDEX_OSPF 3 +#define VTYSH_INDEX_OSPF6 4 +#define VTYSH_INDEX_BGP 5 +#define VTYSH_INDEX_MAX 6 + +/* UNIX domain socket path. */ +#define ZEBRA_PATH "/tmp/.zebra" +#define RIP_PATH "/tmp/.ripd" +#define RIPNG_PATH "/tmp/.ripngd" +#define OSPF_PATH "/tmp/.ospfd" +#define OSPF6_PATH "/tmp/.ospf6d" +#define BGP_PATH "/tmp/.bgpd" + +/* vtysh local configuration file. */ +#define VTYSH_DEFAULT_CONFIG "vtysh.conf" + +void vtysh_init_vty (); +void vtysh_init_cmd (); +void vtysh_connect_all (); +void vtysh_readline_init (); +void vtysh_user_init (); + +void vtysh_execute (char *); +void vtysh_execute_no_pager (char *); + +char *vtysh_prompt (); + +void vtysh_config_write (); + +int vtysh_config_from_file (struct vty *, FILE *); + +void vtysh_read_config (char *, char *, char *); + +void vtysh_config_parse (char *); + +void vtysh_config_dump (FILE *); + +void vtysh_config_init (); + +void vtysh_pager_init (); + +/* Child process execution flag. */ +extern int execute_flag; + +extern struct vty *vty; + +#endif /* VTYSH_H */ diff --git a/vtysh/vtysh_cmd.c b/vtysh/vtysh_cmd.c new file mode 100644 index 0000000..f55a594 --- /dev/null +++ b/vtysh/vtysh_cmd.c @@ -0,0 +1,15439 @@ +#include +#include "command.h" +#include "vtysh.h" + +DEFSH (VTYSH_BGPD, neighbor_version_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X) " "version <4-4>", + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Set the BGP version to match a neighbor\n" + "Neighbor's BGP version\n") + +DEFSH (VTYSH_BGPD, no_set_aspath_prepend_cmd_vtysh, + "no set as-path prepend", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "Prepend string for a BGP AS-path attribute\n" + "Prepend to the as-path\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, clear_ipv6_prefix_list_cmd_vtysh, + "clear ipv6 prefix-list", + "Reset functions\n" + "IPv6 information\n" + "Build a prefix list\n" ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_soft_out_cmd_vtysh, + "clear ip bgp A.B.C.D vpnv4 unicast soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_host_any_cmd_vtysh, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "Any destination host\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ip_prefix_list_description_cmd_vtysh, + "ip prefix-list WORD description .LINE", + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Prefix-list specific description\n" + "Up to 80 characters describing this prefix-list\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_inter_external_cmd_vtysh, + "distance ospf intra-area <1-255> inter-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n") + +DEFSH (VTYSH_ZEBRA, no_ipv6_route_cmd_vtysh, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE|null0)", + "Negate a command or set its defaults\n" + "IP information\n" + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_interface_ifname_prefix_detail_cmd_vtysh, + "show ipv6 ospf6 interface IFNAME prefix (X:X::X:X|X:X::X:X/M|detail)", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Interface infomation\n" + "Interface name(e.g. ep0)\n" + "Display connected prefixes to advertise\n" + "Display the route bestmatches the address\n" + "Display the route\n" + "Dispaly details of the prefixes\n" + ) + +DEFSH (VTYSH_BGPD, no_neighbor_update_source_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "update-source", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Source of routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_route_cmd_vtysh, + "show bgp ipv6 X:X::X:X", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Network in the BGP routing table to display\n") + +DEFSH (VTYSH_ZEBRA, no_bandwidth_if_cmd_vtysh, + "no bandwidth", + "Negate a command or set its defaults\n" + "Set bandwidth informational parameter\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_standard_any_cmd_vtysh, + "access-list (<1-99>|<1300-1999>) (deny|permit) any", + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any source host\n") + +DEFSH (VTYSH_BGPD, no_match_ipv6_next_hop_cmd_vtysh, + "no match ipv6 next-hop X:X::X:X", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IPv6 information\n" + "Match IPv6 next-hop address of route\n" + "IPv6 address of next hop\n") + +DEFSH (VTYSH_BGPD, clear_bgp_external_out_cmd_vtysh, + "clear bgp external out", + "Reset functions\n" + "BGP information\n" + "Clear all external peers\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_message_sendrecv_cmd_vtysh, + "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 message\n" + "Debug Unknown message\n" + "Debug Hello message\n" + "Debug Database Description message\n" + "Debug Link State Request message\n" + "Debug Link State Update message\n" + "Debug Link State Acknowledgement message\n" + "Debug All message\n" + "Debug only sending message\n" + "Debug only receiving message\n" + ) + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ip_prefix_list_seq_le_cmd_vtysh, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>", + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_instance_summary_cmd_vtysh, + "show ip bgp view WORD summary", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "View name\n" + "Summary of BGP neighbor status\n") + +DEFSH (VTYSH_BGPD, no_bgp_graceful_restart_stalepath_time_val_cmd_vtysh, + "no bgp graceful-restart stalepath-time <1-3600>", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Graceful restart capability parameters\n" + "Set the max time to hold onto restarting peer's stale paths\n" + "Delay value (seconds)\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_kernel_metric_routemap_cmd_vtysh, + "redistribute kernel metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, no_bgp_distance_source_cmd_vtysh, + "no distance <1-255> A.B.C.D/M", + "Negate a command or set its defaults\n" + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n") + +DEFSH (VTYSH_OSPF6D, no_ospf6_redistribute_cmd_vtysh, + "no redistribute (static|kernel|connected|ripng|bgp)", + "Negate a command or set its defaults\n" + "Redistribute\n" + "Static route\n" + "Kernel route\n" + "Connected route\n" + "RIPng route\n" + "BGP route\n" + ) + +DEFSH (VTYSH_RIPNGD, ripng_aggregate_address_cmd_vtysh, + "aggregate-address X:X::X:X/M", + "Set aggregate RIPng route announcement\n" + "Aggregate network\n") + +DEFSH (VTYSH_RIPD, send_lifetime_duration_month_day_cmd_vtysh, + "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ip_prefix_list_ge_cmd_vtysh, + "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>", + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_dampening_cmd_vtysh, + "clear ip bgp dampening", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear route flap dampening information\n") + +DEFSH (VTYSH_BGPD, neighbor_maximum_prefix_threshold_warning_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> <1-100> warning-only", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Threshold value (%) at which to generate a warning msg\n" + "Only give warning message when limit is exceeded\n") + +DEFSH (VTYSH_RIPNGD, debug_ripng_zebra_cmd_vtysh, + "debug ripng zebra", + "Debugging functions (see also 'undebug')\n" + "RIPng configuration\n" + "Debug option set for ripng and zebra communication\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_community_cmd_vtysh, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_OSPF6D, no_ospf6_interface_area_cmd_vtysh, + "no interface IFNAME area A.B.C.D", + "Negate a command or set its defaults\n" + "Disable routing on an IPv6 interface\n" + "Interface name(e.g. ep0)\n" + "Specify the OSPF6 area ID\n" + "OSPF6 area ID in IPv4 address notation\n" + ) + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_cmd_vtysh, + "no redistribute static", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Static routes\n") + +DEFSH (VTYSH_BGPD, show_bgp_community3_cmd_vtysh, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_all_cmd_vtysh, + "show ipv6 bgp community", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes matching the communities\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_next_hop_prefix_list_val_cmd_vtysh, + "no match ip next-hop prefix-list WORD", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IP information\n" + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") + +DEFSH (VTYSH_BGPD, no_neighbor_local_as_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Specify a local-as number\n") + +DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_cmd_vtysh, + "redistribute (connected|kernel|ospf6|ripng|static)", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n") + +DEFSH (VTYSH_OSPFD, ospf_network_cmd_vtysh, + "ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", + "OSPF interface commands\n" + "Network type\n" + "Specify OSPF broadcast multi-access network\n" + "Specify OSPF NBMA network\n" + "Specify OSPF point-to-multipoint network\n" + "Specify OSPF point-to-point network\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_BGPD, no_set_metric_cmd_vtysh, + "no set metric", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "Metric value for destination routing protocol\n") + +DEFSH (VTYSH_BGPD, show_ip_as_path_access_list_all_cmd_vtysh, + "show ip as-path-access-list", + "Show running system information\n" + "IP information\n" + "List AS path access lists\n") + +DEFSH (VTYSH_BGPD, set_ip_nexthop_bgp_cmd_vtysh, + "set ip next-hop peer-address", + "Set values in destination routing protocol\n" + "IP information\n" + "Next hop address\n" + "Use peer address (for BGP only)\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_filter_list_cmd_vtysh, + "show ip bgp filter-list WORD", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") + +DEFSH (VTYSH_RIPNGD, no_ipv6_distribute_list_prefix_cmd_vtysh, + "no distribute-list prefix WORD (in|out) WORD", + "Negate a command or set its defaults\n" + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_BGPD, neighbor_transport_connection_mode_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "transport connection-mode (active|passive)", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Transport options\n" + "Specify passive or active connection\n" + "Actively establish the TCP session\n" + "Passively establish the TCP session\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_prefix_list_seq_ge_cmd_vtysh, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>", + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_BGPD, no_bgp_timers_cmd_vtysh, + "no timers bgp", + "Negate a command or set its defaults\n" + "Adjust routing timers\n" + "BGP timers\n") + +DEFSH (VTYSH_BGPD, no_bgp_enforce_first_as_cmd_vtysh, + "no bgp enforce-first-as", + "Negate a command or set its defaults\n" + "BGP information\n" + "Enforce the first AS for EBGP routes(default)\n") + +DEFSH (VTYSH_RIPD, no_ip_rip_authentication_mode_cmd_vtysh, + "no ip rip authentication mode", + "Negate a command or set its defaults\n" + "IP information\n" + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication mode\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_cmd_vtysh, + "distance ospf intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") + +DEFSH (VTYSH_BGPD, match_ipv6_address_cmd_vtysh, + "match ipv6 address WORD", + "Match values from routing table\n" + "IPv6 information\n" + "Match IPv6 address of route\n" + "IPv6 access-list name\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_static_cmd_vtysh, + "redistribute static", + "Redistribute information from another routing protocol\n" + "Static routes\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_soft_in_cmd_vtysh, + "clear ip bgp * soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_ZEBRA, ip_route_mask_distance_cmd_vtysh, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>", + "IP information\n" + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_metric_routemap_cmd_vtysh, + "no redistribute ospf6 metric <0-16> route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_RIPD, no_router_rip_cmd_vtysh, + "no router rip", + "Negate a command or set its defaults\n" + "Enable a routing process\n" + "Routing Information Protocol (RIP)\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_prefix_list_summary_name_cmd_vtysh, + "show ip prefix-list summary WORD", + "Show running system information\n" + "IP information\n" + "Build a prefix list\n" + "Summary of prefix lists\n" + "Name of a prefix list\n") + +DEFSH (VTYSH_BGPD, clear_bgp_all_cmd_vtysh, + "clear bgp *", + "Reset functions\n" + "BGP information\n" + "Clear all peers\n") + +DEFSH (VTYSH_BGPD, no_neighbor_strict_capability_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X) " "strict-capability-match", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Strict capability negotiation match\n") + +DEFSH (VTYSH_OSPFD, no_ospf_refresh_timer_cmd_vtysh, + "no refresh timer", + "Adjust refresh parameters\n" + "Unset refresh timer\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_community2_cmd_vtysh, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD, no_set_metric_val_cmd_vtysh, + "no set metric <0-4294967295>", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "Metric value for destination routing protocol\n" + "Metric value\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_in_cmd_vtysh, + "clear ip bgp * in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_out_cmd_vtysh, + "clear ip bgp peer-group WORD out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, neighbor_activate_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "activate", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Enable the Address Family for this Neighbor\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_flap_route_map_cmd_vtysh, + "show ip bgp flap-statistics route-map WORD", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display flap statistics of routes\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") + +DEFSH (VTYSH_OSPF6D|VTYSH_BGPD, no_match_ipv6_address_prefix_list_cmd_vtysh, + "no match ipv6 address prefix-list WORD", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IPv6 information\n" + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_access_list_any_cmd_vtysh, + "no ipv6 access-list WORD (deny|permit) any", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any prefixi to match\n") + +DEFSH (VTYSH_ZEBRA, ipv6_nd_reachable_time_cmd_vtysh, + "ipv6 nd reachable-time MILLISECONDS", + "IP information\n" + "Neighbor discovery\n" + "Reachable time\n" + "Reachable time in milliseconds\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_prefix_list_ge_le_cmd_vtysh, + "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_BGPD, aggregate_address_mask_cmd_vtysh, + "aggregate-address A.B.C.D A.B.C.D", + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n") + +DEFSH (VTYSH_BGPD, no_set_ip_nexthop_val_bgp_cmd_vtysh, + "no set ip next-hop peer-address", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "IP information\n" + "Next hop address\n" + "Use peer address (for BGP only)\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_static_metric_cmd_vtysh, + "redistribute static metric <0-16>", + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n" + "Metric value\n") + +DEFSH (VTYSH_OSPFD, no_ospf_compatible_rfc1583_cmd_vtysh, + "no compatible rfc1583", + "Negate a command or set its defaults\n" + "OSPF compatibility list\n" + "compatible with RFC 1583\n") + +DEFSH (VTYSH_OSPFD, debug_ospf_ism_cmd_vtysh, + "debug ospf ism", + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Interface State Machine\n") + +DEFSH (VTYSH_RIPD, rip_split_horizon_cmd_vtysh, + "ip split-horizon", + "IP information\n" + "Perform split horizon\n") + +DEFSH (VTYSH_BGPD, no_ip_community_list_expanded_all_cmd_vtysh, + "no ip community-list <100-500>", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a community list entry\n" + "Community list number (expanded)\n") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_spf_process_cmd_vtysh, + "no debug ospf6 spf process", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Quit Debugging SPF Calculation\n" + "Quit Debugging Detailed SPF Process\n" + ) + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_list_exact_cmd_vtysh, + "show ipv6 mbgp community-list WORD exact-match", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes matching the community-list\n" + "community-list name\n" + "Exact match of the communities\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_routemap_cmd_vtysh, + "default-information originate always route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_soft_cmd_vtysh, + "clear bgp ipv6 external soft", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all external peers\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, no_ip_community_list_standard_all_cmd_vtysh, + "no ip community-list <1-99>", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a community list entry\n" + "Community list number (standard)\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ip_prefix_list_sequence_number_cmd_vtysh, + "ip prefix-list sequence-number", + "IP information\n" + "Build a prefix list\n" + "Include/exclude sequence numbers in NVGEN\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_hello_interval_cmd_vtysh, + "no ip ospf hello-interval", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Time between HELLO packets\n") + +DEFSH (VTYSH_BGPD, show_bgp_neighbor_received_routes_cmd_vtysh, + "show bgp neighbors (A.B.C.D|X:X::X:X) received-routes", + "Show running system information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_cost_cmd_vtysh, + "no ip ospf cost", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Interface cost\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_community4_cmd_vtysh, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, no_match_ecommunity_cmd_vtysh, + "no match extcommunity", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "Match BGP/VPN extended community list\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_seq_ge_le_cmd_vtysh, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_BGPD, clear_bgp_peer_group_soft_in_cmd_vtysh, + "clear bgp peer-group WORD soft in", + "Reset functions\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, no_aggregate_address_as_set_cmd_vtysh, + "no aggregate-address A.B.C.D/M as-set", + "Negate a command or set its defaults\n" + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Generate AS set path information\n") + +DEFSH (VTYSH_OSPF6D, no_ipv6_ospf6_ifmtu_cmd_vtysh, + "no ipv6 ospf6 ifmtu", + "Negate a command or set its defaults\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Interface MTU\n" + ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_soft_out_cmd_vtysh, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, no_set_local_pref_cmd_vtysh, + "no set local-preference", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP local preference path attribute\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_route_detail_cmd_vtysh, + "show ipv6 ospf6 route (X:X::X:X|X:X::X:X/M|detail|summary)", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Routing Table\n" + "Specify IPv6 address\n" + "Specify IPv6 prefix\n" + "Detailed information\n" + "Summary of route table\n" + ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd_vtysh, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in prefix-filter", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out the existing ORF prefix-list\n") + +DEFSH (VTYSH_BGPD, old_no_ipv6_bgp_network_cmd_vtysh, + "no ipv6 bgp network X:X::X:X/M", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "BGP information\n" + "Specify a network to announce via BGP\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") + +DEFSH (VTYSH_ZEBRA, ipv6_nd_send_ra_cmd_vtysh, + "ipv6 nd send-ra", + "IP information\n" + "Neighbor discovery\n" + "Send Router Advertisement\n") + +DEFSH (VTYSH_BGPD, debug_bgp_normal_cmd_vtysh, + "debug bgp", + "Debugging functions (see also 'undebug')\n" + "BGP information\n" ) + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_metric_routemap_cmd_vtysh, + "no redistribute static metric <0-16> route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_ZEBRA, no_bandwidth_if_val_cmd_vtysh, + "no bandwidth <1-10000000>", + "Negate a command or set its defaults\n" + "Set bandwidth informational parameter\n" + "Bandwidth in kilobits\n") + +DEFSH (VTYSH_BGPD, no_bgp_router_id_val_cmd_vtysh, + "no bgp router-id A.B.C.D", + "Negate a command or set its defaults\n" + "BGP information\n" + "Override configured router identifier\n" + "Manually configured router identifier\n") + +DEFSH (VTYSH_RIPD, no_rip_offset_list_cmd_vtysh, + "no offset-list WORD (in|out) <0-16>", + "Negate a command or set its defaults\n" + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n") + +DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_detail_all_cmd_vtysh, + "show ip ospf neighbor detail all", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Neighbor list\n" + "detail of all neighbors\n" + "include down status neighbor\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_prefix_cmd_vtysh, + "show bgp ipv6 X:X::X:X/M", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "IPv6 prefix /\n") + +DEFSH (VTYSH_BGPD, no_dump_bgp_routes_cmd_vtysh, + "no dump bgp routes-mrt [PATH] [INTERVAL]", + "Negate a command or set its defaults\n" + "Dump packet\n" + "BGP packet dump\n" + "Dump whole BGP routing table\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_external_cmd_vtysh, + "distance ospf inter-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n") + +DEFSH (VTYSH_OSPFD, debug_ospf_event_cmd_vtysh, + "debug ospf event", + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF event information\n") + +DEFSH (VTYSH_OSPFD, no_ospf_retransmit_interval_cmd_vtysh, + "no ospf retransmit-interval", + "Negate a command or set its defaults\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n") + +DEFSH (VTYSH_BGPD, set_community_none_cmd_vtysh, + "set community none", + "Set values in destination routing protocol\n" + "BGP community attribute\n" + "No community attribute\n") + +DEFSH (VTYSH_BGPD, debug_bgp_filter_cmd_vtysh, + "debug bgp filters", + "Debugging functions (see also 'undebug')\n" + "BGP information\n" + "BGP filters\n") + +DEFSH (VTYSH_OSPF6D, ospf6_routemap_set_forwarding_cmd_vtysh, + "set forwarding-address X:X::X:X", + "Set value\n" + "Forwarding Address\n" + "IPv6 Address\n") + +DEFSH (VTYSH_BGPD, neighbor_maximum_prefix_restart_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> restart <1-65535>", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Restart bgp connection after limit is exceeded\n" + "Restart interval in minutes") + +DEFSH (VTYSH_BGPD, no_bgp_bestpath_compare_router_id_cmd_vtysh, + "no bgp bestpath compare-routerid", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Change the default bestpath selection\n" + "Compare router-id for identical EBGP paths\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_address_val_cmd_vtysh, + "no match ip address (<1-199>|<1300-2699>|WORD)", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IP information\n" + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") + +DEFSH (VTYSH_ZEBRA, bandwidth_if_cmd_vtysh, + "bandwidth <1-10000000>", + "Set bandwidth informational parameter\n" + "Bandwidth in kilobits\n") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_neighbor_detail_cmd_vtysh, + "no debug ospf6 neighbor (state|event)", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 Neighbor\n" + "Debug OSPFv3 Neighbor State Change\n" + "Debug OSPFv3 Neighbor Event\n" + ) + +DEFSH (VTYSH_OSPFD, ospf_default_metric_cmd_vtysh, + "default-metric <0-16777214>", + "Set metric of redistributed routes\n" + "Default metric\n") + +DEFSH (VTYSH_BGPD, no_neighbor_allowas_in_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "allowas-in", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "allow local ASN appears in aspath attribute\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_default_metric_cmd_vtysh, + "no default-metric", + "Negate a command or set its defaults\n" + "Set a metric of redistribute routes\n" + "Default metric\n") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_zebra_sendrecv_cmd_vtysh, + "no debug ospf6 zebra (send|recv)", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug connection between zebra\n" + "Debug Sending zebra\n" + "Debug Receiving zebra\n" + ) + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_area_spf_tree_cmd_vtysh, + "show ipv6 ospf6 area A.B.C.D spf tree", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Area information\n" + "Area ID (as an IPv4 notation)\n" + "Shortest Path First caculation\n" + "Show SPF tree\n") + +DEFSH (VTYSH_BGPD, bgp_damp_unset2_cmd_vtysh, + "no bgp dampening <1-45> <1-20000> <1-20000> <1-255>", + "Negate a command or set its defaults\n" + "BGP Specific commands\n" + "Enable route-flap dampening\n" + "Half-life time for the penalty\n" + "Value to start reusing a route\n" + "Value to start suppressing a route\n" + "Maximum duration to suppress a stable route\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_authentication_key_addr_cmd_vtysh, + "ip ospf authentication-key AUTH_KEY A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Authentication password (key)\n" + "The OSPF password (key)\n" + "Address of interface") + +DEFSH (VTYSH_RIPD, ip_rip_send_version_2_cmd_vtysh, + "ip rip send version 2 1", + "IP information\n" + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "RIP version 2\n" + "RIP version 1\n") + +DEFSH (VTYSH_ZEBRA, ipv6_route_ifname_cmd_vtysh, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE", + "IP information\n" + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n") + +DEFSH (VTYSH_BGPD, show_bgp_community_all_cmd_vtysh, + "show bgp community", + "Show running system information\n" + "BGP information\n" + "Display routes matching the communities\n") + +DEFSH (VTYSH_BGPD, neighbor_port_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X) " "port <0-65535>", + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Neighbor's BGP port\n" + "TCP port number\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_dampening_prefix_cmd_vtysh, + "clear ip bgp dampening A.B.C.D/M", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear route flap dampening information\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_RIPNGD, no_ipv6_distribute_list_all_cmd_vtysh, + "no distribute-list WORD (in|out)", + "Negate a command or set its defaults\n" + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_soft_out_cmd_vtysh, + "clear bgp ipv6 * soft out", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_border_routers_cmd_vtysh, + "show ipv6 ospf6 border-routers", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Display routing table for ABR and ASBR\n" + ) + +DEFSH (VTYSH_BGPD, show_ip_community_list_cmd_vtysh, + "show ip community-list", + "Show running system information\n" + "IP information\n" + "List community-list\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_mask_host_cmd_vtysh, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "A single destination host\n" + "Destination address\n") + +DEFSH (VTYSH_ZEBRA, ipv6_nd_ra_lifetime_cmd_vtysh, + "ipv6 nd ra-lifetime SECONDS", + "IP information\n" + "Neighbor discovery\n" + "Router lifetime\n" + "Router lifetime in seconds\n") + +DEFSH (VTYSH_BGPD, set_ecommunity_soo_cmd_vtysh, + "set extcommunity soo .ASN:nn_or_IP-address:nn", + "Set values in destination routing protocol\n" + "BGP extended community attribute\n" + "Site-of-Origin extended community\n" + "VPN extended community\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_community4_exact_cmd_vtysh, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, no_set_originator_id_cmd_vtysh, + "no set originator-id", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP originator ID attribute\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_prefix_list_prefix_cmd_vtysh, + "show ip prefix-list WORD A.B.C.D/M", + "Show running system information\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_RIPD, send_lifetime_infinite_day_month_cmd_vtysh, + "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Never expires") + +DEFSH (VTYSH_BGPD, no_neighbor_description_val_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "description .LINE", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Neighbor specific description\n" + "Up to 80 characters describing this neighbor\n") + +DEFSH (VTYSH_ZEBRA, ipv6_nd_suppress_ra_cmd_vtysh, + "ipv6 nd suppress-ra", + "IP information\n" + "Neighbor discovery\n" + "Suppress Router Advertisement\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_vlink_authtype_authkey_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) " + "(authentication-key|)", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Enable authentication on this virtual link\n" "dummy string \n" + "Authentication password (key)\n" "The OSPF password (key)" ) + +DEFSH (VTYSH_BGPD, no_neighbor_default_originate_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "default-originate", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Originate default route to this neighbor\n") + +DEFSH (VTYSH_RIPD, no_rip_passive_interface_cmd_vtysh, + "no passive-interface IFNAME", + "Negate a command or set its defaults\n" + "Suppress routing updates on an interface\n" + "Interface name\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_remark_arg_cmd_vtysh, + "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list\n" + "Access list entry comment\n" + "Comment up to 100 characters\n") + +DEFSH (VTYSH_BGPD, aggregate_address_as_set_cmd_vtysh, + "aggregate-address A.B.C.D/M as-set", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Generate AS set path information\n") + +DEFSH (VTYSH_BGPD, no_neighbor_send_community_type_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community (both|extended|standard)", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Send Community attribute to this neighbor\n" + "Send Standard and Extended Community attributes\n" + "Send Extended Community attributes\n" + "Send Standard Community attributes\n") + +DEFSH (VTYSH_OSPFD, ospf_hello_interval_cmd_vtysh, + "ospf hello-interval <1-65535>", + "OSPF interface commands\n" + "Time between HELLO packets\n" + "Seconds\n") + +DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_all_cmd_vtysh, + "show ip ospf neighbor all", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Neighbor list\n" + "include down status neighbor\n") + +DEFSH (VTYSH_OSPF6D, ipv6_ospf6_cost_cmd_vtysh, + "ipv6 ospf6 cost <1-65535>", + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Interface cost\n" + "Outgoing metric of this interface\n" + ) + +DEFSH (VTYSH_OSPFD, ospf_area_vlink_md5_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(message-digest-key|) <1-255> md5 KEY", + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)" ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_external_out_cmd_vtysh, + "clear ip bgp external out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all external peers\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD, match_interface_cmd_vtysh, + "match interface WORD", + "Match values from routing table\n" + "Match first hop interface of route\n" + "Interface name\n") + +DEFSH (VTYSH_ZEBRA, debug_zebra_kernel_cmd_vtysh, + "debug zebra kernel", + "Debugging functions (see also 'undebug')\n" + "Zebra configuration\n" + "Debug option set for zebra between kernel interface\n") + +DEFSH (VTYSH_BGPD, no_aggregate_address_cmd_vtysh, + "no aggregate-address A.B.C.D/M", + "Negate a command or set its defaults\n" + "Configure BGP aggregate entries\n" + "Aggregate prefix\n") + +DEFSH (VTYSH_ZEBRA, show_ipv6_forwarding_cmd_vtysh, + "show ipv6 forwarding", + "Show running system information\n" + "IPv6 information\n" + "Forwarding status\n") + +DEFSH (VTYSH_ZEBRA, no_ipv6_nd_prefix_advertisement_cmd_vtysh, + "no ipv6 nd prefix-advertisement IPV6PREFIX", + "Negate a command or set its defaults\n" + "IP information\n" + "Neighbor discovery\n" + "Prefix information\n" + "IPv6 prefix\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_source_cmd_vtysh, + "distance <1-255> A.B.C.D/M", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") + +DEFSH (VTYSH_OSPF6D, ipv6_ospf6_instance_cmd_vtysh, + "ipv6 ospf6 instance-id <0-255>", + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Instance ID for this interface\n" + "Instance ID value\n" + ) + +DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_rmap_metric_cmd_vtysh, + "redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n" + "Metric for redistributed routes\n" + "Default metric\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_stub_no_summary_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) stub no-summary", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as stub\n" + "Do not inject inter-area routes into area\n") + +DEFSH (VTYSH_BGPD, no_aggregate_address_as_set_summary_cmd_vtysh, + "no aggregate-address A.B.C.D/M as-set summary-only", + "Negate a command or set its defaults\n" + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Generate AS set path information\n" + "Filter more specific routes from updates\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_authentication_args_addr_cmd_vtysh, + "ip ospf authentication (null|message-digest) A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n" + "Use null authentication\n" + "Use message-digest authentication\n" + "Address of interface") + +DEFSH (VTYSH_BGPD, no_neighbor_capability_dynamic_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "capability dynamic", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Advertise capability to the peer\n" + "Advertise dynamic capability to this neighbor\n") + +DEFSH (VTYSH_OSPFD, ospf_retransmit_interval_cmd_vtysh, + "ospf retransmit-interval <3-65535>", + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n" + "Seconds\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_soft_in_cmd_vtysh, + "clear bgp ipv6 peer-group WORD soft in", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, bgp_confederation_identifier_cmd_vtysh, + "bgp confederation identifier <1-65535>", + "BGP specific commands\n" + "AS confederation parameters\n" + "AS number\n" + "Set routing domain confederation AS\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_soft_cmd_vtysh, + "clear ip bgp <1-65535> vpnv4 unicast soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged4_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med (as-path|next-hop)", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "As-path attribute\n" + "Nexthop attribute\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_in_prefix_filter_cmd_vtysh, + "clear bgp ipv6 peer-group WORD in prefix-filter", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_OSPFD, no_debug_ospf_nsm_cmd_vtysh, + "no debug ospf nsm", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Neighbor State Machine") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_ipv4_soft_out_cmd_vtysh, + "clear ip bgp view WORD * ipv4 (unicast|multicast) soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_ZEBRA, ip_route_mask_cmd_vtysh, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)", + "IP information\n" + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n") + +DEFSH (VTYSH_BGPD, no_match_ipv6_address_cmd_vtysh, + "no match ipv6 address WORD", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IPv6 information\n" + "Match IPv6 address of route\n" + "IPv6 access-list name\n") + +DEFSH (VTYSH_BGPD, bgp_damp_set_cmd_vtysh, + "bgp dampening <1-45> <1-20000> <1-20000> <1-255>", + "BGP Specific commands\n" + "Enable route-flap dampening\n" + "Half-life time for the penalty\n" + "Value to start reusing a route\n" + "Value to start suppressing a route\n" + "Maximum duration to suppress a stable route\n") + +DEFSH (VTYSH_BGPD, no_bgp_timers_arg_cmd_vtysh, + "no timers bgp <0-65535> <0-65535>", + "Negate a command or set its defaults\n" + "Adjust routing timers\n" + "BGP timers\n" + "Keepalive interval\n" + "Holdtime\n") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_message_cmd_vtysh, + "no debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 message\n" + "Debug Unknown message\n" + "Debug Hello message\n" + "Debug Database Description message\n" + "Debug Link State Request message\n" + "Debug Link State Update message\n" + "Debug Link State Acknowledgement message\n" + "Debug All message\n" + ) + +DEFSH (VTYSH_RIPD, send_lifetime_month_day_month_day_cmd_vtysh, + "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") + +DEFSH (VTYSH_BGPD, show_bgp_community4_exact_cmd_vtysh, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, no_neighbor_maximum_prefix_val_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295>", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_external_inter_cmd_vtysh, + "distance ospf intra-area <1-255> external <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "External routes\n" + "Distance for external routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") + +DEFSH (VTYSH_BGPD, no_set_atomic_aggregate_cmd_vtysh, + "no set atomic-aggregate", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP atomic aggregate attribute\n" ) + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_cmd_vtysh, + "clear bgp ipv6 external", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all external peers\n") + +DEFSH (VTYSH_OSPFD, ospf_neighbor_priority_poll_interval_cmd_vtysh, + "neighbor A.B.C.D priority <0-255> poll-interval <1-65535>", + "Specify neighbor router\n" + "Neighbor IP address\n" + "Neighbor Priority\n" + "Priority\n" + "Dead Neighbor Polling interval\n" + "Seconds\n") + +DEFSH (VTYSH_RIPNGD, ipv6_distribute_list_all_cmd_vtysh, + "distribute-list WORD (in|out)", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_neighbor_cmd_vtysh, + "debug ospf6 neighbor", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 Neighbor\n" + ) + +DEFSH (VTYSH_BGPD, bgp_bestpath_aspath_ignore_cmd_vtysh, + "bgp bestpath as-path ignore", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "AS-path attribute\n" + "Ignore as-path length in selecting a route\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_dampening_address_cmd_vtysh, + "clear ip bgp dampening A.B.C.D", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear route flap dampening information\n" + "Network to clear damping information\n") + +DEFSH (VTYSH_OSPFD, ospf_area_stub_no_summary_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) stub no-summary", + "OSPF stub parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as stub\n" + "Do not inject inter-area routes into stub\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_kernel_metric_cmd_vtysh, + "redistribute kernel metric <0-16>", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n" + "Metric value\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_any_any_cmd_vtysh, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any any", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "Any destination host\n") + +DEFSH (VTYSH_BGPD, bgp_bestpath_med_cmd_vtysh, + "bgp bestpath med (confed|missing-as-worst)", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Compare MED among confederation paths\n" + "Treat missing MED as the least preferred one\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_all_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) community", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_in_prefix_filter_cmd_vtysh, + "clear ip bgp peer-group WORD in prefix-filter", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_cmd_vtysh, + "show ipv6 mbgp", + "Show running system information\n" + "IP information\n" + "MBGP information\n" ) + +DEFSH (VTYSH_BGPD, no_neighbor_unsuppress_map_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "unsuppress-map WORD", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Route-map to selectively unsuppress suppressed routes\n" + "Name of route map\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_routemap_cmd_vtysh, + "no redistribute ospf6 route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_vlink_param4_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" ) + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_prefix_list_summary_cmd_vtysh, + "show ip prefix-list summary", + "Show running system information\n" + "IP information\n" + "Build a prefix list\n" + "Summary of prefix lists\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, show_ipv6_prefix_list_summary_name_cmd_vtysh, + "show ipv6 prefix-list summary WORD", + "Show running system information\n" + "IPv6 information\n" + "Build a prefix list\n" + "Summary of prefix lists\n" + "Name of a prefix list\n") + +DEFSH (VTYSH_BGPD, set_aggregator_as_cmd_vtysh, + "set aggregator as <1-65535> A.B.C.D", + "Set values in destination routing protocol\n" + "BGP aggregator attribute\n" + "AS number of aggregator\n" + "AS number\n" + "IP address of aggregator\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, match_ip_address_prefix_list_cmd_vtysh, + "match ip address prefix-list WORD", + "Match values from routing table\n" + "IP information\n" + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") + +DEFSH (VTYSH_BGPD, no_bgp_network_mask_backdoor_cmd_vtysh, + "no network A.B.C.D mask A.B.C.D backdoor", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Specify a BGP backdoor route\n") + +DEFSH (VTYSH_BGPD, no_match_origin_val_cmd_vtysh, + "no match origin (egp|igp|incomplete)", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "BGP origin code\n" + "remote EGP\n" + "local IGP\n" + "unknown heritage\n") + +DEFSH (VTYSH_RIPD, rip_network_cmd_vtysh, + "network (A.B.C.D/M|WORD)", + "Enable routing on an IP network\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Interface name\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_cost_cmd_vtysh, + "ip ospf cost <1-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Interface cost\n" + "Cost") + +DEFSH (VTYSH_BGPD, ipv6_aggregate_address_cmd_vtysh, + "aggregate-address X:X::X:X/M", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n") + +DEFSH (VTYSH_BGPD, clear_bgp_as_cmd_vtysh, + "clear bgp <1-65535>", + "Reset functions\n" + "BGP information\n" + "Clear peers with the AS number\n") + +DEFSH (VTYSH_BGPD, no_neighbor_disable_connected_check_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "disable-connected-check", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "one-hop away EBGP peer using loopback address\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_intra_inter_cmd_vtysh, + "distance ospf external <1-255> intra-area <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") + +DEFSH (VTYSH_OSPFD, ospf_cost_cmd_vtysh, + "ospf cost <1-65535>", + "OSPF interface commands\n" + "Interface cost\n" + "Cost") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_seq_cmd_vtysh, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Any prefix match. Same as \"::0/0 le 128\"\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_type_metric_routemap_cmd_vtysh, + "default-information originate metric-type (1|2) metric <0-16777214> route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "OSPF default metric\n" + "OSPF metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_prefix_cmd_vtysh, + "show ipv6 mbgp X:X::X:X/M", + "Show running system information\n" + "IP information\n" + "MBGP information\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") + +DEFSH (VTYSH_ZEBRA, no_ipv6_nd_other_config_flag_cmd_vtysh, + "no ipv6 nd other-config-flag", + "Negate a command or set its defaults\n" + "IP information\n" + "Neighbor discovery\n" + "Other statefull configuration flag\n") + +DEFSH (VTYSH_RIPD, no_key_cmd_vtysh, + "no key <0-2147483647>", + "Negate a command or set its defaults\n" + "Delete a key\n" + "Key identifier number\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_interface_cmd_vtysh, + "debug ospf6 interface", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 Interface\n" + ) + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_ge_cmd_vtysh, + "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_BGPD, neighbor_attr_unchanged4_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med (as-path|next-hop)", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "As-path attribute\n" + "Nexthop attribute\n") + +DEFSH (VTYSH_OSPFD, ospf_area_vlink_authkey_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication-key|) AUTH_KEY", + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Authentication password (key)\n" "The OSPF password (key)" ) + +DEFSH (VTYSH_RIPNGD, no_debug_ripng_zebra_cmd_vtysh, + "no debug ripng zebra", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "RIPng configuration\n" + "Debug option set for ripng and zebra communication\n") + +DEFSH (VTYSH_BGPD, no_neighbor_weight_val_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "weight <0-65535>", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Set default weight for routes from this neighbor\n" + "default weight\n") + +DEFSH (VTYSH_RIPD, no_rip_default_information_originate_cmd_vtysh, + "no default-information originate", + "Negate a command or set its defaults\n" + "Control distribution of default route\n" + "Distribute a default route\n") + +DEFSH (VTYSH_OSPFD, ospf_area_vlink_authtype_args_md5_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) (message-digest|null) " + "(message-digest-key|) <1-255> md5 KEY", + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Enable authentication on this virtual link\n" "dummy string \n" "Use null authentication\n" "Use message-digest authentication\n" + "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)" ) + +DEFSH (VTYSH_BGPD, clear_bgp_as_in_cmd_vtysh, + "clear bgp <1-65535> in", + "Reset functions\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, match_community_exact_cmd_vtysh, + "match community (<1-99>|<100-500>|WORD) exact-match", + "Match values from routing table\n" + "Match BGP community list\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n" + "Do exact matching of communities\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_any_host_cmd_vtysh, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "A single destination host\n" + "Destination address\n") + +DEFSH (VTYSH_BGPD, ipv6_bgp_network_cmd_vtysh, + "network X:X::X:X/M", + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n") + +DEFSH (VTYSH_BGPD, bgp_fast_external_failover_cmd_vtysh, + "bgp fast-external-failover", + "BGP information\n" + "Immediately reset session if a link to a directly connected external peer goes down\n") + +DEFSH (VTYSH_ZEBRA, ip_route_distance_cmd_vtysh, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>", + "IP information\n" + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_prefix_list_cmd_vtysh, + "show ipv6 mbgp prefix-list WORD", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes matching the prefix-list\n" + "IPv6 prefix-list name\n") + +DEFSH (VTYSH_BGPD, bgp_network_mask_cmd_vtysh, + "network A.B.C.D mask A.B.C.D", + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n") + +DEFSH (VTYSH_BGPD, show_bgp_cmd_vtysh, + "show bgp", + "Show running system information\n" + "BGP information\n" ) + +DEFSH (VTYSH_OSPFD, ospf_area_default_cost_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Set the summary-default cost of a NSSA or stub area\n" + "Stub's advertised default summary cost\n") + +DEFSH (VTYSH_BGPD, bgp_network_mask_backdoor_cmd_vtysh, + "network A.B.C.D mask A.B.C.D backdoor", + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Specify a BGP backdoor route\n") + +DEFSH (VTYSH_RIPD, ip_rip_authentication_string_cmd_vtysh, + "ip rip authentication string LINE", + "IP information\n" + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication string\n" + "Authentication string\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_interface_cmd_vtysh, + "show ipv6 ospf6 interface", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Interface infomation\n" + ) + +DEFSH (VTYSH_OSPFD, no_ospf_neighbor_priority_cmd_vtysh, + "no neighbor A.B.C.D priority <0-255>", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor IP address\n" + "Neighbor Priority\n" + "Priority\n") + +DEFSH (VTYSH_BGPD, no_set_community_none_cmd_vtysh, + "no set community none", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP community attribute\n" + "No community attribute\n") + +DEFSH (VTYSH_BGPD, show_ip_as_path_access_list_cmd_vtysh, + "show ip as-path-access-list WORD", + "Show running system information\n" + "IP information\n" + "List AS path access lists\n" + "AS path access list name\n") + +DEFSH (VTYSH_BGPD, show_bgp_instance_summary_cmd_vtysh, + "show bgp view WORD summary", + "Show running system information\n" + "BGP information\n" + "BGP view\n" + "View name\n" + "Summary of BGP neighbor status\n") + +DEFSH (VTYSH_RIPD, distribute_list_prefix_cmd_vtysh, + "distribute-list prefix WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_BGPD, ipv6_bgp_network_route_map_cmd_vtysh, + "network X:X::X:X/M route-map WORD", + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_connected_metric_cmd_vtysh, + "redistribute connected metric <0-16>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n" + "Metric value\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_ge_le_cmd_vtysh, + "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_authentication_addr_cmd_vtysh, + "ip ospf authentication A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n" + "Address of interface") + +DEFSH (VTYSH_OSPFD, ip_ospf_authentication_key_cmd_vtysh, + "ip ospf authentication-key AUTH_KEY", + "IP Information\n" + "OSPF interface commands\n" + "Authentication password (key)\n" + "The OSPF password (key)") + +DEFSH (VTYSH_ZEBRA, ipv6_nd_other_config_flag_cmd_vtysh, + "ipv6 nd other-config-flag", + "IP information\n" + "Neighbor discovery\n" + "Other statefull configuration flag\n") + +DEFSH (VTYSH_BGPD, show_bgp_neighbor_advertised_route_cmd_vtysh, + "show bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", + "Show running system information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, clear_ip_prefix_list_name_prefix_cmd_vtysh, + "clear ip prefix-list WORD A.B.C.D/M", + "Reset functions\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, bgp_client_to_client_reflection_cmd_vtysh, + "bgp client-to-client reflection", + "BGP specific commands\n" + "Configure client to client route reflection\n" + "reflection of routes allowed\n") + +DEFSH (VTYSH_BGPD, clear_bgp_external_soft_in_cmd_vtysh, + "clear bgp external soft in", + "Reset functions\n" + "BGP information\n" + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_RIPD, no_rip_redistribute_type_routemap_cmd_vtysh, + "no redistribute (kernel|connected|static|ospf|bgp) route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, no_aggregate_address_mask_summary_as_set_cmd_vtysh, + "no aggregate-address A.B.C.D A.B.C.D summary-only as-set", + "Negate a command or set its defaults\n" + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Filter more specific routes from updates\n" + "Generate AS set path information\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_tags_cmd_vtysh, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn tags", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Display BGP tags for prefixes\n") + +DEFSH (VTYSH_BGPD, no_set_ecommunity_soo_cmd_vtysh, + "no set extcommunity soo", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP extended community attribute\n" + "Site-of-Origin extended community\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_exact_cmd_vtysh, + "access-list WORD (deny|permit) A.B.C.D/M exact-match", + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n" + "Exact match of the prefixes\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_route_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) A.B.C.D", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Network in the BGP routing table to display\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_cmd_vtysh, + "clear bgp ipv6 *", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all peers\n") + +DEFSH (VTYSH_BGPD, bgp_confederation_peers_cmd_vtysh, + "bgp confederation peers .<1-65535>", + "BGP specific commands\n" + "AS confederation parameters\n" + "Peer ASs in BGP confederation\n" + "AS number\n" ) + +DEFSH (VTYSH_BGPD, no_set_ecommunity_soo_val_cmd_vtysh, + "no set extcommunity soo .ASN:nn_or_IP-address:nn", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP extended community attribute\n" + "Site-of-Origin extended community\n" + "VPN extended community\n") + +DEFSH (VTYSH_OSPFD, ospf_redistribute_source_metric_routemap_cmd_vtysh, + "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Metric for redistributed routes\n" + "OSPF default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_cost_addr_cmd_vtysh, + "ip ospf cost <1-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Interface cost\n" + "Cost\n" + "Address of interface") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_soft_in_cmd_vtysh, + "clear bgp ipv6 external soft in", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_RIPD, show_ip_rip_cmd_vtysh, + "show ip rip", + "Show running system information\n" + "IP information\n" + "Show RIP routes\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_in_cmd_vtysh, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_RIPD, show_debugging_rip_cmd_vtysh, + "show debugging rip", + "Show running system information\n" + "Debugging functions (see also 'undebug')\n" + "RIP information\n" ) + +DEFSH (VTYSH_BGPD, no_bgp_network_mask_route_map_cmd_vtysh, + "no network A.B.C.D mask A.B.C.D route-map WORD", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + +DEFSH (VTYSH_BGPD, set_local_pref_cmd_vtysh, + "set local-preference <0-4294967295>", + "Set values in destination routing protocol\n" + "BGP local preference path attribute\n" + "Preference value\n") + +DEFSH (VTYSH_BGPD, no_neighbor_activate_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "activate", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Enable the Address Family for this Neighbor\n") + +DEFSH (VTYSH_RIPD, no_rip_redistribute_type_metric_cmd_vtysh, + "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16>", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n") + +DEFSH (VTYSH_ZEBRA, no_debug_zebra_kernel_cmd_vtysh, + "no debug zebra kernel", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Zebra configuration\n" + "Debug option set for zebra between kernel interface\n") + +DEFSH (VTYSH_BGPD, no_set_ipv6_nexthop_global_val_cmd_vtysh, + "no set ipv6 next-hop global X:X::X:X", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "IPv6 information\n" + "IPv6 next-hop address\n" + "IPv6 global address\n" + "IPv6 address of next hop\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_soft_in_cmd_vtysh, + "clear bgp ipv6 * soft in", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_OSPFD, ospf_area_range_not_advertise_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M not-advertise", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "DoNotAdvertise this range\n") + +DEFSH (VTYSH_BGPD, show_bgp_community4_cmd_vtysh, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n") + +DEFSH (VTYSH_RIPD, no_rip_split_horizon_cmd_vtysh, + "no ip split-horizon", + "Negate a command or set its defaults\n" + "IP information\n" + "Perform split horizon\n") + +DEFSH (VTYSH_BGPD, neighbor_local_as_no_prepend_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as <1-65535> no-prepend", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Specify a local-as number\n" + "AS number used as local AS\n" + "Do not prepend local-as to updates from ebgp peers\n") + +DEFSH (VTYSH_OSPFD, ospf_redistribute_source_type_routemap_cmd_vtysh, + "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, no_aggregate_address_mask_as_set_cmd_vtysh, + "no aggregate-address A.B.C.D A.B.C.D as-set", + "Negate a command or set its defaults\n" + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Generate AS set path information\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_inter_cmd_vtysh, + "distance ospf external <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") + +DEFSH (VTYSH_RIPD, accept_lifetime_month_day_month_day_cmd_vtysh, + "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") + +DEFSH (VTYSH_BGPD, no_set_originator_id_val_cmd_vtysh, + "no set originator-id A.B.C.D", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP originator ID attribute\n" + "IP address of originator\n") + +DEFSH (VTYSH_OSPFD, ospf_area_range_advertise_cost_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Advertise this range (default)\n" + "User specified metric for this range\n" + "Advertised metric for this range\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_neighbor_routes_cmd_vtysh, + "show ip bgp vpnv4 all neighbors A.B.C.D routes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_metric_routemap_cmd_vtysh, + "no redistribute bgp metric <0-16> route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_routemap_cmd_vtysh, + "default-information originate route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_list_exact_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD) exact-match", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_remark_cmd_vtysh, + "access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE", + "Add an access list entry\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list\n" + "Access list entry comment\n" + "Comment up to 100 characters\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_prefix_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, no_bgp_router_id_cmd_vtysh, + "no bgp router-id", + "Negate a command or set its defaults\n" + "BGP information\n" + "Override configured router identifier\n") + +DEFSH (VTYSH_BGPD, dump_bgp_all_interval_cmd_vtysh, + "dump bgp all PATH INTERVAL", + "Dump packet\n" + "BGP packet dump\n" + "Dump all BGP packets\n" + "Output filename\n" + "Interval of output\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_filter_list_cmd_vtysh, + "show ipv6 mbgp filter-list WORD", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") + +DEFSH (VTYSH_BGPD, dump_bgp_updates_cmd_vtysh, + "dump bgp updates PATH", + "Dump packet\n" + "BGP packet dump\n" + "Dump BGP updates only\n" + "Output filename\n") + +DEFSH (VTYSH_BGPD, no_bgp_network_backdoor_cmd_vtysh, + "no network A.B.C.D/M backdoor", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify a BGP backdoor route\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_in_cmd_vtysh, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, clear_bgp_peer_soft_in_cmd_vtysh, + "clear bgp (A.B.C.D|X:X::X:X) soft in", + "Reset functions\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_OSPF6D, redistribute_ospf6_cmd_vtysh, + "redistribute ospf6", + "Redistribute control\n" + "OSPF6 route\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_seq_ge_le_cmd_vtysh, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_dead_interval_cmd_vtysh, + "no ip ospf dead-interval", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ip_prefix_list_le_cmd_vtysh, + "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>", + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_BGPD, bgp_bestpath_med2_cmd_vtysh, + "bgp bestpath med confed missing-as-worst", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Compare MED among confederation paths\n" + "Treat missing MED as the least preferred one\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_community3_cmd_vtysh, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_in_cmd_vtysh, + "clear bgp ipv6 * in", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all peers\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_OSPFD, no_ospf_passive_interface_cmd_vtysh, + "no passive-interface IFNAME", + "Negate a command or set its defaults\n" + "Allow routing updates on an interface\n" + "Interface's name\n") + +DEFSH (VTYSH_BGPD, ip_extcommunity_list_standard2_cmd_vtysh, + "ip extcommunity-list <1-99> (deny|permit)", + "IP information\n" + "Add a extended community list entry\n" + "Extended Community list number (standard)\n" + "Specify community to reject\n" + "Specify community to accept\n") + +DEFSH (VTYSH_BGPD, neighbor_ebgp_multihop_ttl_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop <1-255>", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Allow EBGP neighbors not on directly connected networks\n" + "maximum hop count\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_flap_prefix_longer_cmd_vtysh, + "show ip bgp flap-statistics A.B.C.D/M longer-prefixes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") + +DEFSH (VTYSH_BGPD, no_neighbor_peer_group_cmd_vtysh, + "no neighbor WORD peer-group", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor tag\n" + "Configure peer-group\n") + +DEFSH (VTYSH_ZEBRA, no_ipv6_route_ifname_cmd_vtysh, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE", + "Negate a command or set its defaults\n" + "IP information\n" + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n") + +DEFSH (VTYSH_BGPD, show_version_bgpd_cmd_vtysh, + "show version bgpd", + "Show running system information\n" + "Displays zebra version\n" + "Displays bgpd version\n") + +DEFSH (VTYSH_RIPD, rip_distance_source_access_list_cmd_vtysh, + "distance <1-255> A.B.C.D/M WORD", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") + +DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_rmap_metric_cmd_vtysh, + "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n" + "Metric for redistributed routes\n" + "Default metric\n") + +DEFSH (VTYSH_OSPF6D, ipv6_ospf6_advertise_prefix_list_cmd_vtysh, + "ipv6 ospf6 advertise prefix-list WORD", + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Advertising options\n" + "Filter prefix using prefix-list\n" + "Prefix list name\n" + ) + +DEFSH (VTYSH_OSPF6D, ipv6_ospf6_transmitdelay_cmd_vtysh, + "ipv6 ospf6 transmit-delay <1-3600>", + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Transmit delay of this interface\n" + "<1-65535> Seconds\n" + ) + +DEFSH (VTYSH_OSPFD, no_ospf_passive_interface_addr_cmd_vtysh, + "no passive-interface IFNAME A.B.C.D", + "Negate a command or set its defaults\n" + "Allow routing updates on an interface\n" + "Interface's name\n") + +DEFSH (VTYSH_BGPD, neighbor_maximum_prefix_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295>", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n") + +DEFSH (VTYSH_BGPD, vpnv4_network_cmd_vtysh, + "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "BGP tag\n" + "tag value\n") + +DEFSH (VTYSH_ZEBRA, show_ipv6_route_addr_cmd_vtysh, + "show ipv6 route X:X::X:X", + "Show running system information\n" + "IP information\n" + "IPv6 routing table\n" + "IPv6 Address\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_neighbors_peer_cmd_vtysh, + "show ip bgp neighbors (A.B.C.D|X:X::X:X)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n") + +DEFSH (VTYSH_OSPFD, debug_ospf_nsm_cmd_vtysh, + "debug ospf nsm", + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Neighbor State Machine\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_message_digest_key_cmd_vtysh, + "ip ospf message-digest-key <1-255> md5 KEY", + "IP Information\n" + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n" + "Use MD5 algorithm\n" + "The OSPF password (key)") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_bgp_metric_routemap_cmd_vtysh, + "redistribute bgp metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, bgp_default_local_preference_cmd_vtysh, + "bgp default local-preference <0-4294967295>", + "BGP specific commands\n" + "Configure BGP defaults\n" + "local preference (higher=more preferred)\n" + "Configure default local preference value\n") + +DEFSH (VTYSH_RIPD, rip_distance_source_cmd_vtysh, + "distance <1-255> A.B.C.D/M", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_prefix_list_seq_le_cmd_vtysh, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>", + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_BGPD, show_bgp_regexp_cmd_vtysh, + "show bgp regexp .LINE", + "Show running system information\n" + "BGP information\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_regexp_cmd_vtysh, + "show ipv6 bgp regexp .LINE", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_priority_cmd_vtysh, + "no ip ospf priority", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Router priority\n") + +DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_set_ip_nexthop_cmd_vtysh, + "no set ip next-hop", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "IP information\n" + "Next hop address\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_dead_interval_addr_cmd_vtysh, + "ip ospf dead-interval <1-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n" + "Seconds\n" + "Address of interface") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, show_ipv6_prefix_list_name_seq_cmd_vtysh, + "show ipv6 prefix-list WORD seq <1-4294967295>", + "Show running system information\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_access_list_cmd_vtysh, + "ipv6 access-list WORD (deny|permit) X:X::X:X/M", + "IPv6 information\n" + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 3ffe:506::/32\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_flooding_cmd_vtysh, + "debug ospf6 flooding", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 flooding function\n" + ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_external_cmd_vtysh, + "clear ip bgp external", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all external peers\n") + +DEFSH (VTYSH_RIPD, no_distribute_list_cmd_vtysh, + "no distribute-list WORD (in|out) WORD", + "Negate a command or set its defaults\n" + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ip_prefix_list_seq_ge_le_cmd_vtysh, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_BGPD, no_set_aspath_prepend_val_cmd_vtysh, + "no set as-path prepend .<1-65535>", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "Prepend string for a BGP AS-path attribute\n" + "Prepend to the as-path\n" + "AS number\n") + +DEFSH (VTYSH_RIPD, no_rip_default_metric_val_cmd_vtysh, + "no default-metric <1-16>", + "Negate a command or set its defaults\n" + "Set a metric of redistribute routes\n" + "Default metric\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_prefix_cmd_vtysh, + "show ip bgp A.B.C.D/M", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, clear_bgp_external_in_cmd_vtysh, + "clear bgp external in", + "Reset functions\n" + "BGP information\n" + "Clear all external peers\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, set_community_delete_cmd_vtysh, + "set comm-list (<1-99>|<100-500>|WORD) delete", + "Set values in destination routing protocol\n" + "set BGP community list (for deletion)\n" + "Community-list number (standard)\n" + "Communitly-list number (expanded)\n" + "Community-list name\n" + "Delete matching communities\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_access_list_name_cmd_vtysh, + "show ip access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)", + "Show running system information\n" + "IP information\n" + "List IP access lists\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_spf_time_cmd_vtysh, + "debug ospf6 spf time", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug SPF Calculation\n" + "Measure time taken by SPF Calculation\n" + ) + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_community3_exact_cmd_vtysh, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_RIPD, rip_redistribute_rip_cmd_vtysh, + "redistribute rip", + "Redistribute information from another routing protocol\n" + "Routing Information Protocol (RIP)\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_passive_interface_cmd_vtysh, + "no passive-interface IFNAME", + "Negate a command or set its defaults\n" + "Suppress routing updates on an interface\n" + "Interface name\n") + +DEFSH (VTYSH_OSPF6D, ipv6_ospf6_hellointerval_cmd_vtysh, + "ipv6 ospf6 hello-interval <1-65535>", + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Interval time of Hello packets\n" + "<1-65535> Seconds\n" + ) + +DEFSH (VTYSH_BGPD, no_bgp_network_mask_natural_backdoor_cmd_vtysh, + "no network A.B.C.D backdoor", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "Network number\n" + "Specify a BGP backdoor route\n") + +DEFSH (VTYSH_ZEBRA, multicast_cmd_vtysh, + "multicast", + "Set multicast flag to interface\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_inter_intra_cmd_vtysh, + "distance ospf external <1-255> inter-area <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") + +DEFSH (VTYSH_RIPD, rip_redistribute_type_cmd_vtysh, + "redistribute (kernel|connected|static|ospf|bgp)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_host_host_cmd_vtysh, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "A single destination host\n" + "Destination address\n") + +DEFSH (VTYSH_BGPD, bgp_config_type_cmd_vtysh, + "bgp config-type (cisco|zebra)", + "BGP information\n" + "Configuration type\n" + "cisco\n" + "zebra\n") + +DEFSH (VTYSH_OSPFD, ospf_area_shortcut_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) shortcut (default|enable|disable)", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure the area's shortcutting mode\n" + "Set default shortcutting behavior\n" + "Enable shortcutting through the area\n" + "Disable shortcutting through the area\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_community2_exact_cmd_vtysh, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, show_ip_bgp_view_cmd_vtysh, + "show ip bgp view WORD", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "BGP view name\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_dampening_address_mask_cmd_vtysh, + "clear ip bgp dampening A.B.C.D A.B.C.D", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear route flap dampening information\n" + "Network to clear damping information\n" + "Network mask\n") + +DEFSH (VTYSH_RIPD, no_rip_neighbor_cmd_vtysh, + "no neighbor A.B.C.D", + "Negate a command or set its defaults\n" + "Specify a neighbor router\n" + "Neighbor address\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_connected_metric_routemap_cmd_vtysh, + "redistribute connected metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_filter_list_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Filter networks between OSPF areas\n" + "Filter prefixes between OSPF areas\n" + "Name of an IP prefix-list\n" + "Filter networks sent to this area\n" + "Filter networks sent from this area\n") + +DEFSH (VTYSH_BGPD, no_bgp_deterministic_med_cmd_vtysh, + "no bgp deterministic-med", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Pick the best-MED path among paths advertised from the neighboring AS\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community4_exact_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, no_set_aggregator_as_cmd_vtysh, + "no set aggregator as", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP aggregator attribute\n" + "AS number of aggregator\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_soft_cmd_vtysh, + "clear bgp ipv6 * soft", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all peers\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_cmd_vtysh, + "no redistribute (connected|kernel|ospf|rip|static)", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_soft_in_cmd_vtysh, + "clear ip bgp external ipv4 (unicast|multicast) soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_prefix_list_cmd_vtysh, + "ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)", + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Any prefix match. Same as \"::0/0 le 128\"\n") + +DEFSH (VTYSH_BGPD, bgp_graceful_restart_cmd_vtysh, + "bgp graceful-restart", + "BGP specific commands\n" + "Graceful restart capability parameters\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_soft_cmd_vtysh, + "clear ip bgp * vpnv4 unicast soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, debug_bgp_keepalive_cmd_vtysh, + "debug bgp keepalives", + "Debugging functions (see also 'undebug')\n" + "BGP information\n" + "BGP keepalives\n") + +DEFSH (VTYSH_BGPD, no_router_bgp_cmd_vtysh, + "no router bgp <1-65535>", + "Negate a command or set its defaults\n" + "Enable a routing process\n" + "BGP information\n" + "AS number\n" ) + +DEFSH (VTYSH_ZEBRA, ipv6_route_ifname_pref_cmd_vtysh, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", + "IP information\n" + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_transmit_delay_addr_cmd_vtysh, + "no ip ospf transmit-delay A.B.C.D", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Link state transmit delay\n" + "Address of interface") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_prefix_list_ge_cmd_vtysh, + "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>", + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_cmd_vtysh, + "distance <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_remark_cmd_vtysh, + "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list\n" + "Access list entry comment\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_routemap_cmd_vtysh, + "no redistribute connected route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged5_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path next-hop med", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") + +DEFSH (VTYSH_OSPFD, no_ospf_distance_ospf_cmd_vtysh, + "no distance ospf", + "Negate a command or set its defaults\n" + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "OSPF Distance\n") + +DEFSH (VTYSH_ZEBRA, no_ip_route_distance_cmd_vtysh, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>", + "Negate a command or set its defaults\n" + "IP information\n" + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_vlink_authtype_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|)", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Enable authentication on this virtual link\n" "dummy string \n" ) + +DEFSH (VTYSH_OSPFD, ospf_redistribute_source_metric_cmd_vtysh, + "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Metric for redistributed routes\n" + "OSPF default metric\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_neighbor_cmd_vtysh, + "show ipv6 ospf6 neighbor", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Neighbor list\n" + ) + +DEFSH (VTYSH_RIPD, key_string_cmd_vtysh, + "key-string LINE", + "Set key string\n" + "The key\n") + +DEFSH (VTYSH_RIPNGD, debug_ripng_events_cmd_vtysh, + "debug ripng events", + "Debugging functions (see also 'undebug')\n" + "RIPng configuration\n" + "Debug option set for ripng events\n") + +DEFSH (VTYSH_OSPF6D, no_redistribute_ospf6_cmd_vtysh, + "no redistribute ospf6", + "Negate a command or set its defaults\n" + "Redistribute control\n" + "OSPF6 route\n") + +DEFSH (VTYSH_BGPD, neighbor_description_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "description .LINE", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Neighbor specific description\n" + "Up to 80 characters describing this neighbor\n") + +DEFSH (VTYSH_ZEBRA, no_ipv6_route_pref_cmd_vtysh, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE|null0) <1-255>", + "Negate a command or set its defaults\n" + "IP information\n" + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n") + +DEFSH (VTYSH_OSPFD, debug_ospf_packet_send_recv_cmd_vtysh, + "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail information\n") + +DEFSH (VTYSH_OSPF6D, area_range_cmd_vtysh, + "area A.B.C.D range X:X::X:X/M", + "OSPF area parameters\n" + "Area ID (as an IPv4 notation)\n" + "Configured address range\n" + "Specify IPv6 prefix\n" + ) + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_prefix_list_seq_le_ge_cmd_vtysh, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_in_prefix_filter_cmd_vtysh, + "clear ip bgp external ipv4 (unicast|multicast) in prefix-filter", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_any_mask_cmd_vtysh, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "Destination address\n" + "Destination Wildcard bits\n") + +DEFSH (VTYSH_RIPD, no_ip_rip_authentication_key_chain2_cmd_vtysh, + "no ip rip authentication key-chain LINE", + "Negate a command or set its defaults\n" + "IP information\n" + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication key-chain\n" + "name of key-chain\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_cidr_only_cmd_vtysh, + "show ip bgp cidr-only", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display only routes with non-natural netmasks\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_description_cmd_vtysh, + "no ipv6 prefix-list WORD description", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Prefix-list specific description\n") + +DEFSH (VTYSH_RIPD, no_ip_rip_send_version_num_cmd_vtysh, + "no ip rip send version (1|2)", + "Negate a command or set its defaults\n" + "IP information\n" + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "Version 1\n" + "Version 2\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_import_list_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) import-list NAME", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Unset the filter for networks announced to other areas\n" + "Name of the access-list\n") + +DEFSH (VTYSH_OSPFD, ospf_area_authentication_message_digest_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) authentication message-digest", + "OSPF area parameters\n" + "Enable authentication\n" + "Use message-digest authentication\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_ospf6_routemap_cmd_vtysh, + "redistribute ospf6 route-map WORD", + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_ZEBRA, no_shutdown_if_cmd_vtysh, + "no shutdown", + "Negate a command or set its defaults\n" + "Shutdown the selected interface\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_soft_in_cmd_vtysh, + "clear ip bgp view WORD * soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, show_ip_extcommunity_list_arg_cmd_vtysh, + "show ip extcommunity-list (<1-500>|WORD)", + "Show running system information\n" + "IP information\n" + "List extended-community list\n" + "Extcommunity-list number\n" + "Extcommunity-list name\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_cmd_vtysh, + "clear bgp ipv6 peer-group WORD", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_exact_cmd_vtysh, + "no access-list WORD (deny|permit) A.B.C.D/M exact-match", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n" + "Exact match of the prefixes\n") + +DEFSH (VTYSH_ZEBRA, ip_tunnel_cmd_vtysh, + "ip tunnel IP_address IP_address", + "KAME ip tunneling configuration commands\n" + "Set FROM IP address and TO IP address\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_soft_in_cmd_vtysh, + "clear ip bgp A.B.C.D soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_cost_addr_cmd_vtysh, + "no ip ospf cost A.B.C.D", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Interface cost\n" + "Address of interface") + +DEFSH (VTYSH_ZEBRA, ipv6_route_cmd_vtysh, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE|null0)", + "IP information\n" + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n") + +DEFSH (VTYSH_BGPD, neighbor_enforce_multihop_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "enforce-multihop", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Enforce EBGP neighbors perform multihop\n") + +DEFSH (VTYSH_OSPFD, debug_ospf_packet_all_cmd_vtysh, + "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n") + +DEFSH (VTYSH_ZEBRA, no_ip_route_mask_distance_cmd_vtysh, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>", + "Negate a command or set its defaults\n" + "IP information\n" + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_in_prefix_filter_cmd_vtysh, + "clear ip bgp <1-65535> in prefix-filter", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_BGPD, no_match_aspath_cmd_vtysh, + "no match as-path", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "Match BGP AS path list\n") + +DEFSH (VTYSH_RIPD, no_debug_rip_events_cmd_vtysh, + "no debug rip events", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "RIP information\n" + "RIP events\n") + +DEFSH (VTYSH_BGPD, no_bgp_network_mask_natural_cmd_vtysh, + "no network A.B.C.D", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "Network number\n") + +DEFSH (VTYSH_BGPD, neighbor_attr_unchanged5_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path next-hop med", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") + +DEFSH (VTYSH_RIPD, rip_default_information_originate_cmd_vtysh, + "default-information originate", + "Control distribution of default route\n" + "Distribute a default route\n") + +DEFSH (VTYSH_OSPFD, ospf_area_vlink_authtype_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|)", + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Enable authentication on this virtual link\n" "dummy string \n" ) + +DEFSH (VTYSH_OSPFD, no_ospf_abr_type_cmd_vtysh, + "no ospf abr-type (cisco|ibm|shortcut)", + "Negate a command or set its defaults\n" + "OSPF specific commands\n" + "Set OSPF ABR type\n" + "Alternative ABR, cisco implementation\n" + "Alternative ABR, IBM implementation\n" + "Shortcut ABR\n") + +DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_rmap_cmd_vtysh, + "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_OSPFD, no_ospf_transmit_delay_cmd_vtysh, + "no ospf transmit-delay", + "Negate a command or set its defaults\n" + "OSPF interface commands\n" + "Link state transmit delay\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_access_list_remark_cmd_vtysh, + "ipv6 access-list WORD remark .LINE", + "IPv6 information\n" + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Access list entry comment\n" + "Comment up to 100 characters\n") + +DEFSH (VTYSH_BGPD, no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> <1-100> restart <1-65535>", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Threshold value (%) at which to generate a warning msg\n" + "Restart bgp connection after limit is exceeded\n" + "Restart interval in minutes") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, show_ipv6_prefix_list_detail_cmd_vtysh, + "show ipv6 prefix-list detail", + "Show running system information\n" + "IPv6 information\n" + "Build a prefix list\n" + "Detail of prefix lists\n") + +DEFSH (VTYSH_BGPD, ip_extcommunity_list_standard_cmd_vtysh, + "ip extcommunity-list <1-99> (deny|permit) .AA:NN", + "IP information\n" + "Add a extended community list entry\n" + "Extended Community list number (standard)\n" + "Specify community to reject\n" + "Specify community to accept\n" + "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n" ) + +DEFSH (VTYSH_ZEBRA, no_ipv6_nd_reachable_time_cmd_vtysh, + "no ipv6 nd reachable-time", + "Negate a command or set its defaults\n" + "IP information\n" + "Neighbor discovery\n" + "Reachable time\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community3_exact_cmd_vtysh, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_ge_le_cmd_vtysh, + "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_retransmit_interval_cmd_vtysh, + "no ip ospf retransmit-interval", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_community2_cmd_vtysh, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, aggregate_address_mask_as_set_summary_cmd_vtysh, + "aggregate-address A.B.C.D A.B.C.D as-set summary-only", + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Generate AS set path information\n" + "Filter more specific routes from updates\n") + +DEFSH (VTYSH_BGPD, no_aggregate_address_mask_cmd_vtysh, + "no aggregate-address A.B.C.D A.B.C.D", + "Negate a command or set its defaults\n" + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_prefix_longer_cmd_vtysh, + "show ip bgp A.B.C.D/M longer-prefixes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD, set_metric_cmd_vtysh, + "set metric <0-4294967295>", + "Set values in destination routing protocol\n" + "Metric value for destination routing protocol\n" + "Metric value\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_cmd_vtysh, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, ipv6_bgp_neighbor_routes_cmd_vtysh, + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_description_arg_cmd_vtysh, + "no ip prefix-list WORD description .LINE", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Prefix-list specific description\n" + "Up to 80 characters describing this prefix-list\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_neighbors_cmd_vtysh, + "show ip bgp neighbors", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n") + +DEFSH (VTYSH_BGPD, neighbor_advertise_interval_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X) " "advertisement-interval <0-600>", + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Minimum interval between sending BGP routing updates\n" + "time in seconds\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_external_soft_cmd_vtysh, + "clear ip bgp external soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all external peers\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, no_neighbor_remove_private_as_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "remove-private-AS", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Remove private AS number from outbound updates\n") + +DEFSH (VTYSH_RIPD, no_ip_rip_send_version_cmd_vtysh, + "no ip rip send version", + "Negate a command or set its defaults\n" + "IP information\n" + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n") + +DEFSH (VTYSH_BGPD, clear_bgp_external_in_prefix_filter_cmd_vtysh, + "clear bgp external in prefix-filter", + "Reset functions\n" + "BGP information\n" + "Clear all external peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_shortcut_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) shortcut (enable|disable)", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Deconfigure the area's shortcutting mode\n" + "Deconfigure enabled shortcutting through the area\n" + "Deconfigure disabled shortcutting through the area\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_route_cmd_vtysh, + "show ip bgp A.B.C.D", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Network in the BGP routing table to display\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, clear_ipv6_prefix_list_name_cmd_vtysh, + "clear ipv6 prefix-list WORD", + "Reset functions\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_soft_in_cmd_vtysh, + "clear ip bgp peer-group WORD soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, no_neighbor_timers_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "timers", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP per neighbor timers\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_type_routemap_cmd_vtysh, + "default-information originate always metric-type (1|2) route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_access_list_exact_cmd_vtysh, + "ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match", + "IPv6 information\n" + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 3ffe:506::/32\n" + "Exact match of the prefixes\n") + +DEFSH (VTYSH_BGPD, ip_extcommunity_list_expanded_cmd_vtysh, + "ip extcommunity-list <100-500> (deny|permit) .LINE", + "IP information\n" + "Add a extended community list entry\n" + "Extended Community list number (expanded)\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") + +DEFSH (VTYSH_BGPD, show_ip_community_list_arg_cmd_vtysh, + "show ip community-list (<1-500>|WORD)", + "Show running system information\n" + "IP information\n" + "List community-list\n" + "Community-list number\n" + "Community-list name\n") + +DEFSH (VTYSH_BGPD, bgp_timers_cmd_vtysh, + "timers bgp <0-65535> <0-65535>", + "Adjust routing timers\n" + "BGP timers\n" + "Keepalive interval\n" + "Holdtime\n") + +DEFSH (VTYSH_RIPD, rip_neighbor_cmd_vtysh, + "neighbor A.B.C.D", + "Specify a neighbor router\n" + "Neighbor address\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, show_ipv6_prefix_list_prefix_first_match_cmd_vtysh, + "show ipv6 prefix-list WORD X:X::X:X/M first-match", + "Show running system information\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "First matched prefix\n") + +DEFSH (VTYSH_BGPD, neighbor_shutdown_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "shutdown", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Administratively shut down this neighbor\n") + +DEFSH (VTYSH_BGPD, no_debug_bgp_fsm_cmd_vtysh, + "no debug bgp fsm", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "BGP information\n" + "Finite State Machine\n") + +DEFSH (VTYSH_BGPD, bgp_graceful_restart_stalepath_time_cmd_vtysh, + "bgp graceful-restart stalepath-time <1-3600>", + "BGP specific commands\n" + "Graceful restart capability parameters\n" + "Set the max time to hold onto restarting peer's stale paths\n" + "Delay value (seconds)\n") + +DEFSH (VTYSH_BGPD, neighbor_weight_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "weight <0-65535>", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Set default weight for routes from this neighbor\n" + "default weight\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_soft_in_cmd_vtysh, + "clear bgp ipv6 <1-65535> soft in", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_soft_cmd_vtysh, + "clear ip bgp A.B.C.D soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh, + "show ip bgp vpnv4 all neighbors A.B.C.D", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_list_cmd_vtysh, + "show ipv6 bgp community-list WORD", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes matching the community-list\n" + "community-list name\n") + +DEFSH (VTYSH_OSPFD, ospf_area_vlink_authtype_args_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) (message-digest|null)", + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Enable authentication on this virtual link\n" "dummy string \n" "Use null authentication\n" "Use message-digest authentication\n" ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_soft_in_cmd_vtysh, + "clear ip bgp A.B.C.D vpnv4 unicast soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_le_cmd_vtysh, + "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_BGPD, no_bgp_bestpath_med2_cmd_vtysh, + "no bgp bestpath med confed missing-as-worst", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Compare MED among confederation paths\n" + "Treat missing MED as the least preferred one\n") + +DEFSH (VTYSH_OSPFD, no_ospf_priority_cmd_vtysh, + "no ospf priority", + "Negate a command or set its defaults\n" + "OSPF interface commands\n" + "Router priority\n") + +DEFSH (VTYSH_BGPD, bgp_network_mask_natural_cmd_vtysh, + "network A.B.C.D", + "Specify a network to announce via BGP\n" + "Network number\n") + +DEFSH (VTYSH_BGPD, no_neighbor_maximum_prefix_restart_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> restart <1-65535>", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Restart bgp connection after limit is exceeded\n" + "Restart interval in minutes") + +DEFSH (VTYSH_BGPD, no_synchronization_cmd_vtysh, + "no synchronization", + "Negate a command or set its defaults\n" + "Perform IGP synchronization\n") + +DEFSH (VTYSH_RIPD|VTYSH_BGPD, set_ip_nexthop_cmd_vtysh, + "set ip next-hop A.B.C.D", + "Set values in destination routing protocol\n" + "IP information\n" + "Next hop address\n" + "IP address of next hop\n") + +DEFSH (VTYSH_RIPD, no_rip_version_val_cmd_vtysh, + "no version <1-2>", + "Negate a command or set its defaults\n" + "Set routing protocol version\n" + "version\n") + +DEFSH (VTYSH_BGPD, no_bgp_scan_time_cmd_vtysh, + "no bgp scan-time", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Configure background scanner interval\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_metric_cmd_vtysh, + "no redistribute connected metric", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_authentication_key_addr_cmd_vtysh, + "no ip ospf authentication-key A.B.C.D", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Authentication password (key)\n" + "Address of interface") + +DEFSH (VTYSH_RIPNGD, no_ripng_route_cmd_vtysh, + "no route IPV6ADDR", + "Negate a command or set its defaults\n" + "Static route setup\n" + "Delete static RIPng route announcement\n") + +DEFSH (VTYSH_OSPFD, debug_ospf_nsm_sub_cmd_vtysh, + "debug ospf nsm (status|events|timers)", + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Neighbor State Machine\n" + "NSM Status Information\n" + "NSM Event Information\n" + "NSM Timer Information\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_soft_out_cmd_vtysh, + "clear ip bgp <1-65535> vpnv4 unicast soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, no_debug_bgp_all_cmd_vtysh, + "no debug all bgp", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Enable all debugging\n" + "BGP information\n" ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_soft_out_cmd_vtysh, + "clear ip bgp * vpnv4 unicast soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, no_bgp_distance_cmd_vtysh, + "no distance bgp <1-255> <1-255> <1-255>", + "Negate a command or set its defaults\n" + "Define an administrative distance\n" + "BGP distance\n" + "Distance for routes external to the AS\n" + "Distance for routes internal to the AS\n" + "Distance for local routes\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_soft_out_cmd_vtysh, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_RIPD, no_rip_timers_cmd_vtysh, + "no timers basic", + "Negate a command or set its defaults\n" + "Adjust routing timers\n" + "Basic routing protocol update timers\n") + +DEFSH (VTYSH_OSPF6D, ipv6_ospf6_passive_cmd_vtysh, + "ipv6 ospf6 passive", + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "passive interface, No adjacency will be formed on this interface\n" + ) + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_external_intra_cmd_vtysh, + "distance ospf inter-area <1-255> external <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_type_metric_routemap_cmd_vtysh, + "default-information originate always metric-type (1|2) metric <0-16777214> route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "OSPF default metric\n" + "OSPF metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_RIPNGD, no_debug_ripng_events_cmd_vtysh, + "no debug ripng events", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "RIPng configuration\n" + "Debug option set for ripng events\n") + +DEFSH (VTYSH_RIPD, accept_lifetime_duration_month_day_cmd_vtysh, + "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_ospf6_metric_routemap_cmd_vtysh, + "redistribute ospf6 metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_match_metric_cmd_vtysh, + "no match metric", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "Match metric of route\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, match_ip_next_hop_cmd_vtysh, + "match ip next-hop (<1-199>|<1300-2699>|WORD)", + "Match values from routing table\n" + "IP information\n" + "Match next-hop address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") + +DEFSH (VTYSH_BGPD, aggregate_address_summary_only_cmd_vtysh, + "aggregate-address A.B.C.D/M summary-only", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_in_prefix_filter_cmd_vtysh, + "clear bgp ipv6 <1-65535> in prefix-filter", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_OSPFD, ospf_neighbor_poll_interval_cmd_vtysh, + "neighbor A.B.C.D poll-interval <1-65535>", + "Specify neighbor router\n" + "Neighbor IP address\n" + "Dead Neighbor Polling interval\n" + "Seconds\n") + +DEFSH (VTYSH_BGPD, no_bgp_network_route_map_cmd_vtysh, + "no network A.B.C.D/M route-map WORD", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + +DEFSH (VTYSH_OSPFD, no_ospf_timers_spf_cmd_vtysh, + "no timers spf", + "Negate a command or set its defaults\n" + "Adjust routing timers\n" + "OSPF SPF timers\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_instance_neighbors_peer_cmd_vtysh, + "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "View name\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_cmd_vtysh, + "no redistribute connected", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n") + +DEFSH (VTYSH_OSPFD, ospf_area_range_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n") + +DEFSH (VTYSH_BGPD, aggregate_address_summary_as_set_cmd_vtysh, + "aggregate-address A.B.C.D/M summary-only as-set", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n" + "Generate AS set path information\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_external_in_cmd_vtysh, + "clear ip bgp external in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all external peers\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, no_neighbor_nexthop_self_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "next-hop-self", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Disable the next hop calculation for this neighbor\n") + +DEFSH (VTYSH_RIPD, no_debug_rip_packet_direct_cmd_vtysh, + "no debug rip packet (recv|send)", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "RIP information\n" + "RIP packet\n" + "RIP option set for receive packet\n" + "RIP option set for send packet\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_community2_exact_cmd_vtysh, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_RIPD, no_ip_rip_authentication_mode_type_cmd_vtysh, + "no ip rip authentication mode (md5|text)", + "Negate a command or set its defaults\n" + "IP information\n" + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication mode\n" + "Keyed message digest\n" + "Clear text authentication\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, show_ipv6_prefix_list_summary_cmd_vtysh, + "show ipv6 prefix-list summary", + "Show running system information\n" + "IPv6 information\n" + "Build a prefix list\n" + "Summary of prefix lists\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_any_cmd_vtysh, + "no access-list WORD (deny|permit) any", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, bgp_bestpath_med3_cmd_vtysh, + "bgp bestpath med missing-as-worst confed", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Treat missing MED as the least preferred one\n" + "Compare MED among confederation paths\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_community4_cmd_vtysh, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_retransmit_interval_addr_cmd_vtysh, + "ip ospf retransmit-interval <3-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n" + "Seconds\n" + "Address of interface") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, match_ip_address_cmd_vtysh, + "match ip address (<1-199>|<1300-2699>|WORD)", + "Match values from routing table\n" + "IP information\n" + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") + +DEFSH (VTYSH_OSPF6D, ipv6_ospf6_deadinterval_cmd_vtysh, + "ipv6 ospf6 dead-interval <1-65535>", + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Interval time after which a neighbor is declared down\n" + "<1-65535> Seconds\n" + ) + +DEFSH (VTYSH_OSPFD, debug_ospf_zebra_sub_cmd_vtysh, + "debug ospf zebra (interface|redistribute)", + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Zebra information\n" + "Zebra interface\n" + "Zebra redistribute\n") + +DEFSH (VTYSH_BGPD, match_aspath_cmd_vtysh, + "match as-path WORD", + "Match values from routing table\n" + "Match BGP AS path list\n" + "AS path access-list name\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_flap_cidr_only_cmd_vtysh, + "show ip bgp flap-statistics cidr-only", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display flap statistics of routes\n" + "Display only routes with non-natural netmasks\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_description_arg_cmd_vtysh, + "no ipv6 prefix-list WORD description .LINE", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Prefix-list specific description\n" + "Up to 80 characters describing this prefix-list\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_vlink_authtype_md5_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) " + "(message-digest-key|)", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Enable authentication on this virtual link\n" "dummy string \n" + "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)" ) + +DEFSH (VTYSH_ZEBRA, no_ipv6_nd_ra_interval_cmd_vtysh, + "no ipv6 nd ra-interval", + "Negate a command or set its defaults\n" + "IP information\n" + "Neighbor discovery\n" + "Router Advertisement interval\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd_vtysh, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in prefix-filter", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_soft_cmd_vtysh, + "clear ip bgp * soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Soft reconfig\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_redistribute_cmd_vtysh, + "show ipv6 ospf6 redistribute", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "redistributing External information\n" + ) + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_static_metric_routemap_cmd_vtysh, + "redistribute static metric <0-16> route-map WORD", + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_rmap_metric_cmd_vtysh, + "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n" + "Metric for redistributed routes\n" + "Default metric\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_route_map_cmd_vtysh, + "show bgp ipv6 route-map WORD", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_next_hop_prefix_list_cmd_vtysh, + "no match ip next-hop prefix-list", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IP information\n" + "Match next-hop address of route\n" + "Match entries of prefix-lists\n") + +DEFSH (VTYSH_BGPD, no_neighbor_set_peer_group_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X) " "peer-group WORD", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Member of the peer-group\n" + "peer-group name\n") + +DEFSH (VTYSH_BGPD, show_bgp_neighbor_routes_cmd_vtysh, + "show bgp neighbors (A.B.C.D|X:X::X:X) routes", + "Show running system information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_bgp_cmd_vtysh, + "redistribute bgp", + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_host_mask_cmd_vtysh, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "Destination address\n" + "Destination Wildcard bits\n") + +DEFSH (VTYSH_BGPD, debug_bgp_events_cmd_vtysh, + "debug bgp events", + "Debugging functions (see also 'undebug')\n" + "BGP information\n" + "BGP events\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_seq_ge_cmd_vtysh, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_RIPNGD, debug_ripng_packet_cmd_vtysh, + "debug ripng packet", + "Debugging functions (see also 'undebug')\n" + "RIPng configuration\n" + "Debug option set for ripng packet\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_out_cmd_vtysh, + "clear ip bgp <1-65535> out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_metric_cmd_vtysh, + "no redistribute static metric", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n") + +DEFSH (VTYSH_OSPFD, ospf_redistribute_source_routemap_cmd_vtysh, + "redistribute (kernel|connected|static|rip|bgp) route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, show_bgp_community2_exact_cmd_vtysh, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, clear_bgp_external_soft_cmd_vtysh, + "clear bgp external soft", + "Reset functions\n" + "BGP information\n" + "Clear all external peers\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, no_ipv6_aggregate_address_cmd_vtysh, + "no aggregate-address X:X::X:X/M", + "Negate a command or set its defaults\n" + "Configure BGP aggregate entries\n" + "Aggregate prefix\n") + +DEFSH (VTYSH_BGPD, clear_bgp_all_in_prefix_filter_cmd_vtysh, + "clear bgp * in prefix-filter", + "Reset functions\n" + "BGP information\n" + "Clear all peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_cmd_vtysh, + "show ip bgp", + "Show running system information\n" + "IP information\n" + "BGP information\n" ) + +DEFSH (VTYSH_OSPFD, ip_ospf_message_digest_key_addr_cmd_vtysh, + "ip ospf message-digest-key <1-255> md5 KEY A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n" + "Use MD5 algorithm\n" + "The OSPF password (key)" + "Address of interface") + +DEFSH (VTYSH_BGPD, show_debugging_bgp_cmd_vtysh, + "show debugging bgp", + "Show running system information\n" + "Debugging functions (see also 'undebug')\n" + "BGP information\n" ) + +DEFSH (VTYSH_OSPFD|VTYSH_OSPF6D, ospf6_routemap_set_metric_type_cmd_vtysh, + "set metric-type (type-1|type-2)", + "Set value\n" + "Type of metric\n" + "OSPF6 external type 1 metric\n" + "OSPF6 external type 2 metric\n") + +DEFSH (VTYSH_BGPD, aggregate_address_mask_summary_only_cmd_vtysh, + "aggregate-address A.B.C.D A.B.C.D summary-only", + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Filter more specific routes from updates\n") + +DEFSH (VTYSH_OSPFD, no_ospf_distance_source_cmd_vtysh, + "no distance <1-255> A.B.C.D/M", + "Negate a command or set its defaults\n" + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_standard_cmd_vtysh, + "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D", + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Address to match\n" + "Wildcard bits\n") + +DEFSH (VTYSH_ZEBRA, no_zebra_interface_cmd_vtysh, + "no interface IFNAME", + "Delete a pseudo interface's configuration\n" + "Interface's name\n") + +DEFSH (VTYSH_RIPD, debug_rip_zebra_cmd_vtysh, + "debug rip zebra", + "Debugging functions (see also 'undebug')\n" + "RIP information\n" + "RIP and ZEBRA communication\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_mask_any_cmd_vtysh, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "Any destination host\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_paths_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) paths", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Path information\n") + +DEFSH (VTYSH_OSPFD, ospf_redistribute_source_type_metric_routemap_cmd_vtysh, + "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Metric for redistributed routes\n" + "OSPF default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, clear_bgp_peer_group_soft_out_cmd_vtysh, + "clear bgp peer-group WORD soft out", + "Reset functions\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_route_cmd_vtysh, + "show ipv6 bgp X:X::X:X", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Network in the BGP routing table to display\n") + +DEFSH (VTYSH_BGPD, bgp_network_mask_natural_backdoor_cmd_vtysh, + "network A.B.C.D backdoor", + "Specify a network to announce via BGP\n" + "Network number\n" + "Specify a BGP backdoor route\n") + +DEFSH (VTYSH_RIPD, rip_route_cmd_vtysh, + "route A.B.C.D/M", + "RIP static route configuration\n" + "IP prefix /\n") + +DEFSH (VTYSH_OSPFD, no_ospf_cost_cmd_vtysh, + "no ospf cost", + "Negate a command or set its defaults\n" + "OSPF interface commands\n" + "Interface cost\n") + +DEFSH (VTYSH_OSPFD, ospf_area_vlink_param1_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" ) + +DEFSH (VTYSH_BGPD, clear_bgp_all_soft_out_cmd_vtysh, + "clear bgp * soft out", + "Reset functions\n" + "BGP information\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_prefix_list_sequence_number_cmd_vtysh, + "ipv6 prefix-list sequence-number", + "IPv6 information\n" + "Build a prefix list\n" + "Include/exclude sequence numbers in NVGEN\n") + +DEFSH (VTYSH_RIPD, no_debug_rip_packet_cmd_vtysh, + "no debug rip packet", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "RIP information\n" + "RIP packet\n") + +DEFSH (VTYSH_ZEBRA, show_ip_route_prefix_longer_cmd_vtysh, + "show ip route A.B.C.D/M longer-prefixes", + "Show running system information\n" + "IP information\n" + "IP routing table\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Show route matching the specified Network/Mask pair only\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_default_cost_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Set the summary-default cost of a NSSA or stub area\n" + "Stub's advertised default summary cost\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, show_ipv6_access_list_name_cmd_vtysh, + "show ipv6 access-list WORD", + "Show running system information\n" + "IPv6 information\n" + "List IPv6 access lists\n" + "IPv6 zebra access-list\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ripng_cmd_vtysh, + "no redistribute ripng", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "RIPng route\n") + +DEFSH (VTYSH_BGPD, no_set_community_val_cmd_vtysh, + "no set community .AA:NN", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP community attribute\n" + "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n") + +DEFSH (VTYSH_BGPD, clear_bgp_peer_group_out_cmd_vtysh, + "clear bgp peer-group WORD out", + "Reset functions\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, show_ipv6_prefix_list_prefix_longer_cmd_vtysh, + "show ipv6 prefix-list WORD X:X::X:X/M longer", + "Show running system information\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Lookup longer prefix\n") + +DEFSH (VTYSH_RIPD, no_distribute_list_prefix_cmd_vtysh, + "no distribute-list prefix WORD (in|out) WORD", + "Negate a command or set its defaults\n" + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_metric_cmd_vtysh, + "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_flap_prefix_list_cmd_vtysh, + "show ip bgp flap-statistics prefix-list WORD", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display flap statistics of routes\n" + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_neighbor_cmd_vtysh, + "no debug ospf6 neighbor", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 Neighbor\n" + ) + +DEFSH (VTYSH_OSPFD, no_ospf_area_export_list_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) export-list NAME", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Unset the filter for networks announced to other areas\n" + "Name of the access-list\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_aggregate_address_cmd_vtysh, + "no aggregate-address X:X::X:X/M", + "Negate a command or set its defaults\n" + "Delete aggregate RIPng route announcement\n" + "Aggregate network") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbor_routes_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") + +DEFSH (VTYSH_OSPF6D, ipv6_ospf6_retransmitinterval_cmd_vtysh, + "ipv6 ospf6 retransmit-interval <1-65535>", + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Time between retransmitting lost link state advertisements\n" + "<1-65535> Seconds\n" + ) + +DEFSH (VTYSH_RIPNGD, no_ripng_if_rmap_cmd_vtysh, + "no route-map ROUTEMAP_NAME (in|out) IFNAME", + "Negate a command or set its defaults\n" + "Route map unset\n" + "Route map name\n" + "Route map for input filtering\n" + "Route map for output filtering\n" + "Route map interface name\n") + +DEFSH (VTYSH_RIPD, debug_rip_packet_detail_cmd_vtysh, + "debug rip packet (recv|send) detail", + "Debugging functions (see also 'undebug')\n" + "RIP information\n" + "RIP packet\n" + "RIP receive packet\n" + "RIP send packet\n" + "Detailed information display\n") + +DEFSH (VTYSH_ZEBRA, show_ip_route_protocol_cmd_vtysh, + "show ip route (bgp|connected|kernel|ospf|rip|static)", + "Show running system information\n" + "IP information\n" + "IP routing table\n" + "Border Gateway Protocol (BGP)\n" + "Connected\n" + "Kernel\n" + "Open Shortest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n") + +DEFSH (VTYSH_BGPD, no_bgp_client_to_client_reflection_cmd_vtysh, + "no bgp client-to-client reflection", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Configure client to client route reflection\n" + "reflection of routes allowed\n") + +DEFSH (VTYSH_BGPD, no_bgp_multiple_instance_cmd_vtysh, + "no bgp multiple-instance", + "Negate a command or set its defaults\n" + "BGP information\n" + "BGP multiple instance\n") + +DEFSH (VTYSH_OSPFD, no_debug_ospf_nsm_sub_cmd_vtysh, + "no debug ospf nsm (status|events|timers)", + "Negate a command or set its defaults\n" + "Debugging functions\n" + "OSPF information\n" + "OSPF Interface State Machine\n" + "NSM Status Information\n" + "NSM Event Information\n" + "NSM Timer Information\n") + +DEFSH (VTYSH_BGPD, bgp_distance_cmd_vtysh, + "distance bgp <1-255> <1-255> <1-255>", + "Define an administrative distance\n" + "BGP distance\n" + "Distance for routes external to the AS\n" + "Distance for routes internal to the AS\n" + "Distance for local routes\n") + +DEFSH (VTYSH_BGPD, clear_bgp_peer_group_soft_cmd_vtysh, + "clear bgp peer-group WORD soft", + "Reset functions\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_metric_rmap_cmd_vtysh, + "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_host_any_cmd_vtysh, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "Any destination host\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_attr_info_cmd_vtysh, + "show ip bgp attribute-info", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "List all bgp attribute information\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_standard_host_cmd_vtysh, + "no access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "A single host address\n" + "Address to match\n") + +DEFSH (VTYSH_RIPD, show_ip_protocols_rip_cmd_vtysh, + "show ip protocols", + "Show running system information\n" + "IP information\n" + "IP routing protocol process parameters and statistics\n") + +DEFSH (VTYSH_RIPD, send_lifetime_day_month_day_month_cmd_vtysh, + "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") + +DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_name_expanded_all_cmd_vtysh, + "no ip extcommunity-list expanded WORD", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a extended community list entry\n" + "Specify expanded extcommunity-list\n" + "Extended Community list name\n") + +DEFSH (VTYSH_OSPFD, no_ospf_redistribute_source_cmd_vtysh, + "no redistribute (kernel|connected|static|rip|bgp)", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n") + +DEFSH (VTYSH_RIPD, ip_rip_receive_version_cmd_vtysh, + "ip rip receive version (1|2)", + "IP information\n" + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_priority_addr_cmd_vtysh, + "ip ospf priority <0-255> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Router priority\n" + "Priority\n" + "Address of interface") + +DEFSH (VTYSH_ZEBRA, debug_zebra_events_cmd_vtysh, + "debug zebra events", + "Debugging functions (see also 'undebug')\n" + "Zebra configuration\n" + "Debug option set for zebra events\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_cmd_vtysh, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_name_standard_all_cmd_vtysh, + "no ip extcommunity-list standard WORD", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a extended community list entry\n" + "Specify standard extcommunity-list\n" + "Extended Community list name\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_prefix_longer_cmd_vtysh, + "show bgp ipv6 X:X::X:X/M longer-prefixes", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "IPv6 prefix /\n" + "Display route and more specific routes\n") + +DEFSH (VTYSH_RIPD|VTYSH_BGPD, match_metric_cmd_vtysh, + "match metric <0-4294967295>", + "Match values from routing table\n" + "Match metric of route\n" + "Metric value\n") + +DEFSH (VTYSH_OSPF6D, no_ipv6_ospf6_passive_cmd_vtysh, + "no ipv6 ospf6 passive", + "Negate a command or set its defaults\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "passive interface: No Adjacency will be formed on this I/F\n" + ) + +DEFSH (VTYSH_RIPD, accept_lifetime_infinite_day_month_cmd_vtysh, + "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Never expires") + +DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged6_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path med next-hop", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Med attribute\n" + "Nexthop attribute\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_seq_ge_cmd_vtysh, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_BGPD, neighbor_route_reflector_client_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "route-reflector-client", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Configure a neighbor as Route Reflector client\n") + +DEFSH (VTYSH_BGPD, show_bgp_community_list_cmd_vtysh, + "show bgp community-list (<1-500>|WORD)", + "Show running system information\n" + "BGP information\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_ripng_cmd_vtysh, + "redistribute ripng", + "Redistribute information from another routing protocol\n" + "RIPng route\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_standard_host_cmd_vtysh, + "access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D", + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "A single host address\n" + "Address to match\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_bgp_metric_cmd_vtysh, + "redistribute bgp metric <0-16>", + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n") + +DEFSH (VTYSH_OSPF6D|VTYSH_BGPD, match_ipv6_address_prefix_list_cmd_vtysh, + "match ipv6 address prefix-list WORD", + "Match values from routing table\n" + "IPv6 information\n" + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") + +DEFSH (VTYSH_BGPD, show_bgp_neighbor_received_prefix_filter_cmd_vtysh, + "show bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + "Show running system information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_instance_neighbors_cmd_vtysh, + "show ip bgp view WORD neighbors", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "View name\n" + "Detailed information on TCP and BGP neighbor connections\n") + +DEFSH (VTYSH_BGPD, no_ip_community_list_name_expanded_all_cmd_vtysh, + "no ip community-list expanded WORD", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a community list entry\n" + "Add an expanded community-list entry\n" + "Community list name\n") + +DEFSH (VTYSH_OSPF6D, show_zebra_cmd_vtysh, + "show zebra", + "Show running system information\n" + "Zebra information\n") + +DEFSH (VTYSH_BGPD, clear_bgp_peer_out_cmd_vtysh, + "clear bgp (A.B.C.D|X:X::X:X) out", + "Reset functions\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_description_cmd_vtysh, + "no ip prefix-list WORD description", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Prefix-list specific description\n") + +DEFSH (VTYSH_BGPD, no_ip_community_list_name_standard_all_cmd_vtysh, + "no ip community-list standard WORD", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a community list entry\n" + "Add a standard community-list entry\n" + "Community list name\n") + +DEFSH (VTYSH_ZEBRA, no_ip_forwarding_cmd_vtysh, + "no ip forwarding", + "Negate a command or set its defaults\n" + "IP information\n" + "Turn off IP forwarding") + +DEFSH (VTYSH_RIPD, distribute_list_prefix_all_cmd_vtysh, + "distribute-list prefix WORD (in|out)", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_bgp_routemap_cmd_vtysh, + "redistribute bgp route-map WORD", + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_RIPNGD, ipv6_distribute_list_prefix_all_cmd_vtysh, + "distribute-list prefix WORD (in|out)", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_BGPD, no_debug_bgp_update_cmd_vtysh, + "no debug bgp updates", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "BGP information\n" + "BGP updates\n") + +DEFSH (VTYSH_OSPFD, ospf_area_range_substitute_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Announce area range as another prefix\n" + "Network prefix to be announced instead of range\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_cmd_vtysh, + "no redistribute ospf6", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n") + +DEFSH (VTYSH_ZEBRA, no_ip_address_cmd_vtysh, + "no ip address A.B.C.D/M", + "Negate a command or set its defaults\n" + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP Address (e.g. 10.0.0.1/8)") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_route_map_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) route-map WORD", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") + +DEFSH (VTYSH_OSPFD, no_ospf_neighbor_cmd_vtysh, + "no neighbor A.B.C.D", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor IP address\n") + +DEFSH (VTYSH_ZEBRA, no_ipv6_address_cmd_vtysh, + "no ipv6 address X:X::X:X/M", + "Negate a command or set its defaults\n" + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IPv6 address (e.g. 3ffe:506::1/48)\n") + +DEFSH (VTYSH_BGPD, no_neighbor_shutdown_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "shutdown", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Administratively shut down this neighbor\n") + +DEFSH (VTYSH_RIPD, no_ip_rip_authentication_string2_cmd_vtysh, + "no ip rip authentication string LINE", + "Negate a command or set its defaults\n" + "IP information\n" + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication string\n" + "Authentication string\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_network_cmd_vtysh, + "ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", + "IP Information\n" + "OSPF interface commands\n" + "Network type\n" + "Specify OSPF broadcast multi-access network\n" + "Specify OSPF NBMA network\n" + "Specify OSPF point-to-multipoint network\n" + "Specify OSPF point-to-point network\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_source_access_list_cmd_vtysh, + "distance <1-255> A.B.C.D/M WORD", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") + +DEFSH (VTYSH_BGPD, neighbor_send_community_type_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community (both|extended|standard)", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Send Community attribute to this neighbor\n" + "Send Standard and Extended Community attributes\n" + "Send Extended Community attributes\n" + "Send Standard Community attributes\n") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_abr_cmd_vtysh, + "no debug ospf6 abr", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 ABR function\n" + ) + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_metric_cmd_vtysh, + "no redistribute kernel metric", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n") + +DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_rmap_cmd_vtysh, + "redistribute (connected|kernel|ospf|rip|static) route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_prefix_list_le_cmd_vtysh, + "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>", + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_OSPFD, ospf_redistribute_source_cmd_vtysh, + "redistribute (kernel|connected|static|rip|bgp)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n") + +DEFSH (VTYSH_ZEBRA, ipv6_nd_prefix_advertisement_cmd_vtysh, + "ipv6 nd prefix-advertisement IPV6PREFIX VALID PREFERRED [onlink] [autoconfig]", + "IP information\n" + "Neighbor discovery\n" + "Prefix information\n" + "IPv6 prefix\n" + "Valid lifetime in seconds\n" + "Preferred lifetime in seconds\n" + "On link flag\n" + "Autonomous address-configuration flag\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, show_ipv6_access_list_cmd_vtysh, + "show ipv6 access-list", + "Show running system information\n" + "IPv6 information\n" + "List IPv6 access lists\n") + +DEFSH (VTYSH_BGPD, match_ecommunity_cmd_vtysh, + "match extcommunity (<1-99>|<100-500>|WORD)", + "Match values from routing table\n" + "Match BGP/VPN extended community list\n" + "Extended community-list number (standard)\n" + "Extended community-list number (expanded)\n" + "Extended community-list name\n") + +DEFSH (VTYSH_BGPD, no_neighbor_override_capability_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "override-capability", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Override capability negotiation result\n") + +DEFSH (VTYSH_BGPD, undebug_bgp_update_cmd_vtysh, + "undebug bgp updates", + "Disable debugging functions (see also 'debug')\n" + "BGP information\n" + "BGP updates\n") + +DEFSH (VTYSH_RIPNGD, no_debug_ripng_packet_cmd_vtysh, + "no debug ripng packet", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "RIPng configuration\n" + "Debug option set for ripng packet\n") + +DEFSH (VTYSH_OSPF6D, ipv6_ospf6_ifmtu_cmd_vtysh, + "ipv6 ospf6 ifmtu <1-65535>", + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Interface MTU\n" + "OSPFv3 Interface MTU\n" + ) + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_prefix_list_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) prefix-list WORD", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community2_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, neighbor_attr_unchanged6_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path med next-hop", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Med attribute\n" + "Nexthop attribute\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_flap_filter_list_cmd_vtysh, + "show ip bgp flap-statistics filter-list WORD", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display flap statistics of routes\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd_vtysh, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_routemap_cmd_vtysh, + "no redistribute kernel route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_route_cmd_vtysh, + "show ip bgp vpnv4 all A.B.C.D", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Network in the BGP routing table to display\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_regexp_cmd_vtysh, + "show bgp ipv6 regexp .LINE", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") + +DEFSH (VTYSH_OSPF6D, ipv6_ospf6_priority_cmd_vtysh, + "ipv6 ospf6 priority <0-255>", + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Router priority\n" + "Priority value\n" + ) + +DEFSH (VTYSH_OSPFD, ospf_authentication_key_cmd_vtysh, + "ospf authentication-key AUTH_KEY", + "OSPF interface commands\n" + "Authentication password (key)\n" + "The OSPF password (key)") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_asbr_cmd_vtysh, + "no debug ospf6 asbr", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 ASBR function\n" + ) + +DEFSH (VTYSH_RIPD, no_rip_distance_source_access_list_cmd_vtysh, + "no distance <1-255> A.B.C.D/M WORD", + "Negate a command or set its defaults\n" + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") + +DEFSH (VTYSH_OSPFD, no_ospf_router_id_cmd_vtysh, + "no ospf router-id", + "Negate a command or set its defaults\n" + "OSPF specific commands\n" + "router-id for the OSPF process\n") + +DEFSH (VTYSH_BGPD, bgp_bestpath_compare_router_id_cmd_vtysh, + "bgp bestpath compare-routerid", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "Compare router-id for identical EBGP paths\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_metric_val_cmd_vtysh, + "no redistribute bgp metric <0-16>", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_community3_cmd_vtysh, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_ZEBRA, debug_zebra_packet_direct_cmd_vtysh, + "debug zebra packet (recv|send)", + "Debugging functions (see also 'undebug')\n" + "Zebra configuration\n" + "Debug option set for zebra packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n") + +DEFSH (VTYSH_BGPD, set_ipv6_nexthop_global_cmd_vtysh, + "set ipv6 next-hop global X:X::X:X", + "Set values in destination routing protocol\n" + "IPv6 information\n" + "IPv6 next-hop address\n" + "IPv6 global address\n" + "IPv6 address of next hop\n") + +DEFSH (VTYSH_RIPNGD, no_debug_ripng_packet_direct_cmd_vtysh, + "no debug ripng packet (recv|send)", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "RIPng configuration\n" + "Debug option set for ripng packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n") + +DEFSH (VTYSH_RIPD, send_lifetime_infinite_month_day_cmd_vtysh, + "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Never expires") + +DEFSH (VTYSH_BGPD, no_neighbor_transport_connection_mode_val_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "transport connection-mode (active|passive)", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Transport options\n" + "Specify passive or active connection\n" + "Actively establish the TCP session\n" + "Passively establish the TCP session\n") + +DEFSH (VTYSH_BGPD, no_set_local_pref_val_cmd_vtysh, + "no set local-preference <0-4294967295>", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP local preference path attribute\n" + "Preference value\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_vlink_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" ) + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_ospf6_cmd_vtysh, + "redistribute ospf6", + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_any_any_cmd_vtysh, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip any any", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "Any destination host\n") + +DEFSH (VTYSH_BGPD, no_neighbor_local_as_val_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as <1-65535>", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Specify a local-as number\n" + "AS number used as local AS\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_mask_host_cmd_vtysh, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "A single destination host\n" + "Destination address\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_prefix_list_name_cmd_vtysh, + "show ip prefix-list WORD", + "Show running system information\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n") + +DEFSH (VTYSH_ZEBRA, show_ipv6_route_prefix_cmd_vtysh, + "show ipv6 route X:X::X:X/M", + "Show running system information\n" + "IP information\n" + "IPv6 routing table\n" + "IPv6 prefix\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_soft_cmd_vtysh, + "clear ip bgp A.B.C.D vpnv4 unicast soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_next_hop_cmd_vtysh, + "no match ip next-hop", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IP information\n" + "Match next-hop address of route\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_authentication_addr_cmd_vtysh, + "no ip ospf authentication A.B.C.D", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n" + "Address of interface") + +DEFSH (VTYSH_OSPF6D, ospf6_routemap_no_set_forwarding_cmd_vtysh, + "no set forwarding-address X:X::X:X", + "Negate a command or set its defaults\n" + "Set value\n" + "Forwarding Address\n" + "IPv6 Address\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_route_cmd_vtysh, + "debug ospf6 route (table|intra-area|inter-area)", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug route table calculation\n" + "Debug detail\n" + "Debug intra-area route calculation\n" + "Debug inter-area route calculation\n" + ) + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community2_cmd_vtysh, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_linkstate_cmd_vtysh, + "show ipv6 ospf6 linkstate", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Display linkstate routing table\n" + ) + +DEFSH (VTYSH_RIPD, ip_rip_authentication_key_chain_cmd_vtysh, + "ip rip authentication key-chain LINE", + "IP information\n" + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication key-chain\n" + "name of key-chain\n") + +DEFSH (VTYSH_BGPD, no_neighbor_distribute_list_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Filter updates to/from this neighbor\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n" + "Filter incoming updates\n" + "Filter outgoing updates\n") + +DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_metric_cmd_vtysh, + "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, show_ipv6_prefix_list_cmd_vtysh, + "show ipv6 prefix-list", + "Show running system information\n" + "IPv6 information\n" + "Build a prefix list\n" ) + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_prefix_list_prefix_longer_cmd_vtysh, + "show ip prefix-list WORD A.B.C.D/M longer", + "Show running system information\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Lookup longer prefix\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_intra_external_cmd_vtysh, + "distance ospf inter-area <1-255> intra-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "External routes\n" + "Distance for external routes\n") + +DEFSH (VTYSH_BGPD, no_bgp_bestpath_med3_cmd_vtysh, + "no bgp bestpath med missing-as-worst confed", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Treat missing MED as the least preferred one\n" + "Compare MED among confederation paths\n") + +DEFSH (VTYSH_RIPNGD, debug_ripng_packet_direct_cmd_vtysh, + "debug ripng packet (recv|send)", + "Debugging functions (see also 'undebug')\n" + "RIPng configuration\n" + "Debug option set for ripng packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_soft_in_cmd_vtysh, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_OSPFD, ospf_area_range_cost_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "User specified metric for this range\n" + "Advertised metric for this range\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_soft_out_cmd_vtysh, + "clear ip bgp * soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbor_received_prefix_filter_cmd_vtysh, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_soft_cmd_vtysh, + "clear ip bgp * ipv4 (unicast|multicast) soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_soft_out_cmd_vtysh, + "clear ip bgp * ipv4 (unicast|multicast) soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_RIPD, distribute_list_all_cmd_vtysh, + "distribute-list WORD (in|out)", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_RIPD, accept_lifetime_day_month_day_month_cmd_vtysh, + "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_stub_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) stub", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as stub\n") + +DEFSH (VTYSH_BGPD, no_bgp_cluster_id_cmd_vtysh, + "no bgp cluster-id", + "Negate a command or set its defaults\n" + "BGP information\n" + "Configure Route-Reflector Cluster-id\n") + +DEFSH (VTYSH_BGPD, neighbor_maximum_prefix_warning_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> warning-only", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Only give warning message when limit is exceeded\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_ZEBRA, no_debug_zebra_events_cmd_vtysh, + "no debug zebra events", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Zebra configuration\n" + "Debug option set for zebra events\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_in_cmd_vtysh, + "clear bgp ipv6 peer-group WORD in", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_prefix_list_cmd_vtysh, + "show ipv6 bgp prefix-list WORD", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes matching the prefix-list\n" + "IPv6 prefix-list name\n") + +DEFSH (VTYSH_BGPD, no_bgp_distance2_cmd_vtysh, + "no distance bgp", + "Negate a command or set its defaults\n" + "Define an administrative distance\n" + "BGP distance\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_in_cmd_vtysh, + "clear bgp ipv6 external WORD in", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all external peers\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, no_set_aggregator_as_val_cmd_vtysh, + "no set aggregator as <1-65535> A.B.C.D", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP aggregator attribute\n" + "AS number of aggregator\n" + "AS number\n" + "IP address of aggregator\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_metric_type_routemap_cmd_vtysh, + "default-information originate metric <0-16777214> metric-type (1|2) route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, ip_community_list_name_standard_cmd_vtysh, + "ip community-list standard WORD (deny|permit) .AA:NN", + "IP information\n" + "Add a community list entry\n" + "Add a standard community-list entry\n" + "Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n" ) + +DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_self_cmd_vtysh, + "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") (self-originate|)", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Database summary\n" + "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" "" + "Self-originated link states\n") + +DEFSH (VTYSH_BGPD, bgp_router_id_cmd_vtysh, + "bgp router-id A.B.C.D", + "BGP information\n" + "Override configured router identifier\n" + "Manually configured router identifier\n") + +DEFSH (VTYSH_ZEBRA, show_ip_forwarding_cmd_vtysh, + "show ip forwarding", + "Show running system information\n" + "IP information\n" + "IP forwarding status\n") + +DEFSH (VTYSH_BGPD, ip_community_list_standard_cmd_vtysh, + "ip community-list <1-99> (deny|permit) .AA:NN", + "IP information\n" + "Add a community list entry\n" + "Community list number (standard)\n" + "Specify community to reject\n" + "Specify community to accept\n" + "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n" ) + +DEFSH (VTYSH_ZEBRA, no_multicast_cmd_vtysh, + "no multicast", + "Negate a command or set its defaults\n" + "Unset multicast flag to interface\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_instance_ipv4_summary_cmd_vtysh, + "show ip bgp view WORD ipv4 (unicast|multicast) summary", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "View name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Summary of BGP neighbor status\n") + +DEFSH (VTYSH_BGPD, clear_bgp_peer_soft_cmd_vtysh, + "clear bgp (A.B.C.D|X:X::X:X) soft", + "Reset functions\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, no_bgp_graceful_restart_stalepath_time_cmd_vtysh, + "no bgp graceful-restart stalepath-time", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Graceful restart capability parameters\n" + "Set the max time to hold onto restarting peer's stale paths\n") + +DEFSH (VTYSH_BGPD, set_ecommunity_cost_igp_cmd_vtysh, + "set extcommunity cost igp <0-255> <0-4294967295>", + "Set values in destination routing protocol\n" + "BGP extended community attribute\n" + "Cost extended community\n" + "Compare following IGP cost comparison\n" + "Community ID\n" + "Cost Value\n" + "VPN extended community\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_cmd_vtysh, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "Destination address\n" + "Destination Wildcard bits\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_filter_list_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) filter-list WORD", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_summary_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) summary", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Summary of BGP neighbor status\n") + +DEFSH (VTYSH_RIPD, no_rip_redistribute_type_metric_routemap_cmd_vtysh, + "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16> route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_soft_cmd_vtysh, + "clear ip bgp external ipv4 (unicast|multicast) soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_soft_out_cmd_vtysh, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft out", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_OSPFD, show_ip_ospf_route_cmd_vtysh, + "show ip ospf route", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "OSPF routing table\n") + +DEFSH (VTYSH_BGPD, no_bgp_network_cmd_vtysh, + "no network A.B.C.D/M", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, no_ip_as_path_cmd_vtysh, + "no ip as-path access-list WORD (deny|permit) .LINE", + "Negate a command or set its defaults\n" + "IP information\n" + "BGP autonomous system path filter\n" + "Specify an access list name\n" + "Regular expression access list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "A regular-expression to match the BGP AS paths\n") + +DEFSH (VTYSH_BGPD, neighbor_distribute_list_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Filter updates to/from this neighbor\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n" + "Filter incoming updates\n" + "Filter outgoing updates\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ip_prefix_list_le_ge_cmd_vtysh, + "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_access_list_all_cmd_vtysh, + "no ipv6 access-list WORD", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Add an access list entry\n" + "IPv6 zebra access-list\n") + +DEFSH (VTYSH_BGPD, ip_community_list_name_expanded_cmd_vtysh, + "ip community-list expanded WORD (deny|permit) .LINE", + "IP information\n" + "Add a community list entry\n" + "Add an expanded community-list entry\n" + "Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") + +DEFSH (VTYSH_ZEBRA, ipv6_address_cmd_vtysh, + "ipv6 address X:X::X:X/M", + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IPv6 address (e.g. 3ffe:506::1/48)\n") + +DEFSH (VTYSH_BGPD, ip_community_list_expanded_cmd_vtysh, + "ip community-list <100-500> (deny|permit) .LINE", + "IP information\n" + "Add a community list entry\n" + "Community list number (expanded)\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") + +DEFSH (VTYSH_RIPD, rip_offset_list_ifname_cmd_vtysh, + "offset-list WORD (in|out) <0-16> IFNAME", + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n" + "Interface to match\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_prefix_longer_cmd_vtysh, + "show ipv6 mbgp X:X::X:X/M longer-prefixes", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Display route and more specific routes\n") + +DEFSH (VTYSH_OSPFD, debug_ospf_ism_sub_cmd_vtysh, + "debug ospf ism (status|events|timers)", + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Interface State Machine\n" + "ISM Status Information\n" + "ISM Event Information\n" + "ISM TImer Information\n") + +DEFSH (VTYSH_BGPD, neighbor_send_community_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Send Community attribute to this neighbor\n") + +DEFSH (VTYSH_BGPD, show_bgp_route_map_cmd_vtysh, + "show bgp route-map WORD", + "Show running system information\n" + "BGP information\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_route_cmd_vtysh, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Network in the BGP routing table to display\n") + +DEFSH (VTYSH_ZEBRA, no_ipv6_route_ifname_pref_cmd_vtysh, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", + "Negate a command or set its defaults\n" + "IP information\n" + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n") + +DEFSH (VTYSH_BGPD, dump_bgp_updates_interval_cmd_vtysh, + "dump bgp updates PATH INTERVAL", + "Dump packet\n" + "BGP packet dump\n" + "Dump BGP updates only\n" + "Output filename\n" + "Interval of output\n") + +DEFSH (VTYSH_BGPD, no_bgp_confederation_identifier_arg_cmd_vtysh, + "no bgp confederation identifier <1-65535>", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "AS confederation parameters\n" + "AS number\n" + "Set routing domain confederation AS\n") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_flooding_cmd_vtysh, + "no debug ospf6 flooding", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 flooding function\n" + ) + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_linkstate_network_cmd_vtysh, + "show ipv6 ospf6 linkstate network A.B.C.D A.B.C.D", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Display linkstate routing table\n" + "Display Network Entry\n" + "Specify Router ID as IPv4 address notation\n" + "Specify Link state ID as IPv4 address notation\n" + ) + +DEFSH (VTYSH_BGPD, no_neighbor_route_server_client_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "route-server-client", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Configure a neighbor as Route Server client\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_community_all_cmd_vtysh, + "show ip bgp community", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the communities\n") + +DEFSH (VTYSH_OSPFD, ospf_message_digest_key_cmd_vtysh, + "ospf message-digest-key <1-255> md5 KEY", + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n" + "Use MD5 algorithm\n" + "The OSPF password (key)") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_soft_in_cmd_vtysh, + "clear ip bgp * ipv4 (unicast|multicast) soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_in_prefix_filter_cmd_vtysh, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) in prefix-filter", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig inbound update\n" + "Push out the existing ORF prefix-list\n") + +DEFSH (VTYSH_BGPD, no_match_community_cmd_vtysh, + "no match community", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "Match BGP community list\n") + +DEFSH (VTYSH_RIPD, rip_redistribute_type_metric_cmd_vtysh, + "redistribute (kernel|connected|static|ospf|bgp) metric <0-16>", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n" + "Metric value\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_summary_cmd_vtysh, + "show ip bgp vpnv4 all summary", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Summary of BGP neighbor status\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community2_exact_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_lsa_hex_cmd_vtysh, + "debug ospf6 lsa XXXX/0xXXXX", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug Link State Advertisements (LSAs)\n" + "Specify LS type as Hexadecimal\n" + ) + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_regexp_cmd_vtysh, + "show ipv6 mbgp regexp .LINE", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the MBGP AS paths\n") + +DEFSH (VTYSH_BGPD, no_set_community_delete_cmd_vtysh, + "no set comm-list", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "set BGP community list (for deletion)\n") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_spf_time_cmd_vtysh, + "no debug ospf6 spf time", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Quit Debugging SPF Calculation\n" + "Quit Measuring time taken by SPF Calculation\n" + ) + +DEFSH (VTYSH_OSPFD, no_debug_ospf_zebra_cmd_vtysh, + "no debug ospf zebra", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Zebra information\n") + +DEFSH (VTYSH_ZEBRA, debug_zebra_packet_cmd_vtysh, + "debug zebra packet", + "Debugging functions (see also 'undebug')\n" + "Zebra configuration\n" + "Debug option set for zebra packet\n") + +DEFSH (VTYSH_RIPD, no_rip_redistribute_rip_cmd_vtysh, + "no redistribute rip", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Routing Information Protocol (RIP)\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_metric_type_cmd_vtysh, + "default-information originate metric <0-16777214> metric-type (1|2)", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_out_cmd_vtysh, + "clear ip bgp * ipv4 (unicast|multicast) out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_RIPD, no_rip_version_cmd_vtysh, + "no version", + "Negate a command or set its defaults\n" + "Set routing protocol version\n") + +DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_match_metric_val_cmd_vtysh, + "no match metric <0-4294967295>", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "Match metric of route\n" + "Metric value\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_vlink_authkey_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication-key|)", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Authentication password (key)\n" "The OSPF password (key)" ) + +DEFSH (VTYSH_BGPD, show_ip_bgp_flap_prefix_cmd_vtysh, + "show ip bgp flap-statistics A.B.C.D/M", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display flap statistics of routes\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, bgp_always_compare_med_cmd_vtysh, + "bgp always-compare-med", + "BGP specific commands\n" + "Allow comparing MED from different neighbors\n") + +DEFSH (VTYSH_BGPD, clear_bgp_instance_all_soft_out_cmd_vtysh, + "clear bgp view WORD * soft out", + "Reset functions\n" + "BGP information\n" + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbor_advertised_route_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") + +DEFSH (VTYSH_BGPD, no_match_ip_route_source_val_cmd_vtysh, + "no match ip route-source (<1-199>|<1300-2699>|WORD)", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IP information\n" + "Match advertising source address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP standard access-list name\n") + +DEFSH (VTYSH_BGPD, no_match_ip_route_source_prefix_list_val_cmd_vtysh, + "no match ip route-source prefix-list WORD", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IP information\n" + "Match advertising source address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") + +DEFSH (VTYSH_RIPD, rip_offset_list_cmd_vtysh, + "offset-list WORD (in|out) <0-16>", + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_out_cmd_vtysh, + "clear bgp ipv6 <1-65535> out", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, no_match_ip_route_source_cmd_vtysh, + "no match ip route-source", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IP information\n" + "Match advertising source address of route\n") + +DEFSH (VTYSH_BGPD, dump_bgp_routes_cmd_vtysh, + "dump bgp routes-mrt PATH", + "Dump packet\n" + "BGP packet dump\n" + "Dump whole BGP routing table\n" + "Output filename\n") + +DEFSH (VTYSH_OSPF6D, no_ipv6_ospf6_advertise_prefix_list_cmd_vtysh, + "no ipv6 ospf6 advertise prefix-list", + "Negate a command or set its defaults\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Advertising options\n" + "Filter prefix using prefix-list\n" + ) + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd_vtysh, + "show ip bgp vpnv4 all neighbors A.B.C.D advertised-routes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") + +DEFSH (VTYSH_RIPD, rip_passive_interface_cmd_vtysh, + "passive-interface IFNAME", + "Suppress routing updates on an interface\n" + "Interface name\n") + +DEFSH (VTYSH_OSPFD, no_debug_ospf_lsa_cmd_vtysh, + "no debug ospf lsa", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Link State Advertisement\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_network_cmd_vtysh, + "no network IF_OR_ADDR", + "Negate a command or set its defaults\n" + "RIPng enable on specified interface or network.\n" + "Interface or address") + +DEFSH (VTYSH_BGPD, clear_bgp_external_soft_out_cmd_vtysh, + "clear bgp external soft out", + "Reset functions\n" + "BGP information\n" + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_OSPFD, ospf_redistribute_source_metric_type_cmd_vtysh, + "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> metric-type (1|2)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Metric for redistributed routes\n" + "OSPF default metric\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD, no_rmap_continue_cmd_vtysh, + "no continue", + "Negate a command or set its defaults\n" + "Continue on a different entry within the route-map\n") + +DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_name_standard_cmd_vtysh, + "no ip extcommunity-list standard WORD (deny|permit) .AA:NN", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a extended community list entry\n" + "Specify standard extcommunity-list\n" + "Extended Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n" ) + +DEFSH (VTYSH_OSPFD, no_ospf_default_metric_cmd_vtysh, + "no default-metric", + "Negate a command or set its defaults\n" + "Set metric of redistributed routes\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_paths_cmd_vtysh, + "show ip bgp paths", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Path information\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_advertised_route_cmd_vtysh, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") + +DEFSH (VTYSH_OSPFD, ospf_redistribute_source_type_cmd_vtysh, + "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n") + +DEFSH (VTYSH_BGPD, match_ipv6_next_hop_cmd_vtysh, + "match ipv6 next-hop X:X::X:X", + "Match values from routing table\n" + "IPv6 information\n" + "Match IPv6 next-hop address of route\n" + "IPv6 address of next hop\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_transmit_delay_cmd_vtysh, + "ip ospf transmit-delay <1-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Link state transmit delay\n" + "Seconds\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_soft_in_cmd_vtysh, + "clear ip bgp <1-65535> vpnv4 unicast soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_RIPD, rip_redistribute_type_routemap_cmd_vtysh, + "redistribute (kernel|connected|static|ospf|bgp) route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, no_bgp_graceful_restart_cmd_vtysh, + "no bgp graceful-restart", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Graceful restart capability parameters\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_filter_list_cmd_vtysh, + "show ipv6 bgp filter-list WORD", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") + +DEFSH (VTYSH_BGPD, show_bgp_instance_ipv6_summary_cmd_vtysh, + "show bgp view WORD ipv6 summary", + "Show running system information\n" + "BGP information\n" + "BGP view\n" + "View name\n" + "Address family\n" + "Summary of BGP neighbor status\n") + +DEFSH (VTYSH_ZEBRA, no_ipv6_nd_ra_lifetime_cmd_vtysh, + "no ipv6 nd ra-lifetime", + "Negate a command or set its defaults\n" + "IP information\n" + "Neighbor discovery\n" + "Router lifetime\n") + +DEFSH (VTYSH_BGPD, bgp_distance_source_cmd_vtysh, + "distance <1-255> A.B.C.D/M", + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n") + +DEFSH (VTYSH_ZEBRA, no_ip_tunnel_cmd_vtysh, + "no ip tunnel", + "Negate a command or set its defaults\n" + "Set FROM IP address and TO IP address\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_received_prefix_filter_cmd_vtysh, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_routes_cmd_vtysh, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") + +DEFSH (VTYSH_BGPD, no_set_origin_cmd_vtysh, + "no set origin", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP origin code\n") + +DEFSH (VTYSH_BGPD, no_set_community_delete_val_cmd_vtysh, + "no set comm-list (<1-99>|<100-500>|WORD) delete", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "set BGP community list (for deletion)\n" + "Community-list number (standard)\n" + "Communitly-list number (expanded)\n" + "Community-list name\n" + "Delete matching communities\n") + +DEFSH (VTYSH_BGPD, no_bgp_bestpath_aspath_ignore_cmd_vtysh, + "no bgp bestpath as-path ignore", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Change the default bestpath selection\n" + "AS-path attribute\n" + "Ignore as-path length in selecting a route\n") + +DEFSH (VTYSH_ZEBRA, no_ipv6_nd_suppress_ra_cmd_vtysh, + "no ipv6 nd suppress-ra", + "Negate a command or set its defaults\n" + "IP information\n" + "Neighbor discovery\n" + "Suppress Router Advertisement\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_exact_cmd_vtysh, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, show_ip_bgp_scan_cmd_vtysh, + "show ip bgp scan", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "BGP scan status\n") + +DEFSH (VTYSH_BGPD, no_bgp_bestpath_cost_community_ignore_cmd_vtysh, + "no bgp bestpath cost-community ignore", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Change the default bestpath selection\n" + "cost community\n" + "Ignore cost communities in bestpath selection\n") + +DEFSH (VTYSH_BGPD, no_bgp_cluster_id_arg_cmd_vtysh, + "no bgp cluster-id A.B.C.D", + "Negate a command or set its defaults\n" + "BGP information\n" + "Configure Route-Reflector Cluster-id\n" + "Route-Reflector Cluster-id in IP address format\n") + +DEFSH (VTYSH_OSPFD, ospf_area_vlink_param2_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" ) + +DEFSH (VTYSH_BGPD, no_bgp_confederation_peers_cmd_vtysh, + "no bgp confederation peers .<1-65535>", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "AS confederation parameters\n" + "Peer ASs in BGP confederation\n" + "AS number\n" ) + +DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_id_cmd_vtysh, + "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") A.B.C.D", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Database summary\n" + "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" "" + "Link State ID (as an IP address)\n") + +DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_name_expanded_cmd_vtysh, + "no ip extcommunity-list expanded WORD (deny|permit) .LINE", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a extended community list entry\n" + "Specify expanded extcommunity-list\n" + "Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") + +DEFSH (VTYSH_BGPD, show_bgp_community_list_exact_cmd_vtysh, + "show bgp community-list (<1-500>|WORD) exact-match", + "Show running system information\n" + "BGP information\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") + +DEFSH (VTYSH_BGPD, ipv6_bgp_neighbor_received_routes_cmd_vtysh, + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) received-routes", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") + +DEFSH (VTYSH_OSPFD, no_ospf_hello_interval_cmd_vtysh, + "no ospf hello-interval", + "Negate a command or set its defaults\n" + "OSPF interface commands\n" + "Time between HELLO packets\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_vlink_md5_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(message-digest-key|) <1-255>", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)" ) + +DEFSH (VTYSH_BGPD, no_set_weight_cmd_vtysh, + "no set weight", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP weight for routing table\n") + +DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_int_detail_cmd_vtysh, + "show ip ospf neighbor A.B.C.D detail", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Neighbor list\n" + "Interface address\n" + "detail of all neighbors") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_list_cmd_vtysh, + "show bgp ipv6 community-list (<1-500>|WORD)", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") + +DEFSH (VTYSH_BGPD, clear_bgp_peer_group_in_prefix_filter_cmd_vtysh, + "clear bgp peer-group WORD in prefix-filter", + "Reset functions\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_BGPD, neighbor_maximum_prefix_threshold_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> <1-100>", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Threshold value (%) at which to generate a warning msg\n") + +DEFSH (VTYSH_BGPD, set_ecommunity_rt_cmd_vtysh, + "set extcommunity rt .ASN:nn_or_IP-address:nn", + "Set values in destination routing protocol\n" + "BGP extended community attribute\n" + "Route Target extened communityt\n" + "VPN extended community\n") + +DEFSH (VTYSH_BGPD, no_neighbor_description_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "description", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Neighbor specific description\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_seq_le_cmd_vtysh, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_ZEBRA, no_ipv6_forwarding_cmd_vtysh, + "no ipv6 forwarding", + "Negate a command or set its defaults\n" + "IP information\n" + "Doesn't forward IPv6 protocol packet") + +DEFSH (VTYSH_BGPD, show_bgp_community_cmd_vtysh, + "show bgp community (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_OSPFD, ospf_router_id_cmd_vtysh, + "ospf router-id A.B.C.D", + "OSPF specific commands\n" + "router-id for the OSPF process\n" + "OSPF router-id in IP address format\n") + +DEFSH (VTYSH_BGPD, show_bgp_community_exact_cmd_vtysh, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, no_neighbor_capability_orf_prefix_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "capability orf prefix-list (both|send|receive)", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Advertise capability to the peer\n" + "Advertise ORF capability to the peer\n" + "Advertise prefixlist ORF capability to this neighbor\n" + "Capability to SEND and RECEIVE the ORF to/from this neighbor\n" + "Capability to RECEIVE the ORF from this neighbor\n" + "Capability to SEND the ORF to this neighbor\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_hello_interval_addr_cmd_vtysh, + "ip ospf hello-interval <1-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Time between HELLO packets\n" + "Seconds\n" + "Address of interface") + +DEFSH (VTYSH_BGPD, no_aggregate_address_mask_summary_only_cmd_vtysh, + "no aggregate-address A.B.C.D A.B.C.D summary-only", + "Negate a command or set its defaults\n" + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Filter more specific routes from updates\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_intra_cmd_vtysh, + "distance ospf external <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") + +DEFSH (VTYSH_BGPD, neighbor_soft_reconfiguration_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "soft-reconfiguration inbound", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Per neighbor soft reconfiguration\n" + "Allow inbound soft reconfiguration for this neighbor\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_access_list_exact_cmd_vtysh, + "no ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 3ffe:506::/32\n" + "Exact match of the prefixes\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_external_in_prefix_filter_cmd_vtysh, + "clear ip bgp external in prefix-filter", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all external peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_metric_rmap_cmd_vtysh, + "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_cmd_vtysh, + "no redistribute (connected|kernel|ospf6|ripng|static)", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n") + +DEFSH (VTYSH_ZEBRA, show_ipv6_route_cmd_vtysh, + "show ipv6 route", + "Show running system information\n" + "IP information\n" + "IPv6 routing table\n") + +DEFSH (VTYSH_BGPD, no_bgp_fast_external_failover_cmd_vtysh, + "no bgp fast-external-failover", + "Negate a command or set its defaults\n" + "BGP information\n" + "Immediately reset session if a link to a directly connected external peer goes down\n") + +DEFSH (VTYSH_BGPD, no_aggregate_address_mask_as_set_summary_cmd_vtysh, + "no aggregate-address A.B.C.D A.B.C.D as-set summary-only", + "Negate a command or set its defaults\n" + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Generate AS set path information\n" + "Filter more specific routes from updates\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_external_soft_out_cmd_vtysh, + "clear ip bgp external soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_summary_cmd_vtysh, + "show bgp ipv6 summary", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Summary of BGP neighbor status\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_regexp_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) regexp .LINE", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_spf_database_cmd_vtysh, + "no debug ospf6 spf database", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug SPF Calculation\n" + "Quit Logging number of LSAs at SPF Calculation time\n" + ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_out_cmd_vtysh, + "clear ip bgp * vpnv4 unicast out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged7_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop med as-path", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "Med attribute\n" + "As-path attribute\n") + +DEFSH (VTYSH_OSPFD, ospf_area_vlink_authtype_args_authkey_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) (message-digest|null) " + "(authentication-key|) AUTH_KEY", + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Enable authentication on this virtual link\n" "dummy string \n" "Use null authentication\n" "Use message-digest authentication\n" + "Authentication password (key)\n" "The OSPF password (key)" ) + +DEFSH (VTYSH_BGPD, no_ipv6_bgp_network_route_map_cmd_vtysh, + "no network X:X::X:X/M route-map WORD", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_soft_cmd_vtysh, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, neighbor_ebgp_multihop_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Allow EBGP neighbors not on directly connected networks\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_authentication_key_cmd_vtysh, + "no ip ospf authentication-key", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Authentication password (key)\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_neighbor_routes_cmd_vtysh, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") + +DEFSH (VTYSH_OSPFD, no_debug_ospf_ism_sub_cmd_vtysh, + "no debug ospf ism (status|events|timers)", + "Negate a command or set its defaults\n" + "Debugging functions\n" + "OSPF information\n" + "OSPF Interface State Machine\n" + "ISM Status Information\n" + "ISM Event Information\n" + "ISM Timer Information\n") + +DEFSH (VTYSH_ZEBRA, ipv6_nd_managed_config_flag_cmd_vtysh, + "ipv6 nd managed-config-flag", + "IP information\n" + "Neighbor discovery\n" + "Managed address configuration flag\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_inter_cmd_vtysh, + "distance ospf intra-area <1-255> inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_metric_val_cmd_vtysh, + "no redistribute ospf6 metric <0-16>", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n" + "Metric value\n") + +DEFSH (VTYSH_BGPD, no_set_ipv6_nexthop_local_val_cmd_vtysh, + "no set ipv6 next-hop local X:X::X:X", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "IPv6 information\n" + "IPv6 next-hop address\n" + "IPv6 local address\n" + "IPv6 address of next hop\n") + +DEFSH (VTYSH_BGPD, ip_community_list_name_standard2_cmd_vtysh, + "ip community-list standard WORD (deny|permit)", + "IP information\n" + "Add a community list entry\n" + "Add a standard community-list entry\n" + "Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_cmd_vtysh, + "no access-list WORD (deny|permit) A.B.C.D/M", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n") + +DEFSH (VTYSH_ZEBRA, show_zebra_client_cmd_vtysh, + "show zebra client", + "Show running system information\n" + "Zebra information" + "Client information") + +DEFSH (VTYSH_BGPD, neighbor_allowas_in_arg_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "allowas-in <1-10>", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Accept as-path with my AS present in it\n" + "Number of occurances of AS number\n") + +DEFSH (VTYSH_BGPD, bgp_cluster_id_cmd_vtysh, + "bgp cluster-id A.B.C.D", + "BGP information\n" + "Configure Route-Reflector Cluster-id\n" + "Route-Reflector Cluster-id in IP address format\n") + +DEFSH (VTYSH_OSPFD, ospf_area_stub_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) stub", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as stub\n") + +DEFSH (VTYSH_BGPD, no_router_bgp_view_cmd_vtysh, + "no router bgp <1-65535> view WORD", + "Negate a command or set its defaults\n" + "Enable a routing process\n" + "BGP information\n" + "AS number\n" + "BGP view\n" + "view name\n") + +DEFSH (VTYSH_OSPFD, no_debug_ospf_packet_send_recv_cmd_vtysh, + "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", + "Negate a command or set its defaults\n" + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail Information\n") + +DEFSH (VTYSH_BGPD, no_set_community_cmd_vtysh, + "no set community", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP community attribute\n") + +DEFSH (VTYSH_OSPFD|VTYSH_OSPF6D, ospf6_routemap_no_set_metric_type_cmd_vtysh, + "no set metric-type (type-1|type-2)", + "Negate a command or set its defaults\n" + "Set value\n" + "Type of metric\n" + "OSPF6 external type 1 metric\n" + "OSPF6 external type 2 metric\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_prefix_list_name_seq_cmd_vtysh, + "show ip prefix-list WORD seq <1-4294967295>", + "Show running system information\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n") + +DEFSH (VTYSH_BGPD, neighbor_maximum_prefix_threshold_restart_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> <1-100> restart <1-65535>", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Threshold value (%) at which to generate a warning msg\n" + "Restart bgp connection after limit is exceeded\n" + "Restart interval in minutes") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_soft_in_cmd_vtysh, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_OSPFD, ospf_rfc1583_flag_cmd_vtysh, + "ospf rfc1583compatibility", + "OSPF specific commands\n" + "Enable the RFC1583Compatibility flag\n") + +DEFSH (VTYSH_ZEBRA, no_debug_zebra_packet_cmd_vtysh, + "no debug zebra packet", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Zebra configuration\n" + "Debug option set for zebra packet\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_community4_exact_cmd_vtysh, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_route_cmd_vtysh, + "no debug ospf6 route (table|intra-area|inter-area)", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug route table calculation\n" + "Debug intra-area route calculation\n") + +DEFSH (VTYSH_RIPD, ip_rip_authentication_mode_cmd_vtysh, + "ip rip authentication mode (md5|text)", + "IP information\n" + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication mode\n" + "Keyed message digest\n" + "Clear text authentication\n") + +DEFSH (VTYSH_ZEBRA, no_ipv6_nd_send_ra_cmd_vtysh, + "no ipv6 nd send-ra", + "Negate a command or set its defaults\n" + "IP information\n" + "Neighbor discovery\n" + "Send Router Advertisement\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_exact_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_soft_cmd_vtysh, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Address family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Soft reconfig\n") + +DEFSH (VTYSH_OSPFD, ospf_abr_type_cmd_vtysh, + "ospf abr-type (cisco|ibm|shortcut|standard)", + "OSPF specific commands\n" + "Set OSPF ABR type\n" + "Alternative ABR, cisco implementation\n" + "Alternative ABR, IBM implementation\n" + "Shortcut ABR\n" + "Standard behavior (RFC2328)\n") + +DEFSH (VTYSH_BGPD, no_neighbor_maximum_prefix_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Maximum number of prefix accept from this peer\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_soft_cmd_vtysh, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_metric_type_cmd_vtysh, + "default-information originate always metric <0-16777214> metric-type (1|2)", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_community3_exact_cmd_vtysh, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, neighbor_strict_capability_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X) " "strict-capability-match", + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Strict capability negotiation match\n") + +DEFSH (VTYSH_BGPD, clear_bgp_instance_all_soft_cmd_vtysh, + "clear bgp view WORD * soft", + "Reset functions\n" + "BGP information\n" + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, clear_bgp_peer_in_cmd_vtysh, + "clear bgp (A.B.C.D|X:X::X:X) in", + "Reset functions\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_spf_database_cmd_vtysh, + "debug ospf6 spf database", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug SPF Calculation\n" + "Log number of LSAs at SPF Calculation time\n" + ) + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, show_ipv6_prefix_list_prefix_cmd_vtysh, + "show ipv6 prefix-list WORD X:X::X:X/M", + "Show running system information\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") + +DEFSH (VTYSH_BGPD, ipv6_mbgp_neighbor_advertised_route_cmd_vtysh, + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") + +DEFSH (VTYSH_ZEBRA, show_ip_route_addr_cmd_vtysh, + "show ip route A.B.C.D", + "Show running system information\n" + "IP information\n" + "IP routing table\n" + "Network in the IP routing table to display\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_seq_le_cmd_vtysh, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_list_cmd_vtysh, + "show ipv6 mbgp community-list WORD", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes matching the community-list\n" + "community-list name\n") + +DEFSH (VTYSH_OSPFD, ospf_neighbor_poll_interval_priority_cmd_vtysh, + "neighbor A.B.C.D poll-interval <1-65535> priority <0-255>", + "Specify neighbor router\n" + "Neighbor address\n" + "OSPF dead-router polling interval\n" + "Seconds\n" + "OSPF priority of non-broadcast neighbor\n" + "Priority\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community3_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, neighbor_attr_unchanged7_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop med as-path", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "Med attribute\n" + "As-path attribute\n") + +DEFSH (VTYSH_BGPD, neighbor_default_originate_rmap_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "default-originate route-map WORD", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Originate default route to this neighbor\n" + "Route-map to specify criteria to originate default\n" + "route-map name\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_priority_cmd_vtysh, + "ip ospf priority <0-255>", + "IP Information\n" + "OSPF interface commands\n" + "Router priority\n" + "Priority\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_metric_routemap_cmd_vtysh, + "no redistribute connected metric <0-16> route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, neighbor_allowas_in_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "allowas-in", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Accept as-path with my AS present in it\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_out_cmd_vtysh, + "clear ip bgp external ipv4 (unicast|multicast) out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, clear_bgp_all_in_cmd_vtysh, + "clear bgp * in", + "Reset functions\n" + "BGP information\n" + "Clear all peers\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, bgp_distance_source_access_list_cmd_vtysh, + "distance <1-255> A.B.C.D/M WORD", + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n" + "Access list name\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_regexp_cmd_vtysh, + "show ip bgp regexp .LINE", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_community4_cmd_vtysh, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_summary_cmd_vtysh, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn summary", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Summary of BGP neighbor status\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_route_type_detail_cmd_vtysh, + "show ipv6 ospf6 route (intra-area|inter-area|external-1|external-2) detail", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Routing Table\n" + "Dispaly Intra-Area routes\n" + "Dispaly Inter-Area routes\n" + "Dispaly Type-1 External routes\n" + "Dispaly Type-2 External routes\n" + "Detailed information\n" + ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_in_cmd_vtysh, + "clear ip bgp A.B.C.D in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, neighbor_attr_unchanged_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_out_cmd_vtysh, + "clear bgp ipv6 peer-group WORD out", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, debug_bgp_fsm_cmd_vtysh, + "debug bgp fsm", + "Debugging functions (see also 'undebug')\n" + "BGP information\n" + "BGP Finite State Machine\n") + +DEFSH (VTYSH_RIPNGD, ipv6_distribute_list_cmd_vtysh, + "distribute-list WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_cmd_vtysh, + "no redistribute bgp", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n") + +DEFSH (VTYSH_RIPD, rip_timers_cmd_vtysh, + "timers basic <5-2147483647> <5-2147483647> <5-2147483647>", + "Adjust routing timers\n" + "Basic routing protocol update timers\n" + "Routing table update timer value in second. Default is 30.\n" + "Routing information timeout timer. Default is 180.\n" + "Garbage collection timer. Default is 120.\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_prefix_list_seq_ge_le_cmd_vtysh, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_ipv4_soft_in_cmd_vtysh, + "clear ip bgp view WORD * ipv4 (unicast|multicast) soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, old_ipv6_aggregate_address_cmd_vtysh, + "ipv6 bgp aggregate-address X:X::X:X/M", + "IPv6 information\n" + "BGP information\n" + "Configure BGP aggregate entries\n" + "Aggregate prefix\n") + +DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged1_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged (as-path|next-hop|med)", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD, no_match_interface_cmd_vtysh, + "no match interface", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "Match first hop interface of route\n") + +DEFSH (VTYSH_ZEBRA, show_ipv6_route_prefix_longer_cmd_vtysh, + "show ipv6 route X:X::X:X/M longer-prefixes", + "Show running system information\n" + "IP information\n" + "IPv6 routing table\n" + "IPv6 prefix\n" + "Show route matching the specified Network/Mask pair only\n") + +DEFSH (VTYSH_OSPFD, ospf_priority_cmd_vtysh, + "ospf priority <0-255>", + "OSPF interface commands\n" + "Router priority\n" + "Priority\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_prefix_list_description_cmd_vtysh, + "ipv6 prefix-list WORD description .LINE", + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Prefix-list specific description\n" + "Up to 80 characters describing this prefix-list\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_all_cmd_vtysh, + "show bgp ipv6 community", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes matching the communities\n") + +DEFSH (VTYSH_OSPFD, no_router_ospf_id_cmd_vtysh, + "no router-id", + "Negate a command or set its defaults\n" + "router-id for the OSPF process\n") + +DEFSH (VTYSH_BGPD, no_neighbor_advertise_interval_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X) " "advertisement-interval", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Minimum interval between sending BGP routing updates\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community3_cmd_vtysh, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_RIPD, send_lifetime_duration_day_month_cmd_vtysh, + "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ip_prefix_list_seq_cmd_vtysh, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)", + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_prefix_cmd_vtysh, + "no ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") + +DEFSH (VTYSH_BGPD, clear_bgp_as_soft_cmd_vtysh, + "clear bgp <1-65535> soft", + "Reset functions\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_cmd_vtysh, + "show bgp ipv6", + "Show running system information\n" + "BGP information\n" + "Address family\n") + +DEFSH (VTYSH_BGPD, bgp_scan_time_cmd_vtysh, + "bgp scan-time <5-60>", + "BGP specific commands\n" + "Configure background scanner interval\n" + "Scanner interval (seconds)\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_message_digest_key_addr_cmd_vtysh, + "no ip ospf message-digest-key <1-255> A.B.C.D", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n" + "Address of interface") + +DEFSH (VTYSH_BGPD, no_neighbor_ebgp_multihop_ttl_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop <1-255>", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Allow EBGP neighbors not on directly connected networks\n" + "maximum hop count\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, show_ipv6_prefix_list_name_cmd_vtysh, + "show ipv6 prefix-list WORD", + "Show running system information\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n") + +DEFSH (VTYSH_RIPNGD, show_debugging_ripng_cmd_vtysh, + "show debugging ripng", + "Show running system information\n" + "RIPng configuration\n" + "Debugging information\n") + +DEFSH (VTYSH_BGPD, ip_community_list_standard2_cmd_vtysh, + "ip community-list <1-99> (deny|permit)", + "IP information\n" + "Add a community list entry\n" + "Community list number (standard)\n" + "Specify community to reject\n" + "Specify community to accept\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_access_list_cmd_vtysh, + "show ip access-list", + "Show running system information\n" + "IP information\n" + "List IP access lists\n") + +DEFSH (VTYSH_BGPD, ipv6_bgp_neighbor_advertised_route_cmd_vtysh, + "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") + +DEFSH (VTYSH_BGPD, no_set_origin_val_cmd_vtysh, + "no set origin (egp|igp|incomplete)", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP origin code\n" + "remote EGP\n" + "local IGP\n" + "unknown heritage\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbor_routes_cmd_vtysh, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) routes", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") + +DEFSH (VTYSH_OSPFD, debug_ospf_lsa_cmd_vtysh, + "debug ospf lsa", + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Link State Advertisement\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_message_cmd_vtysh, + "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 message\n" + "Debug Unknown message\n" + "Debug Hello message\n" + "Debug Database Description message\n" + "Debug Link State Request message\n" + "Debug Link State Update message\n" + "Debug Link State Acknowledgement message\n" + "Debug All message\n" + ) + +DEFSH (VTYSH_BGPD, no_neighbor_dont_capability_negotiate_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "dont-capability-negotiate", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Do not perform capability negotiation\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_soft_cmd_vtysh, + "clear ip bgp view WORD * soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_dead_interval_cmd_vtysh, + "ip ospf dead-interval <1-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n" + "Seconds\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_cmd_vtysh, + "distance ospf inter-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_message_digest_key_cmd_vtysh, + "no ip ospf message-digest-key <1-255>", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_soft_cmd_vtysh, + "clear ip bgp peer-group WORD soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_zebra_sendrecv_cmd_vtysh, + "debug ospf6 zebra (send|recv)", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug connection between zebra\n" + "Debug Sending zebra\n" + "Debug Receiving zebra\n" + ) + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_ospf6_metric_cmd_vtysh, + "redistribute ospf6 metric <0-16>", + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n" + "Metric value\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_soft_cmd_vtysh, + "clear ip bgp <1-65535> soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Soft reconfig\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_vlink_param1_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" ) + +DEFSH (VTYSH_OSPFD, no_debug_ospf_zebra_sub_cmd_vtysh, + "no debug ospf zebra (interface|redistribute)", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Zebra information\n" + "Zebra interface\n" + "Zebra redistribute\n") + +DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_cmd_vtysh, + "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" "|max-age|self-originate)", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Database summary\n" + "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" "" + "LSAs in MaxAge list\n" + "Self-originated link states\n") + +DEFSH (VTYSH_BGPD, neighbor_prefix_list_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "prefix-list WORD (in|out)", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Filter updates to/from this neighbor\n" + "Name of a prefix list\n" + "Filter incoming updates\n" + "Filter outgoing updates\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_cmd_vtysh, + "no ip prefix-list WORD", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_metric_cmd_vtysh, + "default-information originate always metric <0-16777214>", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_standard_nomask_cmd_vtysh, + "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D", + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Address to match\n") + +DEFSH (VTYSH_BGPD, neighbor_default_originate_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "default-originate", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Originate default route to this neighbor\n") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_message_sendrecv_cmd_vtysh, + "no debug ospf6 message " + "(unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 message\n" + "Debug Unknown message\n" + "Debug Hello message\n" + "Debug Database Description message\n" + "Debug Link State Request message\n" + "Debug Link State Update message\n" + "Debug Link State Acknowledgement message\n" + "Debug All message\n" + "Debug only sending message\n" + "Debug only receiving message\n" + ) + +DEFSH (VTYSH_RIPD, no_rip_route_cmd_vtysh, + "no route A.B.C.D/M", + "Negate a command or set its defaults\n" + "RIP static route configuration\n" + "IP prefix /\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_linkstate_router_cmd_vtysh, + "show ipv6 ospf6 linkstate router A.B.C.D", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Display linkstate routing table\n" + "Display Router Entry\n" + "Specify Router ID as IPv4 address notation\n" + ) + +DEFSH (VTYSH_RIPD, rip_default_metric_cmd_vtysh, + "default-metric <1-16>", + "Set a metric of redistribute routes\n" + "Default metric\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_dead_interval_addr_cmd_vtysh, + "no ip ospf dead-interval A.B.C.D", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n" + "Address of interface") + +DEFSH (VTYSH_RIPNGD, show_ipv6_ripng_cmd_vtysh, + "show ipv6 ripng", + "Show running system information\n" + "IP information\n" + "Show RIPng routes\n") + +DEFSH (VTYSH_OSPFD, ospf_compatible_rfc1583_cmd_vtysh, + "compatible rfc1583", + "OSPF compatibility list\n" + "compatible with RFC 1583\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_routemap_cmd_vtysh, + "no redistribute static route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, neighbor_attr_unchanged1_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged (as-path|next-hop|med)", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_spf_process_cmd_vtysh, + "debug ospf6 spf process", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug SPF Calculation\n" + "Debug Detailed SPF Process\n" + ) + +DEFSH (VTYSH_BGPD, dump_bgp_routes_interval_cmd_vtysh, + "dump bgp routes-mrt PATH INTERVAL", + "Dump packet\n" + "BGP packet dump\n" + "Dump whole BGP routing table\n" + "Output filename\n" + "Interval of output\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_kernel_routemap_cmd_vtysh, + "redistribute kernel route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_interface_prefix_match_cmd_vtysh, + "show ipv6 ospf6 interface prefix X:X::X:X/M (match|detail)", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Interface infomation\n" + "Display connected prefixes to advertise\n" + "Display the route\n" + "Display the route matches the prefix\n" + "Dispaly details of the prefixes\n" + ) + +DEFSH (VTYSH_OSPFD, ip_ospf_authentication_args_cmd_vtysh, + "ip ospf authentication (null|message-digest)", + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n" + "Use null authentication\n" + "Use message-digest authentication\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community4_exact_cmd_vtysh, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, clear_bgp_as_soft_out_cmd_vtysh, + "clear bgp <1-65535> soft out", + "Reset functions\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_neighbors_cmd_vtysh, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_timers_cmd_vtysh, + "no timers basic", + "Negate a command or set its defaults\n" + "RIPng timers setup\n" + "Basic timer\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_prefix_list_cmd_vtysh, + "show ip prefix-list", + "Show running system information\n" + "IP information\n" + "Build a prefix list\n" ) + +DEFSH (VTYSH_BGPD, no_match_community_val_cmd_vtysh, + "no match community (<1-99>|<100-500>|WORD)", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "Match BGP community list\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n") + +DEFSH (VTYSH_RIPD|VTYSH_BGPD, no_set_ip_nexthop_val_cmd_vtysh, + "no set ip next-hop A.B.C.D", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "IP information\n" + "Next hop address\n" + "IP address of next hop\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_sequence_number_cmd_vtysh, + "no ip prefix-list sequence-number", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Include/exclude sequence numbers in NVGEN\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_in_cmd_vtysh, + "clear bgp ipv6 <1-65535> in", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_RIPD, no_ip_rip_receive_version_cmd_vtysh, + "no ip rip receive version", + "Negate a command or set its defaults\n" + "IP information\n" + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_cmd_vtysh, + "default-information originate always", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_in_cmd_vtysh, + "clear ip bgp * vpnv4 unicast in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbor_received_routes_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received-routes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") + +DEFSH (VTYSH_OSPFD, no_ospf_neighbor_poll_interval_cmd_vtysh, + "no neighbor A.B.C.D poll-interval <1-65535>", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor IP address\n" + "Dead Neighbor Polling interval\n" + "Seconds\n") + +DEFSH (VTYSH_BGPD, no_debug_bgp_normal_cmd_vtysh, + "no debug bgp", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "BGP information\n" ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_out_cmd_vtysh, + "clear ip bgp A.B.C.D vpnv4 unicast out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_metric_routemap_cmd_vtysh, + "default-information originate always metric <0-16777214> route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_metric_cmd_vtysh, + "default-information originate metric <0-16777214>", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF default metric\n" + "OSPF metric\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_standard_cmd_vtysh, + "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Address to match\n" + "Wildcard bits\n") + +DEFSH (VTYSH_ZEBRA, shutdown_if_cmd_vtysh, + "shutdown", + "Shutdown the selected interface\n") + +DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv6_metric_rmap_cmd_vtysh, + "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, no_neighbor_route_reflector_client_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "route-reflector-client", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Configure a neighbor as Route Reflector client\n") + +DEFSH (VTYSH_RIPD, no_rip_distance_source_cmd_vtysh, + "no distance <1-255> A.B.C.D/M", + "Negate a command or set its defaults\n" + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_soft_out_cmd_vtysh, + "clear ip bgp view WORD * soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_OSPFD, no_debug_ospf_event_cmd_vtysh, + "no debug ospf event", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF event information\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_cmd_vtysh, + "clear ip bgp (A.B.C.D|X:X::X:X)", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor IP address to clear\n" + "BGP IPv6 neighbor to clear\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_dampened_paths_cmd_vtysh, + "show ip bgp dampened-paths", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display paths suppressed due to dampening\n") + +DEFSH (VTYSH_BGPD, no_debug_bgp_filter_cmd_vtysh, + "no debug bgp filters", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "BGP information\n" + "BGP filters\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, clear_ip_prefix_list_cmd_vtysh, + "clear ip prefix-list", + "Reset functions\n" + "IP information\n" + "Build a prefix list\n" ) + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_prefix_cmd_vtysh, + "no ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Any prefix match. Same as \"::0/0 le 128\"\n") + +DEFSH (VTYSH_OSPFD, no_ospf_distribute_list_out_cmd_vtysh, + "no distribute-list WORD out (kernel|connected|static|rip|bgp)", + "Negate a command or set its defaults\n" + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter outgoing routing updates\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n") + +DEFSH (VTYSH_BGPD, no_aggregate_address_summary_as_set_cmd_vtysh, + "no aggregate-address A.B.C.D/M summary-only as-set", + "Negate a command or set its defaults\n" + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n" + "Generate AS set path information\n") + +DEFSH (VTYSH_RIPD, debug_rip_events_cmd_vtysh, + "debug rip events", + "Debugging functions (see also 'undebug')\n" + "RIP information\n" + "RIP events\n") + +DEFSH (VTYSH_BGPD, no_set_ecommunity_rt_cmd_vtysh, + "no set extcommunity rt", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP extended community attribute\n" + "Route Target extened communityt\n") + +DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged10_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med as-path next-hop", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "As-path attribute\n" + "Nexthop attribute\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_zebra_cmd_vtysh, + "debug ospf6 zebra", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug connection between zebra\n" + ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_soft_cmd_vtysh, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, undebug_bgp_normal_cmd_vtysh, + "undebug bgp", + "Disable debugging functions (see also 'debug')\n" + "BGP information\n" ) + +DEFSH (VTYSH_OSPFD, no_ip_ospf_retransmit_interval_addr_cmd_vtysh, + "no ip ospf retransmit-interval A.B.C.D", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n" + "Address of interface") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_interface_cmd_vtysh, + "no debug ospf6 interface", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 Interface\n" + ) + +DEFSH (VTYSH_RIPNGD, no_ipv6_distribute_list_prefix_all_cmd_vtysh, + "no distribute-list prefix WORD (in|out)", + "Negate a command or set its defaults\n" + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_routemap_cmd_vtysh, + "no redistribute bgp route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_in_prefix_filter_cmd_vtysh, + "clear ip bgp * in prefix-filter", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_access_list_remark_cmd_vtysh, + "no ipv6 access-list WORD remark", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Access list entry comment\n") + +DEFSH (VTYSH_BGPD, no_match_community_exact_cmd_vtysh, + "no match community (<1-99>|<100-500>|WORD) exact-match", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "Match BGP community list\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n" + "Do exact matching of communities\n") + +DEFSH (VTYSH_BGPD, no_set_ecommunity_cost_igp_val_cmd_vtysh, + "no set extcommunity cost igp <0-255> <0-4294967295>", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP extended community attribute\n" + "Cost extended community\n" + "Compare following IGP cost comparison\n" + "Community ID\n" + "Cost Value\n" + "VPN extended community\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_in_prefix_filter_cmd_vtysh, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) in prefix-filter", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_RIPD, distribute_list_cmd_vtysh, + "distribute-list WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_out_cmd_vtysh, + "clear bgp ipv6 external WORD out", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all external peers\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_authentication_cmd_vtysh, + "ip ospf authentication", + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_inter_intra_cmd_vtysh, + "distance ospf inter-area <1-255> intra-area <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "Intra-area routes\n" + "Distance for intra-area routes\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_out_cmd_vtysh, + "clear ip bgp <1-65535> vpnv4 unicast out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, show_bgp_summary_cmd_vtysh, + "show bgp summary", + "Show running system information\n" + "BGP information\n" + "Summary of BGP neighbor status\n") + +DEFSH (VTYSH_BGPD, bgp_deterministic_med_cmd_vtysh, + "bgp deterministic-med", + "BGP specific commands\n" + "Pick the best-MED path among paths advertised from the neighboring AS\n") + +DEFSH (VTYSH_OSPFD, ospf_area_filter_list_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Filter networks between OSPF areas\n" + "Filter prefixes between OSPF areas\n" + "Name of an IP prefix-list\n" + "Filter networks sent to this area\n" + "Filter networks sent from this area\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_prefix_list_le_ge_cmd_vtysh, + "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_BGPD, undebug_bgp_filter_cmd_vtysh, + "undebug bgp filters", + "Disable debugging functions (see also 'debug')\n" + "BGP information\n" + "BGP filters\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_cmd_vtysh, + "show ipv6 ospf6", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" ) + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_in_prefix_filter_cmd_vtysh, + "clear bgp ipv6 external in prefix-filter", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all external peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_OSPFD, no_ospf_auto_cost_reference_bandwidth_cmd_vtysh, + "no auto-cost reference-bandwidth", + "Negate a command or set its defaults\n" + "Calculate OSPF interface cost according to bandwidth\n" + "Use reference bandwidth method to assign OSPF cost\n") + +DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_cmd_vtysh, + "redistribute (connected|kernel|ospf|rip|static)", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n") + +DEFSH (VTYSH_BGPD, neighbor_filter_list_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "filter-list WORD (in|out)", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Establish BGP filters\n" + "AS path access-list name\n" + "Filter incoming routes\n" + "Filter outgoing routes\n") + +DEFSH (VTYSH_OSPFD, ospf_network_area_cmd_vtysh, + "network A.B.C.D/M area (A.B.C.D|<0-4294967295>)", + "Enable routing on an IP network\n" + "OSPF network prefix\n" + "Set the OSPF area ID\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n") + +DEFSH (VTYSH_BGPD, neighbor_attr_unchanged10_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med as-path next-hop", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "As-path attribute\n" + "Nexthop attribute\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, clear_ip_prefix_list_name_cmd_vtysh, + "clear ip prefix-list WORD", + "Reset functions\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n") + +DEFSH (VTYSH_RIPNGD, ipv6_distribute_list_prefix_cmd_vtysh, + "distribute-list prefix WORD (in|out) WORD", + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_ZEBRA, show_ip_route_cmd_vtysh, + "show ip route", + "Show running system information\n" + "IP information\n" + "IP routing table\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_connected_cmd_vtysh, + "redistribute connected", + "Redistribute information from another routing protocol\n" + "Connected\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_cmd_vtysh, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, clear_bgp_peer_in_prefix_filter_cmd_vtysh, + "clear bgp (A.B.C.D|X:X::X:X) in prefix-filter", + "Reset functions\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig inbound update\n" + "Push out the existing ORF prefix-list\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD, rmap_show_name_cmd_vtysh, + "show route-map WORD", + "Show running system information\n" + "route-map information\n" + "route-map name\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_intra_external_cmd_vtysh, + "distance ospf intra-area <1-255> external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "External routes\n" + "Distance for external routes\n") + +DEFSH (VTYSH_OSPF6D, no_router_ospf6_cmd_vtysh, + "no router ospf6", + "Negate a command or set its defaults\n" + "Enable a routing process\n" ) + +DEFSH (VTYSH_BGPD, ipv6_mbgp_neighbor_received_routes_cmd_vtysh, + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) received-routes", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_range_advertise_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M (advertise|not-advertise)", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Advertise this range (default)\n" + "DoNotAdvertise this range\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_metric_type_routemap_cmd_vtysh, + "default-information originate always metric <0-16777214> metric-type (1|2) route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_seq_cmd_vtysh, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_seq_le_ge_cmd_vtysh, + "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_in_prefix_filter_cmd_vtysh, + "clear bgp ipv6 * in prefix-filter", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_neighbors_cmd_vtysh, + "show ip bgp vpnv4 all neighbors", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbors_cmd_vtysh, + "show bgp ipv6 neighbors", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n") + +DEFSH (VTYSH_RIPNGD, ripng_if_rmap_cmd_vtysh, + "route-map RMAP_NAME (in|out) IFNAME", + "Route map set\n" + "Route map name\n" + "Route map set for input filtering\n" + "Route map set for output filtering\n" + "Route map interface name\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_metric_routemap_cmd_vtysh, + "no redistribute kernel metric <0-16> route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, old_no_ipv6_aggregate_address_summary_only_cmd_vtysh, + "no ipv6 bgp aggregate-address X:X::X:X/M summary-only", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "BGP information\n" + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n") + +DEFSH (VTYSH_OSPFD, ospf_area_vlink_param3_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" ) + +DEFSH (VTYSH_OSPFD, ospf_area_vlink_authtype_md5_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) " + "(message-digest-key|) <1-255> md5 KEY", + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Enable authentication on this virtual link\n" "dummy string \n" + "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)" ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_in_prefix_filter_cmd_vtysh, + "clear ip bgp view WORD * in prefix-filter", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_expanded_all_cmd_vtysh, + "no ip extcommunity-list <100-500>", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a extended community list entry\n" + "Extended Community list number (expanded)\n") + +DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_standard_cmd_vtysh, + "no ip extcommunity-list <1-99> (deny|permit) .AA:NN", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a extended community list entry\n" + "Extended Community list number (standard)\n" + "Specify community to reject\n" + "Specify community to accept\n" + "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n" ) + +DEFSH (VTYSH_BGPD, no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> <1-100> warning-only", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Threshold value (%) at which to generate a warning msg\n" + "Only give warning message when limit is exceeded\n") + +DEFSH (VTYSH_OSPFD, ospf_distribute_list_out_cmd_vtysh, + "distribute-list WORD out (kernel|connected|static|rip|bgp)", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter outgoing routing updates\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_access_list_remark_arg_cmd_vtysh, + "no ipv6 access-list WORD remark .LINE", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Access list entry comment\n" + "Comment up to 100 characters\n") + +DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_standard_all_cmd_vtysh, + "no ip extcommunity-list <1-99>", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a extended community list entry\n" + "Extended Community list number (standard)\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_flap_statistics_cmd_vtysh, + "show ip bgp flap-statistics", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display flap statistics of routes\n") + +DEFSH (VTYSH_ZEBRA, show_ip_route_supernets_cmd_vtysh, + "show ip route supernets-only", + "Show running system information\n" + "IP information\n" + "IP routing table\n" + "Show supernet entries only\n") + +DEFSH (VTYSH_BGPD, set_metric_addsub_cmd_vtysh, + "set metric <+/-metric>", + "Set values in destination routing protocol\n" + "Metric value for destination routing protocol\n" + "Add or subtract BGP metric\n") + +DEFSH (VTYSH_BGPD, set_ipv6_nexthop_local_cmd_vtysh, + "set ipv6 next-hop local X:X::X:X", + "Set values in destination routing protocol\n" + "IPv6 information\n" + "IPv6 next-hop address\n" + "IPv6 local address\n" + "IPv6 address of next hop\n") + +DEFSH (VTYSH_OSPFD, no_ospf_rfc1583_flag_cmd_vtysh, + "no ospf rfc1583compatibility", + "Negate a command or set its defaults\n" + "OSPF specific commands\n" + "Disable the RFC1583Compatibility flag\n") + +DEFSH (VTYSH_BGPD, neighbor_route_map_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "route-map WORD (in|out)", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Apply route map to neighbor\n" + "Name of route map\n" + "Apply map to incoming routes\n" + "Apply map to outbound routes\n") + +DEFSH (VTYSH_BGPD, no_debug_bgp_keepalive_cmd_vtysh, + "no debug bgp keepalives", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "BGP information\n" + "BGP keepalives\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_community3_exact_cmd_vtysh, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, no_bgp_network_mask_natural_route_map_cmd_vtysh, + "no network A.B.C.D route-map WORD", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "Network number\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community_all_cmd_vtysh, + "show ipv6 mbgp community", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes matching the communities\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD, no_route_map_cmd_vtysh, + "no route-map WORD (deny|permit) <1-65535>", + "Negate a command or set its defaults\n" + "Create route-map or enter route-map command mode\n" + "Route map tag\n" + "Route map denies set operations\n" + "Route map permits set operations\n" + "Sequence to insert to/delete from existing route-map entry\n") + +DEFSH (VTYSH_ZEBRA, ip_address_cmd_vtysh, + "ip address A.B.C.D/M", + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_ge_cmd_vtysh, + "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_OSPFD, ospf_area_range_advertise_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "OSPF area range for route advertise (default)\n" + "Area range prefix\n" + "Advertise this range (default)\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_sequence_number_cmd_vtysh, + "no ipv6 prefix-list sequence-number", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Include/exclude sequence numbers in NVGEN\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n") + +DEFSH (VTYSH_OSPFD, ospf_area_import_list_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) import-list NAME", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Set the filter for networks from other areas announced to the specified one\n" + "Name of the access-list\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_any_host_cmd_vtysh, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "A single destination host\n" + "Destination address\n") + +DEFSH (VTYSH_OSPF6D, ospf6_interface_area_cmd_vtysh, + "interface IFNAME area A.B.C.D", + "Enable routing on an IPv6 interface\n" + "Interface name(e.g. ep0)\n" + "Specify the OSPF6 area ID\n" + "OSPF6 area ID in IPv4 address notation\n" + ) + +DEFSH (VTYSH_BGPD, ipv6_mbgp_neighbor_routes_cmd_vtysh, + "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n") + +DEFSH (VTYSH_BGPD, no_ip_extcommunity_list_expanded_cmd_vtysh, + "no ip extcommunity-list <100-500> (deny|permit) .LINE", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a extended community list entry\n" + "Extended Community list number (expanded)\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") + +DEFSH (VTYSH_RIPD, no_ip_rip_authentication_key_chain_cmd_vtysh, + "no ip rip authentication key-chain", + "Negate a command or set its defaults\n" + "IP information\n" + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication key-chain\n") + +DEFSH (VTYSH_OSPFD, no_ospf_default_information_originate_cmd_vtysh, + "no default-information originate", + "Negate a command or set its defaults\n" + "Control distribution of default information\n" + "Distribute a default route\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_interface_ifname_prefix_match_cmd_vtysh, + "show ipv6 ospf6 interface IFNAME prefix X:X::X:X/M (match|detail)", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Interface infomation\n" + "Interface name(e.g. ep0)\n" + "Display connected prefixes to advertise\n" + "Display the route\n" + "Display the route matches the prefix\n" + "Dispaly details of the prefixes\n" + ) + +DEFSH (VTYSH_BGPD, no_bgp_bestpath_med_cmd_vtysh, + "no bgp bestpath med (confed|missing-as-worst)", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Change the default bestpath selection\n" + "MED attribute\n" + "Compare MED among confederation paths\n" + "Treat missing MED as the least preferred one\n") + +DEFSH (VTYSH_ZEBRA, ip_route_cmd_vtysh, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)", + "IP information\n" + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n") + +DEFSH (VTYSH_BGPD, neighbor_unsuppress_map_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "unsuppress-map WORD", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Route-map to selectively unsuppress suppressed routes\n" + "Name of route map\n") + +DEFSH (VTYSH_RIPNGD, ripng_route_cmd_vtysh, + "route IPV6ADDR", + "Static route setup\n" + "Set static RIPng route announcement\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_damp_cmd_vtysh, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the dampened routes received from neighbor\n") + +DEFSH (VTYSH_RIPD, send_lifetime_month_day_day_month_cmd_vtysh, + "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD, no_route_map_all_cmd_vtysh, + "no route-map WORD", + "Negate a command or set its defaults\n" + "Create route-map or enter route-map command mode\n" + "Route map tag\n") + +DEFSH (VTYSH_RIPD, no_rip_network_cmd_vtysh, + "no network (A.B.C.D/M|WORD)", + "Negate a command or set its defaults\n" + "Enable routing on an IP network\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Interface name\n") + +DEFSH (VTYSH_BGPD, bgp_network_mask_route_map_cmd_vtysh, + "network A.B.C.D mask A.B.C.D route-map WORD", + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + +DEFSH (VTYSH_BGPD, set_vpnv4_nexthop_cmd_vtysh, + "set vpnv4 next-hop A.B.C.D", + "Set values in destination routing protocol\n" + "VPNv4 information\n" + "VPNv4 next-hop address\n" + "IP address of next hop\n") + +DEFSH (VTYSH_OSPFD, no_debug_ospf_packet_send_recv_detail_cmd_vtysh, + "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", + "Negate a command or set its defaults\n" + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail Information\n") + +DEFSH (VTYSH_RIPD, no_rip_default_metric_cmd_vtysh, + "no default-metric", + "Negate a command or set its defaults\n" + "Set a metric of redistribute routes\n" + "Default metric\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_soft_out_cmd_vtysh, + "clear ip bgp peer-group WORD soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_route_cmd_vtysh, + "show ipv6 mbgp X:X::X:X", + "Show running system information\n" + "IP information\n" + "MBGP information\n" + "Network in the MBGP routing table to display\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_in_cmd_vtysh, + "clear ip bgp external ipv4 (unicast|multicast) in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_OSPF6D, area_range_advertise_cmd_vtysh, + "area A.B.C.D range X:X::X:X/M (advertise|not-advertise)", + "OSPF area parameters\n" + "Area ID (as an IPv4 notation)\n" + "Configured address range\n" + "Specify IPv6 prefix\n" + ) + +DEFSH (VTYSH_OSPFD, router_ospf_id_cmd_vtysh, + "router-id A.B.C.D", + "router-id for the OSPF process\n" + "OSPF router-id in IP address format\n") + +DEFSH (VTYSH_ZEBRA, ipv6_route_pref_cmd_vtysh, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE|null0) <1-255>", + "IP information\n" + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n") + +DEFSH (VTYSH_BGPD, no_bgp_default_local_preference_val_cmd_vtysh, + "no bgp default local-preference <0-4294967295>", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Configure BGP defaults\n" + "local preference (higher=more preferred)\n" + "Configure default local preference value\n") + +DEFSH (VTYSH_RIPNGD, ripng_timers_cmd_vtysh, + "timers basic <0-65535> <0-65535> <0-65535>", + "RIPng timers setup\n" + "Basic timer\n" + "Routing table update timer value in second. Default is 30.\n" + "Routing information timeout timer. Default is 180.\n" + "Garbage collection timer. Default is 120.\n") + +DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged8_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop as-path med", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "As-path attribute\n" + "Med attribute\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_community2_cmd_vtysh, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_OSPFD, no_set_metric_type_cmd_vtysh, + "no set metric-type", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "Type of metric for destination routing protocol\n") + +DEFSH (VTYSH_BGPD, neighbor_peer_group_cmd_vtysh, + "neighbor WORD peer-group", + "Specify neighbor router\n" + "Neighbor tag\n" + "Configure peer-group\n") + +DEFSH (VTYSH_BGPD|VTYSH_BGPD, no_neighbor_maximum_prefix_warning_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> warning-only", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Maximum number of prefix accept from this peer\n" + "maximum no. of prefix limit\n" + "Only give warning message when limit is exceeded\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_community_exact_cmd_vtysh, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, bgp_enforce_first_as_cmd_vtysh, + "bgp enforce-first-as", + "BGP information\n" + "Enforce the first AS for EBGP routes(default)\n") + +DEFSH (VTYSH_BGPD, show_bgp_community3_exact_cmd_vtysh, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_OSPFD, ospf_dead_interval_cmd_vtysh, + "ospf dead-interval <1-65535>", + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n" + "Seconds\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_soft_cmd_vtysh, + "clear bgp ipv6 peer-group WORD soft", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n") + +DEFSH (VTYSH_OSPFD, ospf_neighbor_cmd_vtysh, + "neighbor A.B.C.D", + "Specify neighbor router\n" + "Neighbor IP address\n") + +DEFSH (VTYSH_BGPD, clear_bgp_external_cmd_vtysh, + "clear bgp external", + "Reset functions\n" + "BGP information\n" + "Clear all external peers\n") + +DEFSH (VTYSH_BGPD, no_ip_community_list_name_standard_cmd_vtysh, + "no ip community-list standard WORD (deny|permit) .AA:NN", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a community list entry\n" + "Specify a standard community-list\n" + "Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n" ) + +DEFSH (VTYSH_BGPD, neighbor_update_source_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "update-source WORD", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Source of routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_in_cmd_vtysh, + "clear ip bgp peer-group WORD in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, ip_extcommunity_list_name_standard_cmd_vtysh, + "ip extcommunity-list standard WORD (deny|permit) .AA:NN", + "IP information\n" + "Add a extended community list entry\n" + "Specify standard extcommunity-list\n" + "Extended Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n" ) + +DEFSH (VTYSH_BGPD, no_ipv6_bgp_network_cmd_vtysh, + "no network X:X::X:X/M", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_connected_metric_val_cmd_vtysh, + "no redistribute connected metric <0-16>", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Metric\n" + "Metric value\n") + +DEFSH (VTYSH_RIPD, ip_rip_receive_version_1_cmd_vtysh, + "ip rip receive version 1 2", + "IP information\n" + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") + +DEFSH (VTYSH_BGPD, no_match_ecommunity_val_cmd_vtysh, + "no match extcommunity (<1-99>|<100-500>|WORD)", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "Match BGP/VPN extended community list\n" + "Extended community-list number (standard)\n" + "Extended community-list number (expanded)\n" + "Extended community-list name\n") + +DEFSH (VTYSH_ZEBRA, show_interface_cmd_vtysh, + "show interface [IFNAME]", + "Show running system information\n" + "Interface status and configuration\n" + "Inteface name\n") + +DEFSH (VTYSH_BGPD, no_bgp_network_mask_cmd_vtysh, + "no network A.B.C.D mask A.B.C.D", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n") + +DEFSH (VTYSH_OSPFD, no_router_ospf_cmd_vtysh, + "no router ospf", + "Negate a command or set its defaults\n" + "Enable a routing process\n" + "Start OSPF configuration\n") + +DEFSH (VTYSH_BGPD, no_bgp_confederation_identifier_cmd_vtysh, + "no bgp confederation identifier", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "AS confederation parameters\n" + "AS number\n") + +DEFSH (VTYSH_OSPFD, ospf_redistribute_source_metric_type_routemap_cmd_vtysh, + "redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> metric-type (1|2) route-map WORD", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "Metric for redistributed routes\n" + "OSPF default metric\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, no_neighbor_local_as_val2_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as <1-65535> no-prepend", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Specify a local-as number\n" + "AS number used as local AS\n" + "Do not prepend local-as to updates from ebgp peers\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_community_info_cmd_vtysh, + "show ip bgp community-info", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "List all bgp community information\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_cidr_only_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) cidr-only", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display only routes with non-natural netmasks\n") + +DEFSH (VTYSH_BGPD, bgp_redistribute_ipv4_metric_cmd_vtysh, + "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_neighbor_detail_cmd_vtysh, + "debug ospf6 neighbor (state|event)", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 Neighbor\n" + "Debug OSPFv3 Neighbor State Change\n" + "Debug OSPFv3 Neighbor Event\n" + ) + +DEFSH (VTYSH_BGPD, no_bgp_log_neighbor_changes_cmd_vtysh, + "no bgp log-neighbor-changes", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Log neighbor up/down and reset reason\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_access_list_any_cmd_vtysh, + "ipv6 access-list WORD (deny|permit) any", + "IPv6 information\n" + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any prefixi to match\n") + +DEFSH (VTYSH_BGPD, undebug_bgp_fsm_cmd_vtysh, + "undebug bgp fsm", + "Disable debugging functions (see also 'debug')\n" + "Debugging functions (see also 'undebug')\n" + "BGP information\n" + "Finite State Machine\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ip_prefix_list_cmd_vtysh, + "ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)", + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") + +DEFSH (VTYSH_BGPD, bgp_bestpath_cost_community_ignore_cmd_vtysh, + "bgp bestpath cost-community ignore", + "BGP specific commands\n" + "Change the default bestpath selection\n" + "cost community\n" + "Ignore cost communities in bestpath selection\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_neighbor_detail_cmd_vtysh, + "show ipv6 ospf6 neighbor (detail|drchoice)", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Neighbor list\n" + "Display details\n" + "Display DR choices\n" + ) + +DEFSH (VTYSH_BGPD, no_bgp_network_import_check_cmd_vtysh, + "no bgp network import-check", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "BGP network command\n" + "Check BGP network route exists in IGP\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_soft_out_cmd_vtysh, + "clear ip bgp A.B.C.D soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_OSPFD, ospf_area_vlink_authtype_authkey_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(authentication|) " + "(authentication-key|) AUTH_KEY", + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Enable authentication on this virtual link\n" "dummy string \n" + "Authentication password (key)\n" "The OSPF password (key)" ) + +DEFSH (VTYSH_BGPD, no_ip_community_list_name_expanded_cmd_vtysh, + "no ip community-list expanded WORD (deny|permit) .LINE", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a community list entry\n" + "Specify an expanded community-list\n" + "Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") + +DEFSH (VTYSH_BGPD, ip_extcommunity_list_name_expanded_cmd_vtysh, + "ip extcommunity-list expanded WORD (deny|permit) .LINE", + "IP information\n" + "Add a extended community list entry\n" + "Specify expanded extcommunity-list\n" + "Extended Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") + +DEFSH (VTYSH_RIPD, no_rip_distance_cmd_vtysh, + "no distance <1-255>", + "Negate a command or set its defaults\n" + "Administrative distance\n" + "Distance value\n") + +DEFSH (VTYSH_ZEBRA, show_debugging_zebra_cmd_vtysh, + "show debugging zebra", + "Show running system information\n" + "Zebra configuration\n" + "Debugging information\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community_list_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") + +DEFSH (VTYSH_RIPD, no_rip_offset_list_ifname_cmd_vtysh, + "no offset-list WORD (in|out) <0-16> IFNAME", + "Negate a command or set its defaults\n" + "Modify RIP metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n" + "Interface to match\n") + +DEFSH (VTYSH_ZEBRA, show_ip_route_prefix_cmd_vtysh, + "show ip route A.B.C.D/M", + "Show running system information\n" + "IP information\n" + "IP routing table\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, no_neighbor_peer_group_remote_as_cmd_vtysh, + "no neighbor WORD remote-as <1-65535>", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor tag\n" + "Specify a BGP neighbor\n" + "AS number\n" ) + +DEFSH (VTYSH_BGPD, aggregate_address_mask_as_set_cmd_vtysh, + "aggregate-address A.B.C.D A.B.C.D as-set", + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Generate AS set path information\n") + +DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_id_adv_router_cmd_vtysh, + "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") A.B.C.D adv-router A.B.C.D", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Database summary\n" + "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" "" + "Link State ID (as an IP address)\n" + "Advertising Router link states\n" + "Advertising Router (as an IP address)\n") + +DEFSH (VTYSH_BGPD, no_dump_bgp_all_cmd_vtysh, + "no dump bgp all [PATH] [INTERVAL]", + "Negate a command or set its defaults\n" + "Dump packet\n" + "BGP packet dump\n" + "Dump all BGP packets\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_interface_prefix_detail_cmd_vtysh, + "show ipv6 ospf6 interface prefix (X:X::X:X|X:X::X:X/M|detail)", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Interface infomation\n" + "Display connected prefixes to advertise\n" + "Display the route bestmatches the address\n" + "Display the route\n" + "Dispaly details of the prefixes\n" + ) + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community4_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, neighbor_attr_unchanged8_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop as-path med", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "As-path attribute\n" + "Med attribute\n") + +DEFSH (VTYSH_BGPD, no_match_ip_route_source_prefix_list_cmd_vtysh, + "no match ip route-source prefix-list", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IP information\n" + "Match advertising source address of route\n" + "Match entries of prefix-lists\n") + +DEFSH (VTYSH_BGPD, no_bgp_config_type_cmd_vtysh, + "no bgp config-type", + "Negate a command or set its defaults\n" + "BGP information\n" + "Display configuration type\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_view_prefix_cmd_vtysh, + "show ip bgp view WORD A.B.C.D/M", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "BGP view name\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, aggregate_address_as_set_summary_cmd_vtysh, + "aggregate-address A.B.C.D/M as-set summary-only", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Generate AS set path information\n" + "Filter more specific routes from updates\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_cmd_vtysh, + "show ipv6 bgp", + "Show running system information\n" + "IP information\n" + "BGP information\n" ) + +DEFSH (VTYSH_OSPFD, no_ospf_distance_source_access_list_cmd_vtysh, + "no distance <1-255> A.B.C.D/M WORD", + "Negate a command or set its defaults\n" + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_ipv4_out_cmd_vtysh, + "clear ip bgp peer-group WORD ipv4 (unicast|multicast) out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_range_cost_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "User specified metric for this range\n" + "Advertised metric for this range\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_external_ipv4_soft_out_cmd_vtysh, + "clear ip bgp external ipv4 (unicast|multicast) soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all external peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, clear_bgp_instance_all_cmd_vtysh, + "clear bgp view WORD *", + "Reset functions\n" + "BGP information\n" + "BGP view\n" + "view name\n" + "Clear all peers\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_border_routers_detail_cmd_vtysh, + "show ipv6 ospf6 border-routers (A.B.C.D|detail)", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Display routing table for ABR and ASBR\n" + "Specify Router-ID\n" + "Display Detail\n" + ) + +DEFSH (VTYSH_BGPD, no_neighbor_port_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X) " "port", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Neighbor's BGP port\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_address_prefix_list_cmd_vtysh, + "no match ip address prefix-list", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IP information\n" + "Match address of route\n" + "Match entries of prefix-lists\n") + +DEFSH (VTYSH_BGPD, neighbor_passive_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "passive", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Don't send open messages to this neighbor\n") + +DEFSH (VTYSH_BGPD, clear_bgp_all_out_cmd_vtysh, + "clear bgp * out", + "Reset functions\n" + "BGP information\n" + "Clear all peers\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, bgp_damp_set2_cmd_vtysh, + "bgp dampening <1-45>", + "BGP Specific commands\n" + "Enable route-flap dampening\n" + "Half-life time for the penalty\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_prefix_list_detail_cmd_vtysh, + "show ip prefix-list detail", + "Show running system information\n" + "IP information\n" + "Build a prefix list\n" + "Detail of prefix lists\n") + +DEFSH (VTYSH_BGPD, neighbor_capability_dynamic_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "capability dynamic", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Advertise capability to the peer\n" + "Advertise dynamic capability to this neighbor\n") + +DEFSH (VTYSH_BGPD, neighbor_timers_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "timers <0-65535> <0-65535>", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP per neighbor timers\n" + "Keepalive interval\n" + "Holdtime\n") + +DEFSH (VTYSH_BGPD, undebug_bgp_all_cmd_vtysh, + "undebug all bgp", + "Disable debugging functions (see also 'debug')\n" + "Enable all debugging\n" + "BGP information\n" ) + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_cmd_vtysh, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n") + +DEFSH (VTYSH_BGPD, show_bgp_prefix_list_cmd_vtysh, + "show bgp prefix-list WORD", + "Show running system information\n" + "BGP information\n" + "Display routes conforming to the prefix-list\n" + "IPv6 prefix-list name\n") + +DEFSH (VTYSH_BGPD, no_set_vpnv4_nexthop_val_cmd_vtysh, + "no set vpnv4 next-hop A.B.C.D", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "VPNv4 information\n" + "VPNv4 next-hop address\n" + "IP address of next hop\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_external_soft_out_cmd_vtysh, + "clear bgp ipv6 external soft out", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_OSPFD, show_ip_ospf_interface_cmd_vtysh, + "show ip ospf interface [INTERFACE]", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Interface information\n" + "Interface name\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbors_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) neighbors", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n") + +DEFSH (VTYSH_BGPD, no_bgp_always_compare_med_cmd_vtysh, + "no bgp always-compare-med", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Allow comparing MED from different neighbors\n") + +DEFSH (VTYSH_BGPD, old_no_ipv6_aggregate_address_cmd_vtysh, + "no ipv6 bgp aggregate-address X:X::X:X/M", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "BGP information\n" + "Configure BGP aggregate entries\n" + "Aggregate prefix\n") + +DEFSH (VTYSH_BGPD, bgp_log_neighbor_changes_cmd_vtysh, + "bgp log-neighbor-changes", + "BGP specific commands\n" + "Log neighbor up/down and reset reason\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_type_metric_cmd_vtysh, + "default-information originate metric-type (1|2) metric <0-16777214>", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "OSPF default metric\n" + "OSPF metric\n") + +DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged2_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path (next-hop|med)", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") + +DEFSH (VTYSH_RIPD, debug_rip_packet_cmd_vtysh, + "debug rip packet", + "Debugging functions (see also 'undebug')\n" + "RIP information\n" + "RIP packet\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbor_advertised_route_cmd_vtysh, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n") + +DEFSH (VTYSH_RIPNGD, ripng_default_metric_cmd_vtysh, + "default-metric <1-16>", + "Set a metric of redistribute routes\n" + "Default metric\n") + +DEFSH (VTYSH_RIPD, no_rip_redistribute_type_cmd_vtysh, + "no redistribute (kernel|connected|static|ospf|bgp)", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPF)\n" + "Border Gateway Protocol (BGP)\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD, rmap_continue_seq_cmd_vtysh, + "continue <1-65535>", + "Continue on a different entry within the route-map\n" + "Route-map entry sequence number\n") + +DEFSH (VTYSH_BGPD, undebug_bgp_keepalive_cmd_vtysh, + "undebug bgp keepalives", + "Disable debugging functions (see also 'debug')\n" + "BGP information\n" + "BGP keepalives\n") + +DEFSH (VTYSH_BGPD, bgp_network_import_check_cmd_vtysh, + "bgp network import-check", + "BGP specific commands\n" + "BGP network command\n" + "Check BGP network route exists in IGP\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_soft_out_cmd_vtysh, + "clear ip bgp <1-65535> soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_cmd_vtysh, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "Destination address\n" + "Destination Wildcard bits\n") + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community4_cmd_vtysh, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, ip_as_path_cmd_vtysh, + "ip as-path access-list WORD (deny|permit) .LINE", + "IP information\n" + "BGP autonomous system path filter\n" + "Specify an access list name\n" + "Regular expression access list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "A regular-expression to match the BGP AS paths\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_out_cmd_vtysh, + "clear ip bgp * out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_RIPD, send_lifetime_day_month_month_day_cmd_vtysh, + "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPF6D, no_router_zebra_cmd_vtysh, + "no router zebra", + "Negate a command or set its defaults\n" + "Configure routing process\n" + "Disable connection to zebra daemon\n") + +DEFSH (VTYSH_RIPD, no_ip_rip_authentication_string_cmd_vtysh, + "no ip rip authentication string", + "Negate a command or set its defaults\n" + "IP information\n" + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication string\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_group_soft_out_cmd_vtysh, + "clear bgp ipv6 peer-group WORD soft out", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, no_neighbor_route_map_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "route-map WORD (in|out)", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Apply route map to neighbor\n" + "Name of route map\n" + "Apply map to incoming routes\n" + "Apply map to outbound routes\n") + +DEFSH (VTYSH_BGPD, ipv6_aggregate_address_summary_only_cmd_vtysh, + "aggregate-address X:X::X:X/M summary-only", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_range_advertise_cost_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Advertise this range (default)\n" + "User specified metric for this range\n" + "Advertised metric for this range\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_transmit_delay_cmd_vtysh, + "no ip ospf transmit-delay", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Link state transmit delay\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_le_ge_cmd_vtysh, + "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, bgp_network_route_map_cmd_vtysh, + "network A.B.C.D/M route-map WORD", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_community_list_cmd_vtysh, + "show ip bgp community-list (<1-500>|WORD)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n") + +DEFSH (VTYSH_RIPD, accept_lifetime_infinite_month_day_cmd_vtysh, + "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Never expires") + +DEFSH (VTYSH_ZEBRA, no_ip_route_mask_cmd_vtysh, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)", + "Negate a command or set its defaults\n" + "IP information\n" + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n") + +DEFSH (VTYSH_OSPFD, ospf_redistribute_source_type_metric_cmd_vtysh, + "redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Routing Information Protocol (RIP)\n" + "Border Gateway Protocol (BGP)\n" + "OSPF exterior metric type for redistributed routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Metric for redistributed routes\n" + "OSPF default metric\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_out_cmd_vtysh, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_in_cmd_vtysh, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) in", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_out_cmd_vtysh, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) out", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, neighbor_override_capability_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "override-capability", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Override capability negotiation result\n") + +DEFSH (VTYSH_BGPD, neighbor_disable_connected_check_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "disable-connected-check", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "one-hop away EBGP peer using loopback address\n") + +DEFSH (VTYSH_BGPD, no_dump_bgp_updates_cmd_vtysh, + "no dump bgp updates [PATH] [INTERVAL]", + "Negate a command or set its defaults\n" + "Dump packet\n" + "BGP packet dump\n" + "Dump BGP updates only\n") + +DEFSH (VTYSH_OSPFD, debug_ospf_lsa_sub_cmd_vtysh, + "debug ospf lsa (generate|flooding|install|refresh)", + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Link State Advertisement\n" + "LSA Generation\n" + "LSA Flooding\n" + "LSA Install/Delete\n" + "LSA Refresh\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_hello_interval_cmd_vtysh, + "ip ospf hello-interval <1-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Time between HELLO packets\n" + "Seconds\n") + +DEFSH (VTYSH_BGPD, neighbor_nexthop_self_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "next-hop-self", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Disable the next hop calculation for this neighbor\n") + +DEFSH (VTYSH_RIPD, accept_lifetime_month_day_day_month_cmd_vtysh, + "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_prefix_longer_cmd_vtysh, + "show ipv6 bgp X:X::X:X/M longer-prefixes", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Display route and more specific routes\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_static_metric_val_cmd_vtysh, + "no redistribute static metric <0-16>", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Metric\n" + "Metric value\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_vlink_param2_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" ) + +DEFSH (VTYSH_BGPD, no_match_aspath_val_cmd_vtysh, + "no match as-path WORD", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "Match BGP AS path list\n" + "AS path access-list name\n") + +DEFSH (VTYSH_RIPD, no_key_chain_cmd_vtysh, + "no key chain WORD", + "Negate a command or set its defaults\n" + "Authentication key management\n" + "Key-chain management\n" + "Key-chain name\n") + +DEFSH (VTYSH_OSPF6D, show_version_ospf6_cmd_vtysh, + "show version ospf6", + "Show running system information\n" + "Displays ospf6d version\n" + ) + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_zebra_cmd_vtysh, + "no debug ospf6 zebra", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug connection between zebra\n" + ) + +DEFSH (VTYSH_BGPD, clear_bgp_peer_cmd_vtysh, + "clear bgp (A.B.C.D|X:X::X:X)", + "Reset functions\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n") + +DEFSH (VTYSH_BGPD, bgp_damp_unset_cmd_vtysh, + "no bgp dampening", + "Negate a command or set its defaults\n" + "BGP Specific commands\n" + "Enable route-flap dampening\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_route_match_detail_cmd_vtysh, + "show ipv6 ospf6 route X:X::X:X/M match detail", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Routing Table\n" + "Specify IPv6 prefix\n" + "Display routes which match the specified route\n" + "Detailed information\n" + ) + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_metric_routemap_cmd_vtysh, + "default-information originate metric <0-16777214> route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF default metric\n" + "OSPF metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_RIPNGD, ripng_default_information_originate_cmd_vtysh, + "default-information originate", + "Default route information\n" + "Distribute default route\n") + +DEFSH (VTYSH_BGPD, neighbor_attr_unchanged2_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path (next-hop|med)", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "As-path attribute\n" + "Nexthop attribute\n" + "Med attribute\n") + +DEFSH (VTYSH_BGPD, clear_bgp_peer_group_in_cmd_vtysh, + "clear bgp peer-group WORD in", + "Reset functions\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_OSPFD, ospf_timers_spf_cmd_vtysh, + "timers spf <0-4294967295> <0-4294967295>", + "Adjust routing timers\n" + "OSPF SPF timers\n" + "Delay between receiving a change to SPF calculation\n" + "Hold time between consecutive SPF calculations\n") + +DEFSH (VTYSH_OSPFD, no_ospf_dead_interval_cmd_vtysh, + "no ospf dead-interval", + "Negate a command or set its defaults\n" + "OSPF interface commands\n" + "Interval after which a neighbor is declared dead\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_all_cmd_vtysh, + "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP standard access list\n" + "IP extended access list\n" + "IP standard access list (expanded range)\n" + "IP extended access list (expanded range)\n" + "IP zebra access-list name\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ip_prefix_list_seq_ge_cmd_vtysh, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>", + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_BGPD, no_set_ecommunity_rt_val_cmd_vtysh, + "no set extcommunity rt .ASN:nn_or_IP-address:nn", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP extended community attribute\n" + "Route Target extened communityt\n" + "VPN extended community\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_route_match_cmd_vtysh, + "show ipv6 ospf6 route X:X::X:X/M match", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Routing Table\n" + "Specify IPv6 prefix\n" + "Display routes which match the specified route\n" + ) + +DEFSH (VTYSH_BGPD, set_atomic_aggregate_cmd_vtysh, + "set atomic-aggregate", + "Set values in destination routing protocol\n" + "BGP atomic aggregate attribute\n" ) + +DEFSH (VTYSH_BGPD, no_neighbor_transport_connection_mode_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "transport connection-mode", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Transport options\n" + "Specify passive or active connection\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_any_cmd_vtysh, + "access-list WORD (deny|permit) any", + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n") + +DEFSH (VTYSH_OSPFD, no_ospf_network_area_cmd_vtysh, + "no network A.B.C.D/M area (A.B.C.D|<0-4294967295>)", + "Negate a command or set its defaults\n" + "Enable routing on an IP network\n" + "OSPF network prefix\n" + "Set the OSPF area ID\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_soft_cmd_vtysh, + "clear bgp ipv6 <1-65535> soft", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, no_neighbor_advertise_interval_val_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X) " "advertisement-interval <0-600>", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Minimum interval between sending BGP routing updates\n" + "time in seconds\n") + +DEFSH (VTYSH_BGPD, debug_bgp_update_cmd_vtysh, + "debug bgp updates", + "Debugging functions (see also 'undebug')\n" + "BGP information\n" + "BGP updates\n") + +DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_metric_cmd_vtysh, + "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n") + +DEFSH (VTYSH_BGPD, show_bgp_prefix_cmd_vtysh, + "show bgp X:X::X:X/M", + "Show running system information\n" + "BGP information\n" + "IPv6 prefix /\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_prefix_cmd_vtysh, + "show ipv6 bgp X:X::X:X/M", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_out_cmd_vtysh, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, show_bgp_filter_list_cmd_vtysh, + "show bgp filter-list WORD", + "Show running system information\n" + "BGP information\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_linkstate_detail_cmd_vtysh, + "show ipv6 ospf6 linkstate detail", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Display linkstate routing table\n" + ) + +DEFSH (VTYSH_BGPD, clear_bgp_peer_soft_out_cmd_vtysh, + "clear bgp (A.B.C.D|X:X::X:X) soft out", + "Reset functions\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_ipv4_in_cmd_vtysh, + "clear ip bgp <1-65535> ipv4 (unicast|multicast) in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_RIPD, rip_distance_cmd_vtysh, + "distance <1-255>", + "Administrative distance\n" + "Distance value\n") + +DEFSH (VTYSH_BGPD, set_origin_cmd_vtysh, + "set origin (egp|igp|incomplete)", + "Set values in destination routing protocol\n" + "BGP origin code\n" + "remote EGP\n" + "local IGP\n" + "unknown heritage\n") + +DEFSH (VTYSH_OSPFD, ospf_transmit_delay_cmd_vtysh, + "ospf transmit-delay <1-65535>", + "OSPF interface commands\n" + "Link state transmit delay\n" + "Seconds\n") + +DEFSH (VTYSH_BGPD, no_neighbor_port_val_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X) " "port <0-65535>", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Neighbor's BGP port\n" + "TCP port number\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_access_list_cmd_vtysh, + "no ipv6 access-list WORD (deny|permit) X:X::X:X/M", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Add an access list entry\n" + "IPv6 zebra access-list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 3ffe:506::/32\n") + +DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_metric_rmap_cmd_vtysh, + "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_exact_cmd_vtysh, + "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, no_neighbor_ebgp_multihop_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Allow EBGP neighbors not on directly connected networks\n") + +DEFSH (VTYSH_BGPD, no_set_weight_val_cmd_vtysh, + "no set weight <0-65535>", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP weight for routing table\n" + "Weight value\n") + +DEFSH (VTYSH_ZEBRA, ipv6_nd_prefix_advertisement_no_val_cmd_vtysh, + "ipv6 nd prefix-advertisement IPV6PREFIX", + "IP information\n" + "Neighbor discovery\n" + "Prefix information\n" + "IPv6 prefix\n") + +DEFSH (VTYSH_BGPD, dump_bgp_all_cmd_vtysh, + "dump bgp all PATH", + "Dump packet\n" + "BGP packet dump\n" + "Dump all BGP packets\n" + "Output filename\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_soft_out_cmd_vtysh, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_route_type_cmd_vtysh, + "show ipv6 ospf6 route (intra-area|inter-area|external-1|external-2)", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Routing Table\n" + "Dispaly Intra-Area routes\n" + "Dispaly Inter-Area routes\n" + "Dispaly Type-1 External routes\n" + "Dispaly Type-2 External routes\n" + ) + +DEFSH (VTYSH_RIPNGD, ripng_passive_interface_cmd_vtysh, + "passive-interface IFNAME", + "Suppress routing updates on an interface\n" + "Interface name\n") + +DEFSH (VTYSH_BGPD, show_bgp_neighbors_peer_cmd_vtysh, + "show bgp neighbors (A.B.C.D|X:X::X:X)", + "Show running system information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n") + +DEFSH (VTYSH_OSPFD, no_debug_ospf_packet_all_cmd_vtysh, + "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, ipv6_prefix_list_seq_cmd_vtysh, + "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)", + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Any prefix match. Same as \"::0/0 le 128\"\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_cmd_vtysh, + "no redistribute kernel", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Kernel routes\n") + +DEFSH (VTYSH_BGPD, set_weight_cmd_vtysh, + "set weight <0-65535>", + "Set values in destination routing protocol\n" + "BGP weight for routing table\n" + "Weight value\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_type_routemap_cmd_vtysh, + "default-information originate metric-type (1|2) route-map WORD", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_bgp_metric_cmd_vtysh, + "no redistribute bgp metric", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Border Gateway Protocol (BGP)\n" + "Metric\n") + +DEFSH (VTYSH_RIPNGD, ripng_network_cmd_vtysh, + "network IF_OR_ADDR", + "RIPng enable on specified interface or network.\n" + "Interface or address") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_ip_prefix_list_seq_le_ge_cmd_vtysh, + "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", + "Negate a command or set its defaults\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_OSPFD, no_ospf_default_metric_val_cmd_vtysh, + "no default-metric <0-16777214>", + "Negate a command or set its defaults\n" + "Set metric of redistributed routes\n" + "Default metric\n") + +DEFSH (VTYSH_OSPFD, ospf_distance_ospf_external_cmd_vtysh, + "distance ospf external <1-255>", + "Define an administrative distance\n" + "OSPF Administrative distance\n" + "External routes\n" + "Distance for external routes\n") + +DEFSH (VTYSH_BGPD, no_bgp_scan_time_val_cmd_vtysh, + "no bgp scan-time <5-60>", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Configure background scanner interval\n" + "Scanner interval (seconds)\n") + +DEFSH (VTYSH_BGPD, old_ipv6_aggregate_address_summary_only_cmd_vtysh, + "ipv6 bgp aggregate-address X:X::X:X/M summary-only", + "IPv6 information\n" + "BGP information\n" + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD, rmap_continue_cmd_vtysh, + "continue", + "Continue on a different entry within the route-map\n") + +DEFSH (VTYSH_BGPD, show_bgp_route_cmd_vtysh, + "show bgp X:X::X:X", + "Show running system information\n" + "BGP information\n" + "Network in the BGP routing table to display\n") + +DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_adv_router_cmd_vtysh, + "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") adv-router A.B.C.D", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Database summary\n" + "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" "" + "Advertising Router link states\n" + "Advertising Router (as an IP address)\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_asbr_cmd_vtysh, + "debug ospf6 asbr", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 ASBR function\n" + ) + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh, + "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_in_cmd_vtysh, + "clear ip bgp <1-65535> in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_RIPD, ip_rip_send_version_cmd_vtysh, + "ip rip send version (1|2)", + "IP information\n" + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") + +DEFSH (VTYSH_OSPFD, ospf_area_export_list_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) export-list NAME", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Set the filter for networks announced to other areas\n" + "Name of the access-list\n") + +DEFSH (VTYSH_OSPFD, no_ospf_authentication_key_cmd_vtysh, + "no ospf authentication-key", + "Negate a command or set its defaults\n" + "OSPF interface commands\n" + "Authentication password (key)\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_host_host_cmd_vtysh, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "A single destination host\n" + "Destination address\n") + +DEFSH (VTYSH_BGPD, neighbor_dont_capability_negotiate_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "dont-capability-negotiate", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Do not perform capability negotiation\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_in_prefix_filter_cmd_vtysh, + "clear ip bgp A.B.C.D in prefix-filter", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Soft reconfig inbound update\n" + "Push out the existing ORF prefix-list\n") + +DEFSH (VTYSH_BGPD, no_neighbor_weight_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "weight", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Set default weight for routes from this neighbor\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, clear_ipv6_prefix_list_name_prefix_cmd_vtysh, + "clear ipv6 prefix-list WORD X:X::X:X/M", + "Reset functions\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_external_soft_in_cmd_vtysh, + "clear ip bgp external soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all external peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, no_set_vpnv4_nexthop_cmd_vtysh, + "no set vpnv4 next-hop", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "VPNv4 information\n" + "VPNv4 next-hop address\n") + +DEFSH (VTYSH_BGPD, bgp_multiple_instance_cmd_vtysh, + "bgp multiple-instance", + "BGP information\n" + "Enable bgp multiple instance\n") + +DEFSH (VTYSH_BGPD, no_set_ipv6_nexthop_global_cmd_vtysh, + "no set ipv6 next-hop global", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "IPv6 information\n" + "IPv6 next-hop address\n" + "IPv6 global address\n") + +DEFSH (VTYSH_BGPD, show_bgp_neighbors_cmd_vtysh, + "show bgp neighbors", + "Show running system information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_next_hop_val_cmd_vtysh, + "no match ip next-hop (<1-199>|<1300-2699>|WORD)", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IP information\n" + "Match next-hop address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") + +DEFSH (VTYSH_BGPD, show_bgp_community2_cmd_vtysh, + "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_prefix_list_cmd_vtysh, + "show bgp ipv6 prefix-list WORD", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes conforming to the prefix-list\n" + "IPv6 prefix-list name\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_cmd_vtysh, + "clear bgp ipv6 (A.B.C.D|X:X::X:X)", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_kernel_cmd_vtysh, + "redistribute kernel", + "Redistribute information from another routing protocol\n" + "Kernel routes\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ip_prefix_list_ge_le_cmd_vtysh, + "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_BGPD, no_bgp_default_local_preference_cmd_vtysh, + "no bgp default local-preference", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Configure BGP defaults\n" + "local preference (higher=more preferred)\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_ipv4_soft_in_cmd_vtysh, + "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, bgp_redistribute_ipv6_rmap_cmd_vtysh, + "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_route_cmd_vtysh, + "show ipv6 ospf6 route", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Routing Table\n" + ) + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_any_mask_cmd_vtysh, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Any source host\n" + "Destination address\n" + "Destination Wildcard bits\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPF6D, router_zebra_cmd_vtysh, + "router zebra", + "Enable a routing process\n" + "Make connection to zebra daemon\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_cmd_vtysh, + "clear ip bgp view WORD *", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "view name\n" + "Clear all peers\n") + +DEFSH (VTYSH_BGPD, no_neighbor_default_originate_rmap_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "default-originate route-map WORD", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Originate default route to this neighbor\n" + "Route-map to specify criteria to originate default\n" + "route-map name\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_cmd_vtysh, + "no ipv6 prefix-list WORD", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_static_routemap_cmd_vtysh, + "redistribute static route-map WORD", + "Redistribute information from another routing protocol\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_RIPD, accept_lifetime_day_month_month_day_cmd_vtysh, + "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_type_metric_cmd_vtysh, + "default-information originate always metric-type (1|2) metric <0-16777214>", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n" + "OSPF default metric\n" + "OSPF metric\n") + +DEFSH (VTYSH_BGPD, neighbor_route_server_client_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "route-server-client", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Configure a neighbor as Route Server client\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_community2_exact_cmd_vtysh, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, show_bgp_prefix_longer_cmd_vtysh, + "show bgp X:X::X:X/M longer-prefixes", + "Show running system information\n" + "BGP information\n" + "IPv6 prefix /\n" + "Display route and more specific routes\n") + +DEFSH (VTYSH_RIPD, no_distribute_list_prefix_all_cmd_vtysh, + "no distribute-list prefix WORD (in|out)", + "Negate a command or set its defaults\n" + "Filter networks in routing updates\n" + "Filter prefixes in routing updates\n" + "Name of an IP prefix-list\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_type_cmd_vtysh, + "default-information originate metric-type (1|2)", + "Control distribution of default information\n" + "Distribute a default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n") + +DEFSH (VTYSH_OSPFD, ospf_area_vlink_param4_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" ) + +DEFSH (VTYSH_BGPD, no_bgp_distance_source_access_list_cmd_vtysh, + "no distance <1-255> A.B.C.D/M WORD", + "Negate a command or set its defaults\n" + "Define an administrative distance\n" + "Administrative distance\n" + "IP source prefix\n" + "Access list name\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_range_substitute_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "Announce area range as another prefix\n" + "Network prefix to be announced instead of range\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, ip_prefix_list_seq_le_ge_cmd_vtysh, + "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_BGPD, neighbor_remote_as_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "remote-as <1-65535>", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Specify a BGP neighbor\n" + "AS number\n" ) + +DEFSH (VTYSH_OSPFD, no_debug_ospf_lsa_sub_cmd_vtysh, + "no debug ospf lsa (generate|flooding|install|refresh)", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Link State Advertisement\n" + "LSA Generation\n" + "LSA Flooding\n" + "LSA Install/Delete\n" + "LSA Refres\n") + +DEFSH (VTYSH_BGPD, no_match_origin_cmd_vtysh, + "no match origin", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "BGP origin code\n") + +DEFSH (VTYSH_BGPD, neighbor_remove_private_as_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "remove-private-AS", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Remove private AS number from outbound updates\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, show_ipv6_prefix_list_detail_name_cmd_vtysh, + "show ipv6 prefix-list detail WORD", + "Show running system information\n" + "IPv6 information\n" + "Build a prefix list\n" + "Detail of prefix lists\n" + "Name of a prefix list\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_flap_address_cmd_vtysh, + "show ip bgp flap-statistics A.B.C.D", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display flap statistics of routes\n" + "Network in the BGP routing table to display\n") + +DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_rmap_cmd_vtysh, + "no redistribute (connected|kernel|ospf|rip|static) route-map WORD", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, clear_bgp_peer_group_cmd_vtysh, + "clear bgp peer-group WORD", + "Reset functions\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n") + +DEFSH (VTYSH_BGPD, neighbor_interface_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X) " "interface WORD", + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Interface\n" + "Interface name\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_peer_soft_in_cmd_vtysh, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft in", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "BGP neighbor address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, clear_bgp_all_soft_cmd_vtysh, + "clear bgp * soft", + "Reset functions\n" + "BGP information\n" + "Clear all peers\n" + "Soft reconfig\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_community3_exact_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_received_routes_cmd_vtysh, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) received-routes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") + +DEFSH (VTYSH_BGPD, aggregate_address_mask_summary_as_set_cmd_vtysh, + "aggregate-address A.B.C.D A.B.C.D summary-only as-set", + "Configure BGP aggregate entries\n" + "Aggregate address\n" + "Aggregate mask\n" + "Filter more specific routes from updates\n" + "Generate AS set path information\n") + +DEFSH (VTYSH_OSPFD, ospf_passive_interface_addr_cmd_vtysh, + "passive-interface IFNAME A.B.C.D", + "Suppress routing updates on an interface\n" + "Interface's name\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_range_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n") + +DEFSH (VTYSH_BGPD, bgp_cluster_id32_cmd_vtysh, + "bgp cluster-id <1-4294967295>", + "BGP information\n" + "Configure Route-Reflector Cluster-id\n" + "Route-Reflector Cluster-id as 32 bit quantity\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_cmd_vtysh, + "clear bgp ipv6 <1-65535>", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear peers with the AS number\n") + +DEFSH (VTYSH_OSPFD|VTYSH_OSPFD, show_ip_ospf_neighbor_id_cmd_vtysh, + "show ip ospf neighbor A.B.C.D", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Neighbor list\n" + "Neighbor ID\n") + +DEFSH (VTYSH_OSPFD, ospf_neighbor_priority_cmd_vtysh, + "neighbor A.B.C.D priority <0-255>", + "Specify neighbor router\n" + "Neighbor IP address\n" + "Neighbor Priority\n" + "Seconds\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_hello_interval_addr_cmd_vtysh, + "no ip ospf hello-interval A.B.C.D", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Time between HELLO packets\n" + "Address of interface") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_kernel_metric_val_cmd_vtysh, + "no redistribute kernel metric <0-16>", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Metric\n" + "Metric value\n") + +DEFSH (VTYSH_OSPF6D, ospf6_redistribute_routemap_cmd_vtysh, + "redistribute (static|kernel|connected|ripng|bgp) route-map WORD", + "Redistribute\n" + "Static routes\n" + "Kernel route\n" + "Connected route\n" + "RIPng route\n" + "BGP route\n" + "Route map reference\n" + "Route map name\n" + ) + +DEFSH (VTYSH_BGPD, neighbor_local_as_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as <1-65535>", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Specify a local-as number\n" + "AS number used as local AS\n") + +DEFSH (VTYSH_BGPD, no_set_ecommunity_cost_igp_cmd_vtysh, + "no set extcommunity cost igp", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "BGP extended community attribute\n" + "Cost extended community\n" + "Compare following IGP cost comparison\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_simulate_spf_tree_root_cmd_vtysh, + "show ipv6 ospf6 simulate spf-tree A.B.C.D area A.B.C.D", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Shortest Path First caculation\n" + "Show SPF tree\n" + "Specify root's router-id to calculate another router's SPF tree\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd_vtysh, + "clear ip bgp view WORD * ipv4 (unicast|multicast) in prefix-filter", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_address_prefix_list_val_cmd_vtysh, + "no match ip address prefix-list WORD", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IP information\n" + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") + +DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged9_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med next-hop as-path", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "Nexthop attribute\n" + "As-path attribute\n") + +DEFSH (VTYSH_ZEBRA, ipv6_nd_ra_interval_cmd_vtysh, + "ipv6 nd ra-interval SECONDS", + "IP information\n" + "Neighbor discovery\n" + "Router Advertisement interval\n" + "Router Advertisement interval in seconds\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_redistribute_ospf6_metric_cmd_vtysh, + "no redistribute ospf6 metric", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "IPv6 Open Shortest Path First (OSPFv3)\n" + "Metric\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_community3_cmd_vtysh, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +DEFSH (VTYSH_BGPD, set_community_cmd_vtysh, + "set community .AA:NN", + "Set values in destination routing protocol\n" + "BGP community attribute\n" + "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_community_list_exact_cmd_vtysh, + "show ip bgp community-list (<1-500>|WORD) exact-match", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") + +DEFSH (VTYSH_BGPD, bgp_network_cmd_vtysh, + "network A.B.C.D/M", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_summary_cmd_vtysh, + "show ip bgp summary", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Summary of BGP neighbor status\n") + +DEFSH (VTYSH_BGPD, no_vpnv4_network_cmd_vtysh, + "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", + "Negate a command or set its defaults\n" + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "BGP tag\n" + "tag value\n") + +DEFSH (VTYSH_BGPD, bgp_network_backdoor_cmd_vtysh, + "network A.B.C.D/M backdoor", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify a BGP backdoor route\n") + +DEFSH (VTYSH_BGPD, no_neighbor_send_community_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Send Community attribute to this neighbor\n") + +DEFSH (VTYSH_ZEBRA, debug_zebra_packet_detail_cmd_vtysh, + "debug zebra packet (recv|send) detail", + "Debugging functions (see also 'undebug')\n" + "Zebra configuration\n" + "Debug option set for zebra packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n" + "Debug option set detaied information\n") + +DEFSH (VTYSH_OSPFD, ospf_auto_cost_reference_bandwidth_cmd_vtysh, + "auto-cost reference-bandwidth <1-4294967>", + "Calculate OSPF interface cost according to bandwidth\n" + "Use reference bandwidth method to assign OSPF cost\n" + "The reference bandwidth in terms of Mbits per second\n") + +DEFSH (VTYSH_OSPFD, show_ip_ospf_cmd_vtysh, + "show ip ospf", + "Show running system information\n" + "IP information\n" + "OSPF information\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_filter_list_cmd_vtysh, + "show bgp ipv6 filter-list WORD", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n") + +DEFSH (VTYSH_RIPD, ip_rip_receive_version_2_cmd_vtysh, + "ip rip receive version 2 1", + "IP information\n" + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "RIP version 2\n" + "RIP version 1\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_prefix_longer_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Display route and more specific routes\n") + +DEFSH (VTYSH_BGPD, clear_bgp_all_soft_in_cmd_vtysh, + "clear bgp * soft in", + "Reset functions\n" + "BGP information\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, no_bgp_default_ipv4_unicast_cmd_vtysh, + "no bgp default ipv4-unicast", + "Negate a command or set its defaults\n" + "BGP specific commands\n" + "Configure BGP defaults\n" + "Activate ipv4-unicast for a peer by default\n") + +DEFSH (VTYSH_ZEBRA, no_ipv6_nd_managed_config_flag_cmd_vtysh, + "no ipv6 nd managed-config-flag", + "Negate a command or set its defaults\n" + "IP information\n" + "Neighbor discovery\n" + "Managed address configuration flag\n") + +DEFSH (VTYSH_OSPFD, no_ospf_message_digest_key_cmd_vtysh, + "no ospf message-digest-key <1-255>", + "Negate a command or set its defaults\n" + "OSPF interface commands\n" + "Message digest authentication password (key)\n" + "Key ID\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_le_cmd_vtysh, + "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_prefix_list_prefix_first_match_cmd_vtysh, + "show ip prefix-list WORD A.B.C.D/M first-match", + "Show running system information\n" + "IP information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "First matched prefix\n") + +DEFSH (VTYSH_OSPF6D, debug_ospf6_abr_cmd_vtysh, + "debug ospf6 abr", + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug OSPFv3 ABR function\n" + ) + +DEFSH (VTYSH_OSPFD, debug_ospf_zebra_cmd_vtysh, + "debug ospf zebra", + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Zebra information\n") + +DEFSH (VTYSH_OSPFD, show_ip_ospf_database_type_id_self_cmd_vtysh, + "show ip ospf database (" "asbr-summary|external|network|router|summary" "" "" ") A.B.C.D (self-originate|)", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Database summary\n" + "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "" "" "" "" + "Link State ID (as an IP address)\n" + "Self-originated link states\n" + "\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_neighbor_flap_cmd_vtysh, + "show ip bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display flap statistics of the routes learned from neighbor\n") + +DEFSH (VTYSH_BGPD, no_ip_as_path_all_cmd_vtysh, + "no ip as-path access-list WORD", + "Negate a command or set its defaults\n" + "IP information\n" + "BGP autonomous system path filter\n" + "Specify an access list name\n" + "Regular expression access list name\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_in_cmd_vtysh, + "clear ip bgp * ipv4 (unicast|multicast) in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_out_cmd_vtysh, + "clear ip bgp A.B.C.D out", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_authentication_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) authentication", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Enable authentication\n") + +DEFSH (VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD, no_rmap_continue_seq_cmd_vtysh, + "no continue <1-65535>", + "Negate a command or set its defaults\n" + "Continue on a different entry within the route-map\n" + "Route-map entry sequence number\n") + +DEFSH (VTYSH_OSPFD, show_ip_ospf_database_cmd_vtysh, + "show ip ospf database", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Database summary\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_interface_ifname_cmd_vtysh, + "show ipv6 ospf6 interface IFNAME", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Interface infomation\n" + "Interface name(e.g. ep0)\n" + ) + +DEFSH (VTYSH_RIPNGD, no_ipv6_distribute_list_cmd_vtysh, + "no distribute-list WORD (in|out) WORD", + "Negate a command or set its defaults\n" + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_group_cmd_vtysh, + "clear ip bgp peer-group WORD", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all members of peer-group\n" + "BGP peer-group name\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_flap_regexp_cmd_vtysh, + "show ip bgp flap-statistics regexp .LINE", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display flap statistics of routes\n" + "Display routes matching the AS path regular expression\n" + "A regular-expression to match the BGP AS paths\n") + +DEFSH (VTYSH_BGPD, clear_bgp_as_soft_in_cmd_vtysh, + "clear bgp <1-65535> soft in", + "Reset functions\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd_vtysh, + "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display information received from a BGP neighbor\n" + "Display the prefixlist filter\n") + +DEFSH (VTYSH_RIPD, rip_version_cmd_vtysh, + "version <1-2>", + "Set routing protocol version\n" + "version\n") + +DEFSH (VTYSH_RIPD, ip_rip_send_version_1_cmd_vtysh, + "ip rip send version 1 2", + "IP information\n" + "Routing Information Protocol\n" + "Advertisement transmission\n" + "Version control\n" + "RIP version 1\n" + "RIP version 2\n") + +DEFSH (VTYSH_RIPD, no_debug_rip_zebra_cmd_vtysh, + "no debug rip zebra", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "RIP information\n" + "RIP and ZEBRA communication\n") + +DEFSH (VTYSH_BGPD, set_aspath_prepend_cmd_vtysh, + "set as-path prepend .<1-65535>", + "Set values in destination routing protocol\n" + "Prepend string for a BGP AS-path attribute\n" + "Prepend to the as-path\n" + "AS number\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbor_received_routes_cmd_vtysh, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the received routes from neighbor\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_interface_prefix_cmd_vtysh, + "show ipv6 ospf6 interface prefix", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Interface infomation\n" + "Display connected prefixes to advertise\n" + ) + +DEFSH (VTYSH_RIPNGD, debug_ripng_packet_detail_cmd_vtysh, + "debug ripng packet (recv|send) detail", + "Debugging functions (see also 'undebug')\n" + "RIPng configuration\n" + "Debug option set for ripng packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n" + "Debug option set detaied information\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD, no_match_interface_val_cmd_vtysh, + "no match interface WORD", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "Match first hop interface of route\n" + "Interface name\n") + +DEFSH (VTYSH_BGPD, match_ip_route_source_prefix_list_cmd_vtysh, + "match ip route-source prefix-list WORD", + "Match values from routing table\n" + "IP information\n" + "Match advertising source address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") + +DEFSH (VTYSH_BGPD, bgp_network_mask_natural_route_map_cmd_vtysh, + "network A.B.C.D route-map WORD", + "Specify a network to announce via BGP\n" + "Network number\n" + "Route-map to modify the attributes\n" + "Name of the route map\n") + +DEFSH (VTYSH_BGPD, neighbor_attr_unchanged9_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med next-hop as-path", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "Med attribute\n" + "Nexthop attribute\n" + "As-path attribute\n") + +DEFSH (VTYSH_BGPD, ip_extcommunity_list_name_standard2_cmd_vtysh, + "ip extcommunity-list standard WORD (deny|permit)", + "IP information\n" + "Add a extended community list entry\n" + "Specify standard extcommunity-list\n" + "Extended Community list name\n" + "Specify community to reject\n" + "Specify community to accept\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_as_soft_out_cmd_vtysh, + "clear bgp ipv6 <1-65535> soft out", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, no_ip_community_list_standard_cmd_vtysh, + "no ip community-list <1-99> (deny|permit) .AA:NN", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a community list entry\n" + "Community list number (standard)\n" + "Specify community to reject\n" + "Specify community to accept\n" + "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n" ) + +DEFSH (VTYSH_BGPD, debug_bgp_update_direct_cmd_vtysh, + "debug bgp updates (in|out)", + "Debugging functions (see also 'undebug')\n" + "BGP information\n" + "BGP updates\n" + "Inbound updates\n" + "Outbound updates\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_interface_ifname_prefix_cmd_vtysh, + "show ipv6 ospf6 interface IFNAME prefix", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Interface infomation\n" + "Interface name(e.g. ep0)\n" + "Display connected prefixes to advertise\n" + ) + +DEFSH (VTYSH_OSPFD, ospf_area_vlink_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D", + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" ) + +DEFSH (VTYSH_OSPFD, show_debugging_ospf_cmd_vtysh, + "show debugging ospf", + "Show running system information\n" + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" ) + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_cmd_vtysh, + "default-information originate", + "Control distribution of default information\n" + "Distribute a default route\n") + +DEFSH (VTYSH_OSPF6D, ospf6_redistribute_cmd_vtysh, + "redistribute (static|kernel|connected|ripng|bgp)", + "Redistribute\n" + "Static route\n" + "Kernel route\n" + "Connected route\n" + "RIPng route\n" + "BGP route\n" + ) + +DEFSH (VTYSH_BGPD, show_ipv6_mbgp_community2_exact_cmd_vtysh, + "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IPv6 information\n" + "MBGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_OSPFD, ip_ospf_transmit_delay_addr_cmd_vtysh, + "ip ospf transmit-delay <1-65535> A.B.C.D", + "IP Information\n" + "OSPF interface commands\n" + "Link state transmit delay\n" + "Seconds\n" + "Address of interface") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, show_ip_prefix_list_detail_name_cmd_vtysh, + "show ip prefix-list detail WORD", + "Show running system information\n" + "IP information\n" + "Build a prefix list\n" + "Detail of prefix lists\n" + "Name of a prefix list\n") + +DEFSH (VTYSH_BGPD, bgp_damp_set3_cmd_vtysh, + "bgp dampening", + "BGP Specific commands\n" + "Enable route-flap dampening\n") + +DEFSH (VTYSH_OSPFD, debug_ospf_packet_send_recv_detail_cmd_vtysh, + "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", + "Debugging functions\n" + "OSPF information\n" + "OSPF packets\n" + "OSPF Hello\n" + "OSPF Database Description\n" + "OSPF Link State Request\n" + "OSPF Link State Update\n" + "OSPF Link State Acknowledgment\n" + "OSPF all packets\n" + "Packet sent\n" + "Packet received\n" + "Detail Information\n") + +DEFSH (VTYSH_BGPD, bgp_default_ipv4_unicast_cmd_vtysh, + "bgp default ipv4-unicast", + "BGP specific commands\n" + "Configure BGP defaults\n" + "Activate ipv4-unicast for a peer by default\n") + +DEFSH (VTYSH_BGPD, no_neighbor_prefix_list_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "prefix-list WORD (in|out)", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Filter updates to/from this neighbor\n" + "Name of a prefix list\n" + "Filter incoming updates\n" + "Filter outgoing updates\n") + +DEFSH (VTYSH_BGPD, no_bgp_redistribute_ipv4_rmap_metric_cmd_vtysh, + "no redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", + "Negate a command or set its defaults\n" + "Redistribute information from another routing protocol\n" + "Connected\n" + "Kernel routes\n" + "Open Shurtest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n" + "Route map reference\n" + "Pointer to route-map entries\n" + "Metric for redistributed routes\n" + "Default metric\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_instance_all_ipv4_soft_cmd_vtysh, + "clear ip bgp view WORD * ipv4 (unicast|multicast) soft", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Address Family Modifier\n" + "Soft reconfig\n") + +DEFSH (VTYSH_OSPF6D, ospf6_router_id_cmd_vtysh, + "router-id A.B.C.D", + "Configure OSPF Router-ID\n" + "specify by IPv4 address notation(e.g. 0.0.0.0)\n" ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_cmd_vtysh, + "clear ip bgp *", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_cmd_vtysh, + "clear ip bgp <1-65535>", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n") + +DEFSH (VTYSH_BGPD, no_ip_community_list_expanded_cmd_vtysh, + "no ip community-list <100-500> (deny|permit) .LINE", + "Negate a command or set its defaults\n" + "IP information\n" + "Add a community list entry\n" + "Community list number (expanded)\n" + "Specify community to reject\n" + "Specify community to accept\n" + "An ordered list as a regular-expression\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_tags_cmd_vtysh, + "show ip bgp vpnv4 all tags", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "Display BGP tags for prefixes\n") + +DEFSH (VTYSH_OSPFD, ospf_area_authentication_cmd_vtysh, + "area (A.B.C.D|<0-4294967295>) authentication", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Enable authentication\n") + +DEFSH (VTYSH_OSPFD, ospf_passive_interface_cmd_vtysh, + "passive-interface IFNAME", + "Suppress routing updates on an interface\n" + "Interface's name\n") + +DEFSH (VTYSH_BGPD, no_neighbor_attr_unchanged3_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop (as-path|med)", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "As-path attribute\n" + "Med attribute\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_prefix_cmd_vtysh, + "show ip bgp vpnv4 all A.B.C.D/M", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n" + "IP prefix /, e.g., 35.0.0.0/8\n") + +DEFSH (VTYSH_BGPD, clear_bgp_as_in_prefix_filter_cmd_vtysh, + "clear bgp <1-65535> in prefix-filter", + "Reset functions\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_authentication_cmd_vtysh, + "no ip ospf authentication", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Enable authentication on this interface\n") + +DEFSH (VTYSH_BGPD, match_origin_cmd_vtysh, + "match origin (egp|igp|incomplete)", + "Match values from routing table\n" + "BGP origin code\n" + "remote EGP\n" + "local IGP\n" + "unknown heritage\n") + +DEFSH (VTYSH_OSPFD, no_debug_ospf_ism_cmd_vtysh, + "no debug ospf ism", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "OSPF information\n" + "OSPF Interface State Machine") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_peer_vpnv4_in_cmd_vtysh, + "clear ip bgp A.B.C.D vpnv4 unicast in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "BGP neighbor address to clear\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_ipv4_in_prefix_filter_cmd_vtysh, + "clear ip bgp * ipv4 (unicast|multicast) in prefix-filter", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n" + "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFSH (VTYSH_RIPD, no_distribute_list_all_cmd_vtysh, + "no distribute-list WORD (in|out)", + "Negate a command or set its defaults\n" + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n") + +DEFSH (VTYSH_OSPFD, no_ospf_network_cmd_vtysh, + "no ospf network", + "Negate a command or set its defaults\n" + "OSPF interface commands\n" + "Network type\n") + +DEFSH (VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD, no_ipv6_prefix_list_le_ge_cmd_vtysh, + "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", + "Negate a command or set its defaults\n" + "IPv6 information\n" + "Build a prefix list\n" + "Name of a prefix list\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "IPv6 prefix /, e.g., 3ffe::/16\n" + "Maximum prefix length to be matched\n" + "Maximum prefix length\n" + "Minimum prefix length to be matched\n" + "Minimum prefix length\n") + +DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_cmd_vtysh, + "show ip ospf neighbor", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Neighbor list\n") + +DEFSH (VTYSH_OSPFD, no_ospf_refresh_timer_val_cmd_vtysh, + "no refresh timer <10-1800>", + "Adjust refresh parameters\n" + "Unset refresh timer\n" + "Timer value in seconds\n") + +DEFSH (VTYSH_BGPD, no_neighbor_remote_as_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X) " "remote-as <1-65535>", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Specify a BGP neighbor\n" + "AS number\n" ) + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_soft_in_cmd_vtysh, + "clear ip bgp <1-65535> soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, neighbor_capability_orf_prefix_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "capability orf prefix-list (both|send|receive)", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Advertise capability to the peer\n" + "Advertise ORF capability to the peer\n" + "Advertise prefixlist ORF capability to this neighbor\n" + "Capability to SEND and RECEIVE the ORF to/from this neighbor\n" + "Capability to RECEIVE the ORF from this neighbor\n" + "Capability to SEND the ORF to this neighbor\n") + +DEFSH (VTYSH_BGPD, clear_bgp_as_out_cmd_vtysh, + "clear bgp <1-65535> out", + "Reset functions\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_OSPFD, show_ip_ospf_neighbor_detail_cmd_vtysh, + "show ip ospf neighbor detail", + "Show running system information\n" + "IP information\n" + "OSPF information\n" + "Neighbor list\n" + "detail of all neighbors\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, match_ip_next_hop_prefix_list_cmd_vtysh, + "match ip next-hop prefix-list WORD", + "Match values from routing table\n" + "IP information\n" + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") + +DEFSH (VTYSH_OSPFD, no_ospf_distance_cmd_vtysh, + "no distance <1-255>", + "Negate a command or set its defaults\n" + "Define an administrative distance\n" + "OSPF Administrative distance\n") + +DEFSH (VTYSH_BGPD, no_neighbor_interface_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X) " "interface WORD", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Interface\n" + "Interface name\n") + +DEFSH (VTYSH_OSPFD, ospf_default_information_originate_always_type_cmd_vtysh, + "default-information originate always metric-type (1|2)", + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPF metric type for default routes\n" + "Set OSPF External Type 1 metrics\n" + "Set OSPF External Type 2 metrics\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_default_metric_val_cmd_vtysh, + "no default-metric <1-16>", + "Negate a command or set its defaults\n" + "Set a metric of redistribute routes\n" + "Default metric\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_route_map_cmd_vtysh, + "show ip bgp route-map WORD", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the route-map\n" + "A route-map to match on\n") + +DEFSH (VTYSH_BGPD, set_originator_id_cmd_vtysh, + "set originator-id A.B.C.D", + "Set values in destination routing protocol\n" + "BGP originator ID attribute\n" + "IP address of originator\n") + +DEFSH (VTYSH_RIPD, debug_rip_packet_direct_cmd_vtysh, + "debug rip packet (recv|send)", + "Debugging functions (see also 'undebug')\n" + "RIP information\n" + "RIP packet\n" + "RIP receive packet\n" + "RIP send packet\n") + +DEFSH (VTYSH_BGPD, no_aggregate_address_summary_only_cmd_vtysh, + "no aggregate-address A.B.C.D/M summary-only", + "Negate a command or set its defaults\n" + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n") + +DEFSH (VTYSH_OSPFD, ospf_refresh_timer_cmd_vtysh, + "refresh timer <10-1800>", + "Adjust refresh parameters\n" + "Set refresh timer\n" + "Timer value in seconds\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_view_route_cmd_vtysh, + "show ip bgp view WORD A.B.C.D", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "BGP view\n" + "BGP view name\n" + "Network in the BGP routing table to display\n") + +DEFSH (VTYSH_OSPFD, no_ospf_area_vlink_param3_cmd_vtysh, + "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " + "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", + "Negate a command or set its defaults\n" + "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" + "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" ) + +DEFSH (VTYSH_RIPD, no_ip_rip_receive_version_num_cmd_vtysh, + "no ip rip receive version (1|2)", + "Negate a command or set its defaults\n" + "IP information\n" + "Routing Information Protocol\n" + "Advertisement reception\n" + "Version control\n" + "Version 1\n" + "Version 2\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_all_vpnv4_soft_in_cmd_vtysh, + "clear ip bgp * vpnv4 unicast soft in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear all peers\n" + "Address family\n" + "Address Family Modifier\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_RIPD, accept_lifetime_duration_day_month_cmd_vtysh, + "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_match_ip_address_cmd_vtysh, + "no match ip address", + "Negate a command or set its defaults\n" + "Match values from routing table\n" + "IP information\n" + "Match address of route\n") + +DEFSH (VTYSH_ZEBRA, show_ipv6_route_protocol_cmd_vtysh, + "show ipv6 route (bgp|connected|kernel|ospf6|ripng|static)", + "Show running system information\n" + "IP information\n" + "IP routing table\n" + "Border Gateway Protocol (BGP)\n" + "Connected\n" + "Kernel\n" + "Open Shortest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n") + +DEFSH (VTYSH_OSPF6D, show_ipv6_ospf6_spf_tree_cmd_vtysh, + "show ipv6 ospf6 spf tree", + "Show running system information\n" + "IPv6 Information\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Shortest Path First caculation\n" + "Show SPF tree\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_community4_exact_cmd_vtysh, + "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_priority_addr_cmd_vtysh, + "no ip ospf priority A.B.C.D", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Router priority\n" + "Address of interface") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_neighbors_peer_cmd_vtysh, + "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X)", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n") + +DEFSH (VTYSH_BGPD, clear_bgp_ipv6_all_out_cmd_vtysh, + "clear bgp ipv6 * out", + "Reset functions\n" + "BGP information\n" + "Address family\n" + "Clear all peers\n" + "Soft reconfig outbound update\n") + +DEFSH (VTYSH_BGPD, aggregate_address_cmd_vtysh, + "aggregate-address A.B.C.D/M", + "Configure BGP aggregate entries\n" + "Aggregate prefix\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_exact_cmd_vtysh, + "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Exact match of the communities") + +DEFSH (VTYSH_BGPD, no_set_ipv6_nexthop_local_cmd_vtysh, + "no set ipv6 next-hop local", + "Negate a command or set its defaults\n" + "Set values in destination routing protocol\n" + "IPv6 information\n" + "IPv6 next-hop address\n" + "IPv6 local address\n") + +DEFSH (VTYSH_BGPD, clear_bgp_instance_all_soft_in_cmd_vtysh, + "clear bgp view WORD * soft in", + "Reset functions\n" + "BGP information\n" + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_prefix_list_cmd_vtysh, + "show ip bgp prefix-list WORD", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display routes conforming to the prefix-list\n" + "IP prefix-list name\n") + +DEFSH (VTYSH_BGPD, neighbor_set_peer_group_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X) " "peer-group WORD", + "Specify neighbor router\n" + "Neighbor address\nIPv6 address\n" + "Member of the peer-group\n" + "peer-group name\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_standard_any_cmd_vtysh, + "no access-list (<1-99>|<1300-1999>) (deny|permit) any", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any source host\n") + +DEFSH (VTYSH_BGPD, no_auto_summary_cmd_vtysh, + "no auto-summary", + "Negate a command or set its defaults\n" + "Enable automatic network number summarization\n") + +DEFSH (VTYSH_OSPFD, no_ip_ospf_network_cmd_vtysh, + "no ip ospf network", + "Negate a command or set its defaults\n" + "IP Information\n" + "OSPF interface commands\n" + "Network type\n") + +DEFSH (VTYSH_BGPD, neighbor_attr_unchanged3_cmd_vtysh, + "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop (as-path|med)", + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "BGP attribute is propagated unchanged to this neighbor\n" + "Nexthop attribute\n" + "As-path attribute\n" + "Med attribute\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_extended_mask_any_cmd_vtysh, + "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any", + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "Source address\n" + "Source wildcard bits\n" + "Any destination host\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_standard_nomask_cmd_vtysh, + "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP standard access list\n" + "IP standard access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Address to match\n") + +DEFSH (VTYSH_BGPD, no_ipv6_aggregate_address_summary_only_cmd_vtysh, + "no aggregate-address X:X::X:X/M summary-only", + "Negate a command or set its defaults\n" + "Configure BGP aggregate entries\n" + "Aggregate prefix\n" + "Filter more specific routes from updates\n") + +DEFSH (VTYSH_BGPD, show_bgp_ipv6_community_list_exact_cmd_vtysh, + "show bgp ipv6 community-list (<1-500>|WORD) exact-match", + "Show running system information\n" + "BGP information\n" + "Address family\n" + "Display routes matching the community-list\n" + "community-list number\n" + "community-list name\n" + "Exact match of the communities\n") + +DEFSH (VTYSH_BGPD, clear_ip_bgp_as_vpnv4_in_cmd_vtysh, + "clear ip bgp <1-65535> vpnv4 unicast in", + "Reset functions\n" + "IP information\n" + "BGP information\n" + "Clear peers with the AS number\n" + "Address family\n" + "Address Family modifier\n" + "Soft reconfig inbound update\n") + +DEFSH (VTYSH_OSPFD, ip_ospf_retransmit_interval_cmd_vtysh, + "ip ospf retransmit-interval <3-65535>", + "IP Information\n" + "OSPF interface commands\n" + "Time between retransmitting lost link state advertisements\n" + "Seconds\n") + +DEFSH (VTYSH_ZEBRA, no_ip_route_cmd_vtysh, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)", + "Negate a command or set its defaults\n" + "IP information\n" + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n") + +DEFSH (VTYSH_BGPD, show_ip_bgp_vpnv4_all_cmd_vtysh, + "show ip bgp vpnv4 all", + "Show running system information\n" + "IP information\n" + "BGP information\n" + "Display VPNv4 NLRI specific information\n" + "Display information about all VPNv4 NLRIs\n") + +DEFSH (VTYSH_RIPD, no_key_string_cmd_vtysh, + "no key-string [LINE]", + "Negate a command or set its defaults\n" + "Unset key string\n" + "The key\n") + +DEFSH (VTYSH_BGPD, no_neighbor_soft_reconfiguration_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "soft-reconfiguration inbound", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Per neighbor soft reconfiguration\n" + "Allow inbound soft reconfiguration for this neighbor\n") + +DEFSH (VTYSH_BGPD, match_ip_route_source_cmd_vtysh, + "match ip route-source (<1-199>|<1300-2699>|WORD)", + "Match values from routing table\n" + "IP information\n" + "Match advertising source address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP standard access-list name\n") + +DEFSH (VTYSH_OSPF6D, no_debug_ospf6_lsa_hex_cmd_vtysh, + "no debug ospf6 lsa XXXX/0xXXXX", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "Open Shortest Path First (OSPF) for IPv6\n" + "Debug Link State Advertisements (LSAs)\n" + "Specify LS type as Hexadecimal\n" + ) + +DEFSH (VTYSH_BGPD, no_debug_bgp_events_cmd_vtysh, + "no debug bgp events", + "Negate a command or set its defaults\n" + "Debugging functions (see also 'undebug')\n" + "BGP information\n" + "BGP events\n") + +DEFSH (VTYSH_BGPD, no_neighbor_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " , + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" ) + +DEFSH (VTYSH_BGPD, match_community_cmd_vtysh, + "match community (<1-99>|<100-500>|WORD)", + "Match values from routing table\n" + "Match BGP community list\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n") + +DEFSH (VTYSH_BGPD, show_ip_extcommunity_list_cmd_vtysh, + "show ip extcommunity-list", + "Show running system information\n" + "IP information\n" + "List extended-community list\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, no_access_list_extended_host_mask_cmd_vtysh, + "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D", + "Negate a command or set its defaults\n" + "Add an access list entry\n" + "IP extended access list\n" + "IP extended access list (expanded range)\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Any Internet Protocol\n" + "A single source host\n" + "Source address\n" + "Destination address\n" + "Destination Wildcard bits\n") + +DEFSH (VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD, access_list_cmd_vtysh, + "access-list WORD (deny|permit) A.B.C.D/M", + "Add an access list entry\n" + "IP zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "Prefix to match. e.g. 10.0.0.0/8\n") + +DEFSH (VTYSH_OSPF6D, no_area_range_cmd_vtysh, + "no area A.B.C.D range X:X::X:X/M", + "OSPF area parameters\n" + "Area ID (as an IPv4 notation)\n" + "Configured address range\n" + "Specify IPv6 prefix\n" + ) + +DEFSH (VTYSH_BGPD, old_ipv6_bgp_network_cmd_vtysh, + "ipv6 bgp network X:X::X:X/M", + "IPv6 information\n" + "BGP information\n" + "Specify a network to announce via BGP\n" + "IPv6 prefix /, e.g., 3ffe::/16\n") + +DEFSH (VTYSH_BGPD, no_neighbor_filter_list_cmd_vtysh, + "no neighbor (A.B.C.D|X:X::X:X|WORD) " "filter-list WORD (in|out)", + "Negate a command or set its defaults\n" + "Specify neighbor router\n" + "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" + "Establish BGP filters\n" + "AS path access-list name\n" + "Filter incoming routes\n" + "Filter outgoing routes\n") + +DEFSH (VTYSH_BGPD, show_ipv6_bgp_community_list_exact_cmd_vtysh, + "show ipv6 bgp community-list WORD exact-match", + "Show running system information\n" + "IPv6 information\n" + "BGP information\n" + "Display routes matching the community-list\n" + "community-list name\n" + "Exact match of the communities\n") + +DEFSH (VTYSH_RIPNGD, ripng_redistribute_connected_routemap_cmd_vtysh, + "redistribute connected route-map WORD", + "Redistribute information from another routing protocol\n" + "Connected\n" + "Route map reference\n" + "Pointer to route-map entries\n") + +DEFSH (VTYSH_BGPD, undebug_bgp_events_cmd_vtysh, + "undebug bgp events", + "Disable debugging functions (see also 'debug')\n" + "BGP information\n" + "BGP events\n") + +DEFSH (VTYSH_RIPNGD, no_ripng_default_information_originate_cmd_vtysh, + "no default-information originate", + "Negate a command or set its defaults\n" + "Default route information\n" + "Distribute default route\n") + +void +vtysh_init_cmd () +{ + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_tags_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged8_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_detail_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_interface_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_neighbors_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_instance_summary_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_in_prefix_filter_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_zebra_sendrecv_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf_nsm_sub_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_addr_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_advertise_interval_val_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_static_metric_routemap_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_network_area_cmd_vtysh); + install_element (BGP_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_prefix_list_name_seq_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_ospf6_instance_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_always_type_routemap_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf_packet_all_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_map_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_external_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf_ism_sub_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_standard_nomask_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_distribute_list_cmd_vtysh); + install_element (RMAP_NODE, &match_aspath_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_in_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_out_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf_nsm_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_weight_val_cmd_vtysh); + install_element (RMAP_NODE, &no_set_metric_type_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_connected_metric_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); + install_element (BGP_NODE, &neighbor_advertise_interval_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf_lsa_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_extended_any_host_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_in_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_external_soft_in_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_bgp_redistribute_ipv4_rmap_metric_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_string_cmd_vtysh); + install_element (BGP_NODE, &neighbor_capability_dynamic_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_le_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged9_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_detail_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_default_originate_cmd_vtysh); + install_element (RMAP_NODE, &set_vpnv4_nexthop_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_route_match_detail_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd_vtysh); + install_element (RMAP_NODE, &no_set_ecommunity_rt_val_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_in_cmd_vtysh); + install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); + install_element (RIP_NODE, &distribute_list_prefix_all_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_cmd_vtysh); + install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd_vtysh); + install_element (OSPF6_NODE, &ospf6_interface_area_cmd_vtysh); + install_element (OSPF_NODE, &ospf_redistribute_source_metric_type_routemap_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_out_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd_vtysh); + install_element (ENABLE_NODE, &show_zebra_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_all_cmd_vtysh); + install_element (RMAP_NODE, &no_match_origin_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_route_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_cmd_vtysh); + install_element (RIPNG_NODE, &ipv6_distribute_list_prefix_cmd_vtysh); + install_element (RMAP_NODE, &match_ip_address_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_paths_cmd_vtysh); + install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ecommunity_cmd_vtysh); + install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_longer_cmd_vtysh); + install_element (BGP_IPV4_NODE, &aggregate_address_as_set_summary_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_static_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_route_mask_distance_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_rip_send_version_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_default_information_originate_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_send_community_type_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_filter_list_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_cmd_vtysh); + install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_as_path_cmd_vtysh); + install_element (ENABLE_NODE, &debug_bgp_normal_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_abr_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_strict_capability_cmd_vtysh); + install_element (BGP_NODE, &neighbor_remote_as_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_allowas_in_arg_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd_vtysh); + install_element (OSPF6_NODE, &no_router_ospf6_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_out_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_prefix_list_name_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_match_cmd_vtysh); + install_element (RMAP_NODE, &match_metric_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_route_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_in_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_route_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_weight_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_route_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd_vtysh); + install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_community3_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_attr_info_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_in_cmd_vtysh); + install_element (KEYCHAIN_NODE, &no_key_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_view_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_extended_host_mask_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_community2_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_all_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged9_cmd_vtysh); + install_element (RIP_NODE, &distribute_list_all_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ripng_zebra_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_prefix_list_name_seq_cmd_vtysh); + install_element (RMAP_NODE, &no_rmap_continue_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_group_in_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ospf_cost_cmd_vtysh); + install_element (BGP_NODE, &neighbor_weight_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_longer_cmd_vtysh); + install_element (RMAP_NODE, &no_set_atomic_aggregate_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_out_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); + install_element (BGP_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh); + install_element (BGP_NODE, &neighbor_interface_cmd_vtysh); + install_element (CONFIG_NODE, &router_zebra_cmd_vtysh); + install_element (RMAP_NODE, &match_ipv6_next_hop_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd_vtysh); + install_element (CONFIG_NODE, &no_router_zebra_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_summary_cmd_vtysh); + install_element (OSPF_NODE, &ospf_neighbor_poll_interval_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_detail_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_all_soft_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_prefix_list_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_port_val_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_prefix_filter_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd_vtysh); + install_element (ENABLE_NODE, &debug_zebra_packet_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_prefix_list_detail_name_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_instance_all_cmd_vtysh); + install_element (RMAP_NODE, &no_set_vpnv4_nexthop_val_cmd_vtysh); + install_element (BGP_NODE, &bgp_damp_set3_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_override_capability_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged3_cmd_vtysh); + install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd_vtysh); + install_element (RMAP_NODE, &match_community_exact_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_database_type_id_adv_router_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_extended_cmd_vtysh); + install_element (VIEW_NODE, &show_version_bgpd_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_community_all_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_neighbor_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_cmd_vtysh); + install_element (INTERFACE_NODE, &ospf_retransmit_interval_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_id_cmd_vtysh); + install_element (BGP_NODE, &bgp_default_ipv4_unicast_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_asbr_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_neighbor_detail_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_default_originate_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_community_list_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ripng_packet_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_prefix_list_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_always_compare_med_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_filter_list_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_list_cmd_vtysh); + install_element (BGP_NODE, &bgp_graceful_restart_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_out_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_cmd_vtysh); + install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_redistribute_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_external_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_no_val_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_out_cmd_vtysh); + install_element (RMAP_NODE, &match_community_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_out_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_community_list_standard_all_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_community2_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_allowas_in_arg_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_in_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); + install_element (ENABLE_NODE, &undebug_bgp_events_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_type_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_access_list_all_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_distance_ospf_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_network_mask_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_router_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_routemap_cmd_vtysh); + install_element (CONFIG_NODE, &bgp_config_type_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_cmd_vtysh); + install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_remark_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_cidr_only_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_confederation_peers_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_cidr_only_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_name_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_intra_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_exact_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_all_in_prefix_filter_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_prefix_filter_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_distribute_list_cmd_vtysh); + install_element (BGP_NODE, &bgp_bestpath_med3_cmd_vtysh); + install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_in_prefix_filter_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_range_advertise_cmd_vtysh); + install_element (RMAP_NODE, &no_match_community_val_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_authentication_cmd_vtysh); + install_element (OSPF_NODE, &ospf_redistribute_source_type_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_timers_cmd_vtysh); + install_element (RIP_NODE, &distribute_list_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_address_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf_event_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_cmd_vtysh); + install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd_vtysh); + install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_community_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_community2_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_standard_nomask_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_summary_cmd_vtysh); + install_element (OSPF_NODE, &ospf_neighbor_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); + install_element (BGP_NODE, &bgp_distance_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_network_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_network_mask_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_passive_interface_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_extcommunity_list_arg_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf_lsa_sub_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_activate_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_rip_receive_version_num_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_all_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_route_ifname_cmd_vtysh); + install_element (KEYCHAIN_NODE, &no_key_chain_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_weight_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_filter_list_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_view_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_community4_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_community_all_cmd_vtysh); + install_element (BGP_NODE, &bgp_client_to_client_reflection_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd_vtysh); + install_element (RMAP_NODE, &rmap_continue_cmd_vtysh); + install_element (OSPF_NODE, &ospf_redistribute_source_type_routemap_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ipv6_address_cmd_vtysh); + install_element (BGP_NODE, &neighbor_port_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_detail_cmd_vtysh); + install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_nexthop_self_cmd_vtysh); + install_element (BGP_NODE, &bgp_cluster_id_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_bgp_normal_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_routes_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_interface_cmd_vtysh); + install_element (RMAP_NODE, &no_match_community_exact_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_prefix_list_name_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_default_originate_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_neighbors_peer_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_out_cmd_vtysh); + install_element (BGP_NODE, &bgp_confederation_peers_cmd_vtysh); + install_element (RMAP_NODE, &set_local_pref_cmd_vtysh); + install_element (BGP_NODE, &neighbor_peer_group_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_addr_cmd_vtysh); + install_element (ENABLE_NODE, &debug_bgp_update_direct_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_route_server_client_cmd_vtysh); + install_element (BGP_NODE, &neighbor_maximum_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_neighbors_peer_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_import_list_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_soft_out_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_detail_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_cmd_vtysh); + install_element (BGP_NODE, &aggregate_address_mask_cmd_vtysh); + install_element (BGP_NODE, &old_no_ipv6_aggregate_address_summary_only_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_forwarding_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_name_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_cmd_vtysh); + install_element (OSPF_NODE, &ospf_redistribute_source_metric_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_prefix_list_cmd_vtysh); + install_element (RMAP_NODE, &set_community_none_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_bgp_update_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_network_route_map_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_dont_capability_negotiate_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_default_local_preference_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_out_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_dead_interval_addr_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_all_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_passive_interface_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_extended_any_mask_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_ospf6_transmitdelay_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_in_cmd_vtysh); + install_element (CONFIG_NODE, &ip_extcommunity_list_name_expanded_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_ge_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_all_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_external_out_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_route_map_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_day_month_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ripng_zebra_cmd_vtysh); + install_element (BGP_NODE, &neighbor_dont_capability_negotiate_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_bgp_events_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ripng_packet_cmd_vtysh); + install_element (BGP_NODE, &bgp_network_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_in_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_vlink_param4_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_prefix_list_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_string2_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_out_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_bgp_keepalive_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged9_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_network_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_prefix_filter_cmd_vtysh); + install_element (BGP_NODE, &bgp_damp_set_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_in_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_prefix_list_prefix_longer_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_default_originate_cmd_vtysh); + install_element (CONFIG_NODE, &debug_bgp_events_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_route_match_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_message_cmd_vtysh); + install_element (RMAP_NODE, &set_origin_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_out_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_shutdown_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_prefix_list_ge_le_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_type_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_transport_connection_mode_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_in_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_spf_tree_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_rip_send_version_num_cmd_vtysh); + install_element (BGP_NODE, &neighbor_unsuppress_map_cmd_vtysh); + install_element (ENABLE_NODE, &debug_rip_zebra_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_zebra_sendrecv_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_fast_external_failover_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &no_key_chain_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_filter_list_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd_vtysh); + install_element (BGP_NODE, &aggregate_address_mask_as_set_cmd_vtysh); + install_element (CONFIG_NODE, &ip_prefix_list_description_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_type_metric_routemap_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_routemap_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_out_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_authentication_cmd_vtysh); + install_element (ZEBRA_NODE, &no_ripng_redistribute_ripng_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_exact_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_advertise_interval_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged1_cmd_vtysh); + install_element (ENABLE_NODE, &debug_rip_packet_direct_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_priority_addr_cmd_vtysh); + install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_confederation_identifier_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_route_protocol_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_route_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_view_route_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_extended_host_any_cmd_vtysh); + install_element (RIP_NODE, &rip_default_information_originate_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged9_cmd_vtysh); + install_element (BGP_NODE, &bgp_distance_source_access_list_cmd_vtysh); + install_element (BGP_NODE, &neighbor_send_community_type_cmd_vtysh); + install_element (OSPF6_NODE, &ospf6_redistribute_cmd_vtysh); + install_element (RMAP_NODE, &match_ipv6_address_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_community3_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_route_map_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_timers_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd_vtysh); + install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); + install_element (ENABLE_NODE, &show_debugging_bgp_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ipv6_next_hop_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_filter_list_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_route_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf_nsm_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_first_match_cmd_vtysh); + install_element (CONFIG_NODE, &ip_community_list_standard_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_out_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_community2_exact_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_exact_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_route_pref_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf_zebra_sub_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_border_routers_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_soft_in_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); + install_element (RMAP_NODE, &no_set_ip_nexthop_cmd_vtysh); + install_element (RIP_NODE, &no_rip_version_val_cmd_vtysh); + install_element (OSPF_NODE, &ospf_network_area_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_description_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ip_next_hop_cmd_vtysh); + install_element (BGP_NODE, &neighbor_description_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ipv6_nd_send_ra_cmd_vtysh); + install_element (BGP_NODE, &bgp_damp_set2_cmd_vtysh); + install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_interface_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_route_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_community_list_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_network_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); + install_element (BGP_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_weight_val_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_prefix_list_le_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_vlink_param3_cmd_vtysh); + install_element (CONFIG_NODE, &debug_rip_zebra_cmd_vtysh); + install_element (BGP_NODE, &bgp_enforce_first_as_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_export_list_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_router_id_val_cmd_vtysh); + install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_routes_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged2_cmd_vtysh); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ipv6_ospf6_ifmtu_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_bgp_filter_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_route_prefix_cmd_vtysh); + install_element (BGP_NODE, &neighbor_distribute_list_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_route_cmd_vtysh); + install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_zebra_cmd_vtysh); + install_element (ENABLE_NODE, &undebug_bgp_update_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_only_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ripng_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_router_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd_vtysh); + install_element (RMAP_NODE, &match_ip_route_source_prefix_list_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_route_addr_cmd_vtysh); + install_element (BGP_NODE, &bgp_network_import_check_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_month_day_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_external_soft_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_bgp_redistribute_ipv4_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_prefix_filter_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_all_cmd_vtysh); + install_element (OSPF_NODE, &ospf_redistribute_source_type_metric_cmd_vtysh); + install_element (OSPF_NODE, &ospf_redistribute_source_routemap_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged1_cmd_vtysh); + install_element (BGP_NODE, &neighbor_update_source_cmd_vtysh); + install_element (RIP_NODE, &rip_network_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_message_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd_vtysh); + install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_if_rmap_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_community_list_arg_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_router_id_cmd_vtysh); + install_element (RIP_NODE, &no_rip_default_metric_val_cmd_vtysh); + install_element (OSPF6_NODE, &area_range_advertise_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_route_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_as_path_access_list_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd_vtysh); + install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd_vtysh); + install_element (OSPF_NODE, &ospf_redistribute_source_metric_type_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_community2_cmd_vtysh); + install_element (BGP_IPV4_NODE, &aggregate_address_as_set_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd_vtysh); + install_element (BGP_NODE, &neighbor_activate_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ipv6_prefix_list_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_out_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_transport_connection_mode_val_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ospf_hello_interval_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd_vtysh); + install_element (RIP_NODE, &rip_timers_cmd_vtysh); + install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_cmd_vtysh); + install_element (CONFIG_NODE, &debug_bgp_update_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_out_cmd_vtysh); + install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_prefix_list_name_seq_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_standard_host_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_weight_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged4_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_asbr_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd_vtysh); + install_element (BGP_NODE, &neighbor_attr_unchanged5_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_cost_addr_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_community3_exact_cmd_vtysh); + install_element (INTERFACE_NODE, &multicast_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd_vtysh); + install_element (BGP_NODE, &bgp_deterministic_med_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_all_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ospf_message_digest_key_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_arg_cmd_vtysh); + install_element (OSPF_NODE, &ospf_redistribute_source_type_metric_routemap_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd_vtysh); + install_element (RMAP_NODE, &set_community_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd_vtysh); + install_element (BGP_NODE, &neighbor_allowas_in_arg_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf_nsm_sub_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_interface_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_community4_exact_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_database_type_adv_router_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_default_local_preference_val_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_message_sendrecv_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_community3_cmd_vtysh); + install_element (INTERFACE_NODE, &ospf_priority_cmd_vtysh); + install_element (CONFIG_NODE, &dump_bgp_routes_cmd_vtysh); + install_element (RMAP_NODE, &no_set_metric_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distribute_list_out_cmd_vtysh); + install_element (BGP_NODE, &neighbor_ebgp_multihop_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_cluster_id_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf_packet_all_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged2_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf_ism_sub_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_rip_packet_direct_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged7_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_auto_cost_reference_bandwidth_cmd_vtysh); + install_element (RIP_NODE, &no_rip_timers_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_neighbors_peer_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_detail_cmd_vtysh); + install_element (ENABLE_NODE, &debug_bgp_keepalive_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd_vtysh); + install_element (RIP_NODE, &rip_offset_list_ifname_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_unsuppress_map_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_bgp_metric_routemap_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_bgp_redistribute_ipv4_rmap_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_auto_summary_cmd_vtysh); + install_element (BGP_NODE, &neighbor_attr_unchanged10_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_routemap_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_route_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_access_list_name_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_filter_list_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_in_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_route_addr_cmd_vtysh); + install_element (BGP_NODE, &bgp_distance_source_cmd_vtysh); + install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_route_map_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_access_list_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_access_list_any_cmd_vtysh); + install_element (BGP_NODE, &no_aggregate_address_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_detail_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_community_exact_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_distance_source_cmd_vtysh); + install_element (CONFIG_NODE, &ip_extcommunity_list_expanded_cmd_vtysh); + install_element (BGP_NODE, &no_aggregate_address_as_set_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd_vtysh); + install_element (CONFIG_NODE, &no_zebra_interface_cmd_vtysh); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_external_in_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd_vtysh); + install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_md5_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd_vtysh); + install_element (RMAP_NODE, &no_set_origin_val_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_database_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_abr_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd_vtysh); + install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf_event_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_ospf6_hellointerval_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_out_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_community2_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_group_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_routemap_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_out_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged7_cmd_vtysh); + install_element (INTERFACE_NODE, &bandwidth_if_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_as_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged4_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_vlink_authtype_authkey_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_range_advertise_cost_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_neighbor_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_disable_connected_check_cmd_vtysh); + install_element (CONFIG_NODE, &debug_rip_packet_detail_cmd_vtysh); + install_element (RMAP_NODE, &no_set_aspath_prepend_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_community_list_expanded_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_le_cmd_vtysh); + install_element (BGP_NODE, &no_aggregate_address_summary_only_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_prefix_list_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_prefix_list_summary_name_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_stub_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_activate_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_authentication_message_digest_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_name_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); + install_element (ENABLE_NODE, &undebug_bgp_filter_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf_ism_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_source_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_prefix_filter_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_ebgp_multihop_ttl_cmd_vtysh); + install_element (INTERFACE_NODE, &ospf_cost_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_route_type_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_month_day_cmd_vtysh); + install_element (RMAP_NODE, &set_ip_nexthop_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf_event_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_cmd_vtysh); + install_element (BGP_NODE, &neighbor_prefix_list_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_metric_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd_vtysh); + install_element (ENABLE_NODE, &debug_bgp_fsm_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_routemap_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_cost_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_all_soft_out_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_damp_set_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_metric_val_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_community2_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_community3_exact_cmd_vtysh); + install_element (CONFIG_NODE, &dump_bgp_all_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ripng_packet_detail_cmd_vtysh); + install_element (INTERFACE_NODE, &ospf_transmit_delay_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_detail_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_weight_cmd_vtysh); + install_element (BGP_NODE, &aggregate_address_as_set_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_distance2_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_vlink_param2_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_zebra_sendrecv_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_filter_list_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_community_exact_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_in_cmd_vtysh); + install_element (OSPF_NODE, &ospf_auto_cost_reference_bandwidth_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_flooding_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_arg_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_source_access_list_cmd_vtysh); + install_element (CONFIG_NODE, &debug_bgp_filter_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_le_ge_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_nexthop_self_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_match_cmd_vtysh); + install_element (ENABLE_NODE, &show_debugging_ripng_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &aggregate_address_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_community4_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_prefix_list_sequence_number_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_zebra_cmd_vtysh); + install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd_vtysh); + install_element (BGP_NODE, &neighbor_route_map_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_network_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_prefix_list_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_scan_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_refresh_timer_val_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_route_map_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_route_server_client_cmd_vtysh); + install_element (RMAP_NODE, &no_set_local_pref_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd_vtysh); + install_element (RIP_NODE, &no_rip_distance_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_extended_any_host_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_month_day_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_type_routemap_cmd_vtysh); + install_element (ENABLE_NODE, &show_debugging_zebra_cmd_vtysh); + install_element (BGP_NODE, &bgp_network_backdoor_cmd_vtysh); + install_element (RMAP_NODE, &no_set_ecommunity_cost_igp_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_day_month_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_out_cmd_vtysh); + install_element (OSPF_NODE, &ospf_redistribute_source_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_range_cost_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_exact_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf_zebra_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_route_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_list_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf_ism_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); + install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_bgp_cmd_vtysh); + install_element (BGP_NODE, &neighbor_default_originate_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ospf_priority_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf_lsa_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_rip_packet_direct_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_extended_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_rip_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_standard_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_static_metric_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd_vtysh); + install_element (ZEBRA_NODE, &rip_redistribute_rip_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_vlink_authkey_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_cmd_vtysh); + install_element (CONFIG_NODE, &no_router_bgp_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_timers_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_as_in_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_route_map_cmd_vtysh); + install_element (INTERFACE_NODE, &ospf_dead_interval_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_as_path_access_list_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_shortcut_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_rip_authentication_key_chain_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_sequence_number_cmd_vtysh); + install_element (BGP_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); + install_element (CONFIG_NODE, &no_bgp_config_type_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_network_mask_route_map_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_weight_val_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd_vtysh); + install_element (BGP_NODE, &neighbor_attr_unchanged6_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_out_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_self_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_regexp_cmd_vtysh); + install_element (RMAP_NODE, &match_origin_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cidr_only_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_as_out_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_route_pref_cmd_vtysh); + install_element (RIP_NODE, &rip_default_metric_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_vlink_param3_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_regexp_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged1_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_regexp_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_vlink_md5_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_priority_addr_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_regexp_cmd_vtysh); + install_element (BGP_NODE, &old_ipv6_bgp_network_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_cmd_vtysh); + install_element (RIP_NODE, &no_distribute_list_prefix_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged3_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ip_route_source_prefix_list_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd_vtysh); + install_element (RMAP_NODE, &no_set_local_pref_val_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_neighbor_poll_interval_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_filter_list_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_message_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_bgp_keepalive_cmd_vtysh); + install_element (RIP_NODE, &rip_distance_cmd_vtysh); + install_element (RMAP_NODE, &no_set_weight_cmd_vtysh); + install_element (ENABLE_NODE, &debug_rip_events_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_detail_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_redistribute_ipv4_rmap_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf_lsa_cmd_vtysh); + install_element (BGP_NODE, &old_no_ipv6_aggregate_address_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_access_list_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_route_map_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_connected_metric_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_bestpath_aspath_ignore_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_vlink_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_as_in_prefix_filter_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_addr_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_network_cmd_vtysh); + install_element (OSPF_NODE, &no_router_ospf_id_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd_vtysh); + install_element (BGP_NODE, &no_synchronization_cmd_vtysh); + install_element (RMAP_NODE, &set_metric_addsub_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_address_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_community_list_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_extcommunity_list_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_all_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_bgp_network_route_map_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_rip_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_standard_host_cmd_vtysh); + install_element (RIPNG_NODE, &ipv6_distribute_list_prefix_all_cmd_vtysh); + install_element (CONFIG_NODE, &ip_prefix_list_sequence_number_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd_vtysh); + install_element (BGP_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh); + install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_range_advertise_cost_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_prefix_cmd_vtysh); + install_element (CONFIG_NODE, &ip_prefix_list_le_ge_cmd_vtysh); + install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_addr_cmd_vtysh); + install_element (RMAP_NODE, &set_weight_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_exact_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_access_list_remark_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged2_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ospf_dead_interval_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd_vtysh); + install_element (BGP_NODE, &aggregate_address_as_set_summary_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_detail_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_community4_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_route_detail_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd_vtysh); + install_element (RMAP_NODE, &no_set_originator_id_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_static_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_ospf6_metric_routemap_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged7_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_forwarding_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_routemap_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_all_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_connected_metric_val_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_rip_receive_version_1_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_scan_time_val_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ripng_packet_direct_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_remote_as_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_ge_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_exact_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd_vtysh); + install_element (OSPF_NODE, &ospf_rfc1583_flag_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged3_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_vlink_param2_cmd_vtysh); + install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd_vtysh); + install_element (CONFIG_NODE, &ip_extcommunity_list_standard2_cmd_vtysh); + install_element (BGP_NODE, &aggregate_address_summary_only_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_prefix_list_summary_name_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd_vtysh); + install_element (RMAP_NODE, &set_originator_id_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ripng_packet_direct_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_prefix_list_name_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_out_cmd_vtysh); + install_element (BGP_NODE, &bgp_cluster_id32_cmd_vtysh); + install_element (RIP_NODE, &no_rip_redistribute_type_routemap_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_client_to_client_reflection_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ip_address_val_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_external_cmd_vtysh); + install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_access_list_any_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_range_cost_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_vlink_param4_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_forwarding_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_flooding_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_community_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_community_cmd_vtysh); + install_element (RMAP_NODE, &set_ecommunity_rt_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_bgp_redistribute_ipv4_metric_rmap_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_rip_authentication_string_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_cmd_vtysh); + install_element (OSPF_NODE, &ospf_timers_spf_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_filter_list_cmd_vtysh); + install_element (CONFIG_NODE, &ip_prefix_list_seq_le_ge_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged4_cmd_vtysh); + install_element (RMAP_NODE, &no_set_community_val_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_out_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_zebra_events_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_log_neighbor_changes_cmd_vtysh); + install_element (BGP_NODE, &neighbor_strict_capability_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_route_type_detail_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_in_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_cmd_vtysh); + install_element (CONFIG_NODE, &debug_zebra_kernel_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_all_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_asbr_cmd_vtysh); + install_element (RMAP_NODE, &no_match_metric_cmd_vtysh); + install_element (CONFIG_NODE, &dump_bgp_updates_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged7_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_ospf6_routemap_cmd_vtysh); + install_element (BGP_NODE, &bgp_always_compare_med_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_address_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_kernel_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_message_sendrecv_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ripng_events_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_extended_host_host_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_rip_receive_version_2_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_cmd_vtysh); + install_element (BGP_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_advertisement_cmd_vtysh); + install_element (RMAP_NODE, &set_metric_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_always_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_tunnel_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd_vtysh); + install_element (RIPNG_NODE, &no_ipv6_distribute_list_all_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ripng_packet_direct_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_authentication_key_addr_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_distance_cmd_vtysh); + install_element (BGP_IPV4_NODE, &aggregate_address_summary_as_set_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_asbr_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_weight_val_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_community2_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_local_as_val_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ip_route_source_prefix_list_val_cmd_vtysh); + install_element (RMAP_NODE, &no_set_community_delete_val_cmd_vtysh); + install_element (RIP_NODE, &no_rip_distance_source_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_prefix_filter_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_filter_list_cmd_vtysh); + install_element (BGP_NODE, &neighbor_attr_unchanged8_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); + install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard2_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_cmd_vtysh); + install_element (BGP_NODE, &neighbor_set_peer_group_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_kernel_routemap_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_prefix_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_out_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_local_as_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_protocols_rip_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_out_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_prefix_list_description_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_standard_any_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_cost_addr_cmd_vtysh); + install_element (CONFIG_NODE, &debug_bgp_fsm_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_community4_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd_vtysh); + install_element (BGP_NODE, &neighbor_enforce_multihop_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_prefix_list_detail_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_rip_zebra_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); + install_element (RMAP_NODE, &no_set_ecommunity_soo_cmd_vtysh); + install_element (BGP_NODE, &neighbor_disable_connected_check_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_always_type_metric_cmd_vtysh); + install_element (CONFIG_NODE, &ip_prefix_list_seq_cmd_vtysh); + install_element (BGP_NODE, &old_ipv6_aggregate_address_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_sequence_number_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_extended_any_mask_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd_vtysh); + install_element (BGP_NODE, &neighbor_route_server_client_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_all_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_neighbor_id_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_day_month_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_in_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_rip_authentication_mode_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_cmd_vtysh); + install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_as_path_all_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_community2_exact_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_type_cmd_vtysh); + install_element (BGP_NODE, &neighbor_attr_unchanged1_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_out_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_regexp_cmd_vtysh); + install_element (OSPF_NODE, &ospf_redistribute_source_metric_routemap_cmd_vtysh); + install_element (OSPF_NODE, &ospf_neighbor_poll_interval_priority_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_in_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_bgp_redistribute_ipv4_metric_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_access_list_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_bestpath_cost_community_ignore_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_in_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_scan_time_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_community_all_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_route_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_le_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_priority_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_default_originate_rmap_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_self_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_vlink_authkey_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_community_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_distance_source_access_list_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_vlink_param1_cmd_vtysh); + install_element (ENABLE_NODE, &show_debugging_rip_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_route_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_static_routemap_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_extended_mask_host_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_activate_cmd_vtysh); + install_element (RIP_NODE, &no_rip_default_metric_cmd_vtysh); + install_element (INTERFACE_NODE, &no_bandwidth_if_cmd_vtysh); + install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_weight_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_cmd_vtysh); + install_element (RMAP_NODE, &no_match_interface_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_default_metric_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ip_route_source_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf_lsa_sub_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_in_prefix_filter_cmd_vtysh); + install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_exact_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_ospf6_retransmitinterval_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_border_routers_detail_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_in_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain2_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_allowas_in_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_out_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_extended_host_any_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_connected_metric_routemap_cmd_vtysh); + install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd_vtysh); + install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_cmd_vtysh); + install_element (BGP_NODE, &bgp_bestpath_compare_router_id_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_prefix_list_cmd_vtysh); + install_element (INTERFACE_NODE, &shutdown_if_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_connected_metric_routemap_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_redistribute_ipv4_metric_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_neighbors_cmd_vtysh); + install_element (BGP_NODE, &neighbor_attr_unchanged2_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_cmd_vtysh); + install_element (BGP_NODE, &neighbor_passive_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf_zebra_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_out_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_send_community_cmd_vtysh); + install_element (RIP_NODE, &rip_distance_source_cmd_vtysh); + install_element (OSPF_NODE, &router_ospf_id_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_bgp_all_cmd_vtysh); + install_element (RMAP_NODE, &no_set_community_delete_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_list_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_authentication_addr_cmd_vtysh); + install_element (BGP_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_adv_router_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_send_community_type_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_standard_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd_vtysh); + install_element (BGP_NODE, &bgp_bestpath_cost_community_ignore_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_rip_send_version_1_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_out_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_message_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_access_list_remark_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &no_key_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_prefix_list_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf_nsm_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_view_prefix_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_exact_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_route_map_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_redistribute_ipv4_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &aggregate_address_summary_as_set_cmd_vtysh); + install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_metric_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); + install_element (CONFIG_NODE, &no_key_chain_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_cmd_vtysh); + install_element (ENABLE_NODE, &undebug_bgp_all_cmd_vtysh); + install_element (RMAP_NODE, &no_set_community_cmd_vtysh); + install_element (RMAP_NODE, &no_set_aggregator_as_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_flooding_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_in_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_route_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_as_soft_in_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_refresh_timer_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_prefix_list_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_route_cmd_vtysh); + install_element (BGP_NODE, &bgp_network_mask_natural_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_cmd_vtysh); + install_element (RIP_NODE, &no_rip_route_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_forwarding_cmd_vtysh); + install_element (RIP_NODE, &rip_route_cmd_vtysh); + install_element (ENABLE_NODE, &debug_rip_packet_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_filter_list_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); + install_element (OSPF_NODE, &ospf_neighbor_priority_poll_interval_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_cmd_vtysh); + install_element (BGP_NODE, &neighbor_attr_unchanged4_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_prefix_list_detail_name_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_static_routemap_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd_vtysh); + install_element (BGP_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ripng_zebra_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_map_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_exact_cmd_vtysh); + install_element (BGP_NODE, &bgp_damp_unset_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_route_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_external_soft_out_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_bgp_network_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd_vtysh); + install_element (BGP_NODE, &no_auto_summary_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_spf_tree_cmd_vtysh); + install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_route_mask_cmd_vtysh); + install_element (RMAP_NODE, &match_ipv6_address_prefix_list_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged3_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_range_advertise_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_in_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_addr_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_out_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_out_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_rip_events_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_prefix_list_summary_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_authentication_args_addr_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_metric_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_prefix_list_summary_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_longer_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_nd_send_ra_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_rip_send_version_2_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_community_info_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_always_type_metric_routemap_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged5_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_port_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_regexp_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); + install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf_nsm_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_confederation_identifier_arg_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_community2_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_version_ospf6_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_all_in_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_capability_dynamic_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_cmd_vtysh); + install_element (CONFIG_NODE, &debug_rip_packet_direct_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_prefix_list_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_metric_routemap_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_route_map_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd_vtysh); + install_element (RIP_NODE, &no_rip_passive_interface_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_extended_mask_any_cmd_vtysh); + install_element (RIP_NODE, &no_distribute_list_prefix_all_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_tags_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_in_prefix_filter_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_distribute_list_out_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_interface_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_neighbor_cmd_vtysh); + install_element (ENABLE_NODE, &show_interface_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_database_type_self_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_route_server_client_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_weight_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd_vtysh); + install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd_vtysh); + install_element (RMAP_NODE, &no_set_weight_val_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_prefix_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_vlink_authtype_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_in_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_in_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_community_list_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd_vtysh); + install_element (RMAP_NODE, &no_rmap_continue_seq_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_addr_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_description_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_rip_receive_version_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_filter_list_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged10_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_activate_cmd_vtysh); + install_element (VIEW_NODE, &show_interface_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_inter_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_remark_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_cmd_vtysh); + install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_range_substitute_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_network_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh); + install_element (CONFIG_NODE, &debug_zebra_events_cmd_vtysh); + install_element (RMAP_NODE, &no_match_origin_val_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_default_cost_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged5_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_cmd_vtysh); + install_element (RMAP_NODE, &match_ecommunity_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &key_string_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_allowas_in_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_all_cmd_vtysh); + install_element (BGP_NODE, &old_ipv6_aggregate_address_summary_only_cmd_vtysh); + install_element (VIEW_NODE, &show_debugging_ripng_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_import_list_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_stub_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_bgp_routemap_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_network_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ripng_events_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_detail_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_cmd_vtysh); + install_element (BGP_NODE, &bgp_default_local_preference_cmd_vtysh); + install_element (RMAP_NODE, &match_ip_next_hop_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_as_path_access_list_all_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_as_path_access_list_all_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_soft_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_community_list_cmd_vtysh); + install_element (VIEW_NODE, &show_debugging_zebra_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_community4_exact_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_graceful_restart_cmd_vtysh); + install_element (BGP_NODE, &aggregate_address_mask_summary_only_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_md5_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_community3_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_access_list_name_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_cidr_only_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ripng_packet_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_routemap_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged10_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_community3_exact_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_prefix_list_prefix_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_default_ipv4_unicast_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh); + install_element (CONFIG_NODE, &bgp_multiple_instance_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_cmd_vtysh); + install_element (CONFIG_NODE, &no_router_rip_cmd_vtysh); + install_element (RMAP_NODE, &no_match_metric_val_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); + install_element (RMAP_NODE, &no_set_originator_id_val_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_bestpath_med_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_community_list_arg_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_inter_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd_vtysh); + install_element (BGP_IPV4_NODE, &aggregate_address_summary_only_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_ge_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_vlink_md5_cmd_vtysh); + install_element (CONFIG_NODE, &ip_prefix_list_le_cmd_vtysh); + install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd_vtysh); + install_element (OSPF_NODE, &ospf_passive_interface_addr_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_default_metric_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_external_in_prefix_filter_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &bgp_network_cmd_vtysh); + install_element (CONFIG_NODE, &ip_as_path_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_ge_le_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_prefix_list_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_cmd_vtysh); + install_element (BGP_NODE, &bgp_bestpath_med_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_view_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_community_all_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd_vtysh); + install_element (RMAP_NODE, &no_match_community_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd_vtysh); + install_element (RIP_NODE, &no_rip_offset_list_ifname_cmd_vtysh); + install_element (BGP_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh); + install_element (BGP_NODE, &neighbor_attr_unchanged_cmd_vtysh); + install_element (OSPF6_NODE, &no_area_range_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_extended_host_mask_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf_nsm_sub_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_community3_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_authkey_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd_vtysh); + install_element (ENABLE_NODE, &undebug_bgp_normal_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd_vtysh); + install_element (OSPF_NODE, &ospf_abr_type_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_filter_list_cmd_vtysh); + install_element (RIP_NODE, &rip_redistribute_type_metric_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ospf_network_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf_ism_sub_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_any_cmd_vtysh); + install_element (BGP_NODE, &bgp_network_route_map_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_route_server_client_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_bgp_update_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_rip_send_version_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_remove_private_as_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_weight_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &no_key_string_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); + install_element (RMAP_NODE, &no_set_metric_val_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_community2_exact_cmd_vtysh); + install_element (INTERFACE_NODE, &ospf_authentication_key_cmd_vtysh); + install_element (RMAP_NODE, &set_aggregator_as_cmd_vtysh); + install_element (BGP_NODE, &neighbor_attr_unchanged9_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_out_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_le_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_priority_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_out_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_day_month_cmd_vtysh); + install_element (RIP_NODE, &rip_version_cmd_vtysh); + install_element (CONFIG_NODE, &ip_route_cmd_vtysh); + install_element (ENABLE_NODE, &show_debugging_ospf_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_exact_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_send_community_type_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_route_addr_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_in_cmd_vtysh); + install_element (CONFIG_NODE, &ip_prefix_list_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_prefix_list_name_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_route_distance_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_access_list_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_interface_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ripng_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_send_community_type_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_month_day_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_activate_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_type_detail_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_peer_cmd_vtysh); + install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_default_metric_cmd_vtysh); + install_element (BGP_NODE, &neighbor_attr_unchanged3_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_detail_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_protocols_rip_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_community3_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_peer_group_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_month_day_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_as_soft_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged6_cmd_vtysh); + install_element (INTERFACE_NODE, &no_rip_split_horizon_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_vlink_authtype_md5_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_in_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_send_community_cmd_vtysh); + install_element (OSPF_NODE, &ospf_passive_interface_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_zebra_sendrecv_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd_vtysh); + install_element (CONFIG_NODE, &no_dump_bgp_all_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_list_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_in_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_name_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_cmd_vtysh); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_only_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_cost_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_database_type_id_self_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_route_protocol_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_export_list_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_access_list_exact_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_abr_type_cmd_vtysh); + install_element (RMAP_NODE, &no_match_aspath_val_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_send_community_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_abr_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_peer_group_remote_as_cmd_vtysh); + install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_shortcut_cmd_vtysh); + install_element (OSPF6_NODE, &ospf6_router_id_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_hello_interval_addr_cmd_vtysh); + install_element (RIP_NODE, &no_rip_redistribute_type_metric_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_route_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd_vtysh); + install_element (ENABLE_NODE, &debug_zebra_kernel_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf_nsm_sub_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_distance_source_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_extended_host_host_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_neighbors_peer_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_authentication_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_paths_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ripng_packet_detail_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_summary_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_detail_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf_ism_sub_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_out_cmd_vtysh); + install_element (CONFIG_NODE, &ip_community_list_name_standard2_cmd_vtysh); + install_element (BGP_NODE, &neighbor_timers_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_route_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_bestpath_med2_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_remove_private_as_cmd_vtysh); + install_element (BGP_NODE, &neighbor_version_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_cmd_vtysh); + install_element (ZEBRA_NODE, &redistribute_ospf6_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_database_type_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_neighbor_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged6_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_forwarding_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_deterministic_med_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_cmd_vtysh); + install_element (CONFIG_NODE, &ip_prefix_list_ge_le_cmd_vtysh); + install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd_vtysh); + install_element (BGP_NODE, &bgp_network_mask_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &debug_rip_packet_detail_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_cluster_id_arg_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf_zebra_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd_vtysh); + install_element (BGP_NODE, &bgp_graceful_restart_stalepath_time_cmd_vtysh); + install_element (BGP_NODE, &bgp_fast_external_failover_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged5_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd_vtysh); + install_element (BGP_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ospf_retransmit_interval_cmd_vtysh); + install_element (BGP_NODE, &no_aggregate_address_mask_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_exact_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_community_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_longer_cmd_vtysh); + install_element (RIP_NODE, &distribute_list_prefix_cmd_vtysh); + install_element (RIP_NODE, &no_distribute_list_all_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_distance_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_all_cmd_vtysh); + install_element (BGP_NODE, &neighbor_route_reflector_client_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_tunnel_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_out_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_community2_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_route_supernets_cmd_vtysh); + install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_cmd_vtysh); + install_element (BGP_NODE, &bgp_router_id_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_rmap_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_val_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_vlink_param1_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_connected_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_send_community_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd_vtysh); + install_element (CONFIG_NODE, &ip_route_distance_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd_vtysh); + install_element (BGP_NODE, &neighbor_default_originate_rmap_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_all_out_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_external_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); + install_element (OSPF_NODE, &ospf_refresh_timer_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_list_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_month_day_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf_zebra_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_exact_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_rip_zebra_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_rip_packet_cmd_vtysh); + install_element (VIEW_NODE, &show_version_ospf6_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_zebra_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_abr_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_route_supernets_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged10_cmd_vtysh); + install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_view_route_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_connected_routemap_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf_ism_cmd_vtysh); + install_element (ENABLE_NODE, &debug_bgp_events_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_activate_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ripng_zebra_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_community3_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_community4_cmd_vtysh); + install_element (BGP_IPV4_NODE, &aggregate_address_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_month_day_cmd_vtysh); + install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_le_cmd_vtysh); + install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_range_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged5_cmd_vtysh); + install_element (CONFIG_NODE, &no_route_map_all_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_passive_interface_addr_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_as_soft_out_cmd_vtysh); + install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_cmd_vtysh); + install_element (BGP_NODE, &neighbor_ebgp_multihop_ttl_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_neighbors_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_external_cmd_vtysh); + install_element (RIPNG_NODE, &no_ipv6_distribute_list_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_prefix_list_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_enforce_first_as_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_rip_events_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_routemap_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_community4_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_static_metric_val_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); + install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_ebgp_multihop_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_network_backdoor_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_prefix_list_name_prefix_cmd_vtysh); + install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_cmd_vtysh); + install_element (INTERFACE_NODE, &ospf_message_digest_key_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_network_mask_backdoor_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_filter_list_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_le_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_in_cmd_vtysh); + install_element (CONFIG_NODE, &debug_zebra_packet_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_message_sendrecv_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged10_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_always_type_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_metric_val_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_prefix_list_cmd_vtysh); + install_element (OSPF6_NODE, &area_range_cmd_vtysh); + install_element (CONFIG_NODE, &debug_rip_events_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_cmd_vtysh); + install_element (RMAP_NODE, &match_interface_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_standard_any_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_prefix_filter_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf_lsa_sub_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_extended_any_any_cmd_vtysh); + install_element (CONFIG_NODE, &debug_bgp_keepalive_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_peer_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ripng_packet_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged8_cmd_vtysh); + install_element (RIP_NODE, &rip_offset_list_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_network_import_check_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_in_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_default_cost_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_prefix_list_ge_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_paths_cmd_vtysh); + install_element (RIP_NODE, &no_rip_offset_list_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_access_list_remark_arg_cmd_vtysh); + install_element (RMAP_NODE, &set_ip_nexthop_bgp_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_community_list_exact_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf_lsa_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_default_metric_val_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_filter_list_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_range_not_advertise_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_type_metric_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_send_community_type_cmd_vtysh); + install_element (BGP_NODE, &neighbor_local_as_no_prepend_cmd_vtysh); + install_element (ENABLE_NODE, &show_zebra_client_cmd_vtysh); + install_element (BGP_NODE, &neighbor_shutdown_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_prefix_list_le_ge_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_detail_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_distribute_list_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_only_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_in_cmd_vtysh); + install_element (RMAP_NODE, &no_set_vpnv4_nexthop_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_out_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_group_out_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_range_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_metric_type_cmd_vtysh); + install_element (RIP_NODE, &rip_distance_source_access_list_cmd_vtysh); + install_element (CONFIG_NODE, &no_router_bgp_view_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_all_soft_in_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_inter_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); + install_element (BGP_NODE, &neighbor_nexthop_self_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_community_list_name_standard_cmd_vtysh); + install_element (RIP_NODE, &no_rip_redistribute_type_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_distance_source_access_list_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_neighbor_priority_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_prefix_filter_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_community4_exact_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_redistribute_ipv4_rmap_metric_cmd_vtysh); + install_element (BGP_NODE, &aggregate_address_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_rip_receive_version_cmd_vtysh); + install_element (OSPF_NODE, &ospf_compatible_rfc1583_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_community_list_expanded_all_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_out_cmd_vtysh); + install_element (RIPNG_NODE, &no_ipv6_distribute_list_prefix_all_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_ospf6_passive_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_metric_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_all_cmd_vtysh); + install_element (RIPNG_NODE, &ipv6_distribute_list_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_extended_any_any_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_regexp_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_ospf6_priority_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd_vtysh); + install_element (RMAP_NODE, &no_set_origin_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd_vtysh); + install_element (RMAP_NODE, &no_set_ecommunity_cost_igp_val_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged8_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_community_all_cmd_vtysh); + install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_network_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); + install_element (INTERFACE_NODE, &no_multicast_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_community3_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_community_list_standard_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf_lsa_sub_cmd_vtysh); + install_element (INTERFACE_NODE, &no_bandwidth_if_val_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_neighbor_detail_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_update_source_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd_vtysh); + install_element (RMAP_NODE, &set_ecommunity_cost_igp_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_database_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ecommunity_val_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_authkey_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_community4_exact_cmd_vtysh); + install_element (OSPF_NODE, &ospf_neighbor_priority_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); + install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_prefix_filter_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_exact_cmd_vtysh); + install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_message_sendrecv_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); + install_element (ENABLE_NODE, &show_version_bgpd_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_send_community_type_cmd_vtysh); + install_element (BGP_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_kernel_cmd_vtysh); + install_element (RMAP_NODE, &no_set_community_none_cmd_vtysh); + install_element (RIP_NODE, &no_rip_version_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_exact_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_send_community_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_dead_interval_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_authentication_addr_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged6_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_route_cmd_vtysh); + install_element (RMAP_NODE, &no_match_aspath_cmd_vtysh); + install_element (CONFIG_NODE, &debug_bgp_normal_cmd_vtysh); + install_element (BGP_NODE, &bgp_bestpath_med2_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_redistribute_source_cmd_vtysh); + install_element (INTERFACE_NODE, &no_shutdown_if_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf_zebra_sub_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_filter_list_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd_vtysh); + install_element (CONFIG_NODE, &debug_bgp_update_direct_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_always_routemap_cmd_vtysh); + install_element (BGP_NODE, &aggregate_address_summary_as_set_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_external_in_prefix_filter_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_access_list_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_list_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd_vtysh); + install_element (RMAP_NODE, &set_atomic_aggregate_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_group_in_prefix_filter_cmd_vtysh); + install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd_vtysh); + install_element (BGP_NODE, &bgp_scan_time_cmd_vtysh); + install_element (ENABLE_NODE, &debug_bgp_update_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd_vtysh); + install_element (CONFIG_NODE, &ipv6_route_ifname_pref_cmd_vtysh); + install_element (RIP_NODE, &rip_passive_interface_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_filter_list_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged1_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_seq_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_cmd_vtysh); + install_element (RMAP_NODE, &set_aspath_prepend_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd_vtysh); + install_element (RIPNG_NODE, &ipv6_distribute_list_all_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd_vtysh); + install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_route_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ip_route_source_val_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_if_rmap_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_timers_arg_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_peer_cmd_vtysh); + install_element (BGP_NODE, &bgp_log_neighbor_changes_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_in_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_connected_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); + install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); + install_element (CONFIG_NODE, &ip_route_mask_distance_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &aggregate_address_mask_cmd_vtysh); + install_element (RMAP_NODE, &match_ip_route_source_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_community4_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_ospf6_routemap_cmd_vtysh); + install_element (CONFIG_NODE, &ip_prefix_list_ge_cmd_vtysh); + install_element (CONFIG_NODE, &ip_community_list_name_standard_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_filter_list_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); + install_element (ENABLE_NODE, &debug_zebra_events_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_prefix_list_detail_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_only_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_interface_cmd_vtysh); + install_element (CONFIG_NODE, &ip_community_list_standard2_cmd_vtysh); + install_element (OSPF6_NODE, &no_ospf6_interface_area_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_prefix_list_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_rfc1583_flag_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged6_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_cmd_vtysh); + install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd_vtysh); + install_element (CONFIG_NODE, &ip_prefix_list_seq_le_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd_vtysh); + install_element (BGP_NODE, &neighbor_override_capability_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_distribute_list_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_ospf6_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_send_community_cmd_vtysh); + install_element (RMAP_NODE, &rmap_continue_seq_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_regexp_cmd_vtysh); + install_element (CONFIG_NODE, &ip_route_mask_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_connected_routemap_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ospf_transmit_delay_cmd_vtysh); + install_element (RIP_NODE, &no_rip_redistribute_type_metric_routemap_cmd_vtysh); + install_element (BGP_NODE, &neighbor_local_as_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ripng_events_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_cmd_vtysh); + install_element (CONFIG_NODE, &access_list_extended_mask_host_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd_vtysh); + install_element (ZEBRA_NODE, &ripng_redistribute_ripng_cmd_vtysh); + install_element (ZEBRA_NODE, &no_rip_redistribute_rip_cmd_vtysh); + install_element (RIP_NODE, &no_rip_default_information_originate_cmd_vtysh); + install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_summary_only_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_out_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf_packet_all_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_summary_cmd_vtysh); + install_element (INTERFACE_NODE, &ospf_hello_interval_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_community_all_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_timers_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd_vtysh); + install_element (RMAP_NODE, &set_community_delete_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged2_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_redistribute_kernel_metric_cmd_vtysh); + install_element (BGP_NODE, &bgp_network_mask_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_bgp_network_route_map_cmd_vtysh); + install_element (BGP_NODE, &neighbor_transport_connection_mode_cmd_vtysh); + install_element (RIP_NODE, &no_rip_neighbor_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_route_protocol_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_month_day_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_external_in_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &aggregate_address_summary_only_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_vlink_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_day_month_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf_event_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_allowas_in_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_day_month_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_description_arg_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_hello_interval_cmd_vtysh); + install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_ge_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_type_routemap_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_default_information_originate_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_prefix_list_prefix_first_match_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_out_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); + install_element (ENABLE_NODE, &undebug_bgp_keepalive_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_cmd_vtysh); + install_element (BGP_NODE, &neighbor_allowas_in_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf_zebra_sub_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_community_list_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_arg_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_auto_summary_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ipv6_address_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_routemap_cmd_vtysh); + install_element (OSPF_NODE, &ospf_router_id_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf_packet_all_cmd_vtysh); + install_element (BGP_NODE, &bgp_confederation_identifier_cmd_vtysh); + install_element (INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_description_val_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ripng_packet_direct_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_authentication_args_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_any_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); + install_element (RIPNG_NODE, &ripng_aggregate_address_cmd_vtysh); + install_element (CONFIG_NODE, &ip_community_list_expanded_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_route_type_cmd_vtysh); + install_element (BGP_IPV6_NODE, &no_synchronization_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd_vtysh); + install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd_vtysh); + install_element (RMAP_NODE, &no_match_ip_address_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged4_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_send_community_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_synchronization_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_prefix_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_redistribute_ipv4_cmd_vtysh); + install_element (RMAP_NODE, &no_set_ecommunity_soo_val_cmd_vtysh); + install_element (BGP_NODE, &bgp_bestpath_aspath_ignore_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_cmd_vtysh); + install_element (RIP_NODE, &no_distribute_list_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_day_month_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_community_exact_cmd_vtysh); + install_element (BGP_NODE, &bgp_damp_unset2_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_detail_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_metric_type_routemap_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_cmd_vtysh); + install_element (INTERFACE_NODE, &ospf_network_cmd_vtysh); + install_element (BGP_NODE, &bgp_redistribute_ipv4_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_extended_mask_any_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_neighbors_cmd_vtysh); + install_element (BGP_NODE, &neighbor_attr_unchanged7_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_stub_no_summary_cmd_vtysh); + install_element (RMAP_NODE, &no_set_aggregator_as_val_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_mbgp_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); + install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_intra_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_range_substitute_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd_vtysh); + install_element (ENABLE_NODE, &debug_bgp_filter_cmd_vtysh); + install_element (CONFIG_NODE, &no_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_damp_set2_cmd_vtysh); + install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_community_list_name_standard_all_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_zebra_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_detail_cmd_vtysh); + install_element (RIP_NODE, &rip_neighbor_cmd_vtysh); + install_element (BGP_IPV4_NODE, &neighbor_route_reflector_client_cmd_vtysh); + install_element (CONFIG_NODE, &ip_extcommunity_list_standard_cmd_vtysh); + install_element (CONFIG_NODE, &no_debug_rip_packet_cmd_vtysh); + install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd_vtysh); + install_element (RMAP_NODE, &no_set_ip_nexthop_val_bgp_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged8_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_bgp_events_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); + install_element (CONFIG_NODE, &no_access_list_remark_arg_cmd_vtysh); + install_element (INTERFACE_NODE, &ip_ospf_authentication_key_cmd_vtysh); + install_element (OSPF_NODE, &ospf_default_information_originate_metric_cmd_vtysh); + install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd_vtysh); + install_element (ENABLE_NODE, &rmap_show_name_cmd_vtysh); + install_element (BGP_NODE, &neighbor_send_community_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_external_out_cmd_vtysh); + install_element (BGP_NODE, &neighbor_remove_private_as_cmd_vtysh); + install_element (VIEW_NODE, &show_zebra_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_remove_private_as_cmd_vtysh); + install_element (RIP_NODE, &no_rip_network_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_compatible_rfc1583_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &neighbor_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ospf_ism_cmd_vtysh); + install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_community4_exact_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_bgp_normal_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_bestpath_med3_cmd_vtysh); + install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_route_map_cmd_vtysh); + install_element (ENABLE_NODE, &show_ip_ospf_database_type_adv_router_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_ipv6_community_all_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_detail_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf6_flooding_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_zebra_events_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_cmd_vtysh); + install_element (RMAP_NODE, &set_ecommunity_soo_cmd_vtysh); + install_element (ENABLE_NODE, &clear_ip_bgp_all_out_cmd_vtysh); + install_element (RIPNG_NODE, &no_ipv6_distribute_list_prefix_cmd_vtysh); + install_element (RIP_NODE, &rip_redistribute_type_cmd_vtysh); + install_element (CONFIG_NODE, &debug_rip_packet_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd_vtysh); + install_element (BGP_NODE, &no_neighbor_filter_list_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_ospf_database_type_id_cmd_vtysh); + install_element (BGP_IPV6_NODE, &neighbor_route_map_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_cmd_vtysh); + install_element (BGP_NODE, &no_bgp_router_id_cmd_vtysh); + install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); + install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_area_authentication_cmd_vtysh); + install_element (CONFIG_NODE, &ip_community_list_name_expanded_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_cmd_vtysh); + install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd_vtysh); + install_element (CONFIG_NODE, &no_router_ospf_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); + install_element (VIEW_NODE, &show_bgp_ipv6_community_all_cmd_vtysh); + install_element (ENABLE_NODE, &no_debug_ripng_events_cmd_vtysh); + install_element (OSPF_NODE, &no_ospf_timers_spf_cmd_vtysh); + install_element (BGP_IPV4_NODE, &no_aggregate_address_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_ge_cmd_vtysh); + install_element (VIEW_NODE, &show_ipv6_bgp_regexp_cmd_vtysh); + install_element (INTERFACE_NODE, &rip_split_horizon_cmd_vtysh); + install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_cmd_vtysh); + install_element (ENABLE_NODE, &show_bgp_community3_exact_cmd_vtysh); + install_element (RIPNG_NODE, &no_ripng_redistribute_bgp_metric_val_cmd_vtysh); + install_element (RMAP_NODE, &no_match_interface_val_cmd_vtysh); + install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd_vtysh); + install_element (BGP_NODE, &neighbor_filter_list_cmd_vtysh); + install_element (CONFIG_NODE, &debug_ospf_zebra_sub_cmd_vtysh); + install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd_vtysh); + install_element (BGP_NODE, &bgp_timers_cmd_vtysh); + install_element (BGP_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh); + install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_out_cmd_vtysh); + install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_day_month_cmd_vtysh); + install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_cmd_vtysh); + install_element (OSPF_NODE, &ospf_area_stub_no_summary_cmd_vtysh); +} diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c new file mode 100644 index 0000000..d8d2f55 --- /dev/null +++ b/vtysh/vtysh_config.c @@ -0,0 +1,439 @@ +/* Configuration generator. + Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra 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, or (at your option) any +later version. + +GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "command.h" +#include "linklist.h" +#include "memory.h" + +#include "vtysh/vtysh.h" + +vector configvec; + +struct config +{ + /* Configuration node name. */ + char *name; + + /* Configuration string line. */ + struct list *line; + + /* Configuration can be nest. */ + struct config *config; + + /* Index of this config. */ + u_int32_t index; +}; + +struct list *config_top; + +int +line_cmp (char *c1, char *c2) +{ + return strcmp (c1, c2); +} + +void +line_del (char *line) +{ + XFREE (MTYPE_VTYSH_CONFIG_LINE, line); +} + +struct config * +config_new () +{ + struct config *config; + config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config)); + return config; +} + +int +config_cmp (struct config *c1, struct config *c2) +{ + return strcmp (c1->name, c2->name); +} + +void +config_del (struct config* config) +{ + list_delete (config->line); + if (config->name) + XFREE (MTYPE_VTYSH_CONFIG_LINE, config->name); + XFREE (MTYPE_VTYSH_CONFIG, config); +} + +struct config * +config_get (int index, char *line) +{ + struct config *config; + struct config *config_loop; + struct list *master; + struct listnode *nn; + + config = config_loop = NULL; + + master = vector_lookup_ensure (configvec, index); + + if (! master) + { + master = list_new (); + master->del = (void (*) (void *))config_del; + master->cmp = (int (*)(void *, void *)) config_cmp; + vector_set_index (configvec, index, master); + } + + LIST_LOOP (master, config_loop, nn) + { + if (strcmp (config_loop->name, line) == 0) + config = config_loop; + } + + if (! config) + { + config = config_new (); + config->line = list_new (); + config->line->del = (void (*) (void *))line_del; + config->line->cmp = (int (*)(void *, void *)) line_cmp; + config->name = XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line); + config->index = index; + listnode_add (master, config); + } + return config; +} + +void +config_add_line (struct list *config, char *line) +{ + listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line)); +} + +void +config_add_line_uniq (struct list *config, char *line) +{ + struct listnode *nn; + char *pnt; + + LIST_LOOP (config, pnt, nn) + { + if (strcmp (pnt, line) == 0) + return; + } + listnode_add_sort (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line)); +} + +void +vtysh_config_parse_line (char *line) +{ + char c; + static struct config *config = NULL; + + if (! line) + return; + + c = line[0]; + + if (c == '\0') + return; + + /* printf ("[%s]\n", line); */ + + switch (c) + { + case '!': + case '#': + break; + case ' ': + /* Store line to current configuration. */ + if (config) + { + if (strncmp (line, " address-family vpnv4", strlen (" address-family vpnv4")) == 0) + config = config_get (BGP_VPNV4_NODE, line); + else if (strncmp (line, " address-family ipv4", strlen (" address-family ipv4")) == 0) + config = config_get (BGP_IPV4_NODE, line); + else if (strncmp (line, " address-family ipv4 multicast", strlen (" address-family ipv4 multicast")) == 0) + config = config_get (BGP_IPV4M_NODE, line); + else if (strncmp (line, " address-family ipv6", strlen (" address-family ipv6")) == 0) + config = config_get (BGP_IPV6_NODE, line); + else if (config->index == RMAP_NODE) + config_add_line_uniq (config->line, line); + else + config_add_line (config->line, line); + } + else + config_add_line (config_top, line); + break; + default: + if (strncmp (line, "interface", strlen ("interface")) == 0) + config = config_get (INTERFACE_NODE, line); + else if (strncmp (line, "router rip", strlen ("router rip")) == 0) + config = config_get (RIP_NODE, line); + else if (strncmp (line, "router ripng", strlen ("router ripng")) == 0) + config = config_get (RIPNG_NODE, line); + else if (strncmp (line, "router ospf", strlen ("router ospf")) == 0) + config = config_get (OSPF_NODE, line); + else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0) + config = config_get (OSPF6_NODE, line); + else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0) + config = config_get (BGP_NODE, line); + else if (strncmp (line, "router", strlen ("router")) == 0) + config = config_get (BGP_NODE, line); + else if (strncmp (line, "route-map", strlen ("route-map")) == 0) + config = config_get (RMAP_NODE, line); + else if (strncmp (line, "access-list", strlen ("access-list")) == 0) + config = config_get (ACCESS_NODE, line); + else if (strncmp (line, "ipv6 access-list", strlen ("ipv6 access-list")) == 0) + config = config_get (ACCESS_IPV6_NODE, line); + else if (strncmp (line, "ip prefix-list", strlen ("ip prefix-list")) == 0) + config = config_get (PREFIX_NODE, line); + else if (strncmp (line, "ipv6 prefix-list", strlen ("ipv6 prefix-list")) == 0) + config = config_get (PREFIX_IPV6_NODE, line); + else if (strncmp (line, "ip as-path access-list", strlen ("ip as-path access-list")) == 0) + config = config_get (AS_LIST_NODE, line); + else if (strncmp (line, "ip community-list", strlen ("ip community-list")) == 0) + config = config_get (COMMUNITY_LIST_NODE, line); + else if (strncmp (line, "ip route", strlen ("ip route")) == 0) + config = config_get (IP_NODE, line); + else if (strncmp (line, "ipv6 route", strlen ("ipv6 route")) == 0) + config = config_get (IP_NODE, line); + else if (strncmp (line, "key", strlen ("key")) == 0) + config = config_get (KEYCHAIN_NODE, line); + else + { + if (strncmp (line, "log", strlen ("log")) == 0 + || strncmp (line, "hostname", strlen ("hostname")) == 0 + || strncmp (line, "password", strlen ("hostname")) == 0) + config_add_line_uniq (config_top, line); + else + config_add_line (config_top, line); + config = NULL; + } + break; + } +} + +void +vtysh_config_parse (char *line) +{ + char *begin; + char *pnt; + + begin = pnt = line; + + while (*pnt != '\0') + { + if (*pnt == '\n') + { + *pnt++ = '\0'; + vtysh_config_parse_line (begin); + begin = pnt; + } + else + { + pnt++; + } + } +} + +/* Macro to check delimiter is needed between each configuration line + or not. */ +#define NO_DELIMITER(I) \ + ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \ + || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE || \ + (I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE) + +/* Display configuration to file pointer. */ +void +vtysh_config_dump (FILE *fp) +{ + struct listnode *nn; + struct listnode *nm; + struct config *config; + struct list *master; + char *line; + int i; + + LIST_LOOP (config_top, line, nn) + { + fprintf (fp, "%s\n", line); + fflush (fp); + } + fprintf (fp, "!\n"); + fflush (fp); + + for (i = 0; i < vector_max (configvec); i++) + if ((master = vector_slot (configvec, i)) != NULL) + { + LIST_LOOP (master, config, nn) + { + fprintf (fp, "%s\n", config->name); + fflush (fp); + + LIST_LOOP (config->line, line, nm) + { + fprintf (fp, "%s\n", line); + fflush (fp); + } + if (! NO_DELIMITER (i)) + { + fprintf (fp, "!\n"); + fflush (fp); + } + } + if (NO_DELIMITER (i)) + { + fprintf (fp, "!\n"); + fflush (fp); + } + } + + for (i = 0; i < vector_max (configvec); i++) + if ((master = vector_slot (configvec, i)) != NULL) + { + list_delete (master); + vector_slot (configvec, i) = NULL; + } + list_delete_all_node (config_top); +} + +/* Read up configuration file from file_name. */ +static void +vtysh_read_file (FILE *confp) +{ + int ret; + struct vty *vty; + + vty = vty_new (); + vty->fd = 0; /* stdout */ + vty->type = VTY_TERM; + vty->node = CONFIG_NODE; + + vtysh_execute_no_pager ("enable"); + vtysh_execute_no_pager ("configure terminal"); + + /* Execute configuration file */ + ret = vtysh_config_from_file (vty, confp); + + vtysh_execute_no_pager ("end"); + vtysh_execute_no_pager ("disable"); + + vty_close (vty); + + if (ret != CMD_SUCCESS) + { + switch (ret) + { + case CMD_ERR_AMBIGUOUS: + fprintf (stderr, "Ambiguous command.\n"); + break; + case CMD_ERR_NO_MATCH: + fprintf (stderr, "There is no such command.\n"); + break; + } + fprintf (stderr, "Error occured during reading below line.\n%s\n", + vty->buf); + exit (1); + } +} + +/* Read up configuration file from file_name. */ +void +vtysh_read_config (char *config_file, + char *config_current_dir, + char *config_default_dir) +{ + char *cwd; + FILE *confp = NULL; + char *fullpath; + + /* If -f flag specified. */ + if (config_file != NULL) + { + if (! IS_DIRECTORY_SEP (config_file[0])) + { + cwd = getcwd (NULL, MAXPATHLEN); + fullpath = XMALLOC (MTYPE_TMP, + strlen (cwd) + strlen (config_file) + 2); + sprintf (fullpath, "%s/%s", cwd, config_file); + } + else + fullpath = config_file; + + confp = fopen (fullpath, "r"); + + if (confp == NULL) + { + fprintf (stderr, "can't open configuration file [%s]\n", + config_file); + exit(1); + } + } + else + { + /* Relative path configuration file open. */ + if (config_current_dir) + confp = fopen (config_current_dir, "r"); + + /* If there is no relative path exists, open system default file. */ + if (confp == NULL) + { + confp = fopen (config_default_dir, "r"); + if (confp == NULL) + { + fprintf (stderr, "can't open configuration file [%s]\n", + config_default_dir); + exit (1); + } + else + fullpath = config_default_dir; + } + else + { + /* Rleative path configuration file. */ + cwd = getcwd (NULL, MAXPATHLEN); + fullpath = XMALLOC (MTYPE_TMP, + strlen (cwd) + strlen (config_current_dir) + 2); + sprintf (fullpath, "%s/%s", cwd, config_current_dir); + } + } + vtysh_read_file (confp); + + fclose (confp); + + host_config_set (fullpath); +} + +void +vtysh_config_write (FILE *fp) +{ + extern struct host host; + + if (host.name) + fprintf (fp, "hostname %s\n", host.name); + fprintf (fp, "!\n"); +} + +void +vtysh_config_init () +{ + config_top = list_new (); + config_top->del = (void (*) (void *))line_del; + configvec = vector_init (1); +} diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c new file mode 100644 index 0000000..f30aba4 --- /dev/null +++ b/vtysh/vtysh_main.c @@ -0,0 +1,288 @@ +/* Virtual terminal interface shell. + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "version.h" +#include "getopt.h" +#include "command.h" + +#include "vtysh/vtysh.h" +#include "vtysh/vtysh_user.h" + +/* VTY shell program name. */ +char *progname; + +/* Configuration file name. Usually this is configurable, but vtysh + has static configuration file only. */ +char *config_file = NULL; + +/* Configuration file and directory. */ +char *config_current = NULL; +char config_default[] = SYSCONFDIR VTYSH_DEFAULT_CONFIG; + +/* Integrated configuration file. */ +char *integrate_file = NULL; +char *integrate_current = NULL; +#if 0 +char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; +#endif + +/* Flag for indicate executing child command. */ +int execute_flag = 0; + +/* For sigsetjmp() & siglongjmp(). */ +static sigjmp_buf jmpbuf; + +/* Flag for avoid recursive siglongjmp() call. */ +static int jmpflag = 0; + +/* A static variable for holding the line. */ +static char *line_read; + +/* Master of threads. */ +struct thread_master *master; + +/* SIGTSTP handler. This function care user's ^Z input. */ +void +sigtstp (int sig) +{ + /* Execute "end" command. */ + vtysh_execute ("end"); + + /* Initialize readline. */ + rl_initialize (); + printf ("\n"); + + /* Check jmpflag for duplicate siglongjmp(). */ + if (! jmpflag) + return; + + jmpflag = 0; + + /* Back to main command loop. */ + siglongjmp (jmpbuf, 1); +} + +/* SIGINT handler. This function care user's ^Z input. */ +void +sigint (int sig) +{ + /* Check this process is not child process. */ + if (! execute_flag) + { + rl_initialize (); + printf ("\n"); + rl_forced_update_display (); + } +} + +/* Signale wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGINT, sigint); + signal_set (SIGTSTP, sigtstp); + signal_set (SIGPIPE, SIG_IGN); +} + +/* Help information display. */ +static void +usage (int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\n\ +Daemon which manages kernel routing table management and \ +redistribution between different routing protocols.\n\n\ +-b, --boot Execute boot startup configuration\n\ +-e, --eval Execute argument as command\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + exit (status); +} + +/* VTY shell options, we use GNU getopt library. */ +struct option longopts[] = +{ + { "boot", no_argument, NULL, 'b'}, + { "eval", required_argument, NULL, 'e'}, + { "help", no_argument, NULL, 'h'}, + { 0 } +}; + +/* Read a string, and return a pointer to it. Returns NULL on EOF. */ +char * +vtysh_rl_gets () +{ + /* If the buffer has already been allocated, return the memory + to the free pool. */ + if (line_read) + { + free (line_read); + line_read = NULL; + } + + /* Get a line from the user. Change prompt according to node. XXX. */ + line_read = readline (vtysh_prompt ()); + + /* If the line has any text in it, save it on the history. */ + if (line_read && *line_read) + add_history (line_read); + + return (line_read); +} + +/* VTY shell main routine. */ +int +main (int argc, char **argv, char **env) +{ + char *p; + int opt; + int eval_flag = 0; + int boot_flag = 0; + char *eval_line = NULL; + char *integrated_file = NULL; + + /* Preserve name of myself. */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + /* Option handling. */ + while (1) + { + opt = getopt_long (argc, argv, "be:h", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'b': + boot_flag = 1; + break; + case 'e': + eval_flag = 1; + eval_line = optarg; + break; + case 'h': + usage (0); + break; + case 'i': + integrated_file = strdup (optarg); + default: + usage (1); + break; + } + } + + /* Initialize user input buffer. */ + line_read = NULL; + + /* Signal and others. */ + signal_init (); + + /* Make vty structure and register commands. */ + vtysh_init_vty (); + vtysh_init_cmd (); + vtysh_user_init (); + vtysh_config_init (); + + vty_init_vtysh (); + + sort_node (); + + vtysh_connect_all (); + + /* Read vtysh configuration file. */ + vtysh_read_config (config_file, config_current, config_default); + + /* If eval mode */ + if (eval_flag) + { + vtysh_execute_no_pager (eval_line); + exit (0); + } + + /* Boot startup configuration file. */ + if (boot_flag) + { + vtysh_read_config (integrate_file, integrate_current, integrate_default); + exit (0); + } + + vtysh_pager_init (); + + vtysh_readline_init (); + + vty_hello (vty); + + vtysh_auth (); + + /* Preparation for longjmp() in sigtstp(). */ + sigsetjmp (jmpbuf, 1); + jmpflag = 1; + + /* Main command loop. */ + while (vtysh_rl_gets ()) + vtysh_execute (line_read); + + printf ("\n"); + + /* Rest in peace. */ + exit (0); +} diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c new file mode 100644 index 0000000..b84da2e --- /dev/null +++ b/vtysh/vtysh_user.c @@ -0,0 +1,191 @@ +/* User authentication for vtysh. + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include + +#ifdef USE_PAM +#include +#include +#endif /* USE_PAM */ + +#include "memory.h" +#include "linklist.h" +#include "command.h" + +#ifdef USE_PAM +static struct pam_conv conv = +{ + misc_conv, + NULL +}; + +int +vtysh_pam (char *user) +{ + int ret; + pam_handle_t *pamh = NULL; + + /* Start PAM. */ + ret = pam_start("zebra", user, &conv, &pamh); + /* printf ("ret %d\n", ret); */ + + /* Is user really user? */ + if (ret == PAM_SUCCESS) + ret = pam_authenticate (pamh, 0); + /* printf ("ret %d\n", ret); */ + +#if 0 + /* Permitted access? */ + if (ret == PAM_SUCCESS) + ret = pam_acct_mgmt (pamh, 0); + printf ("ret %d\n", ret); + + if (ret == PAM_AUTHINFO_UNAVAIL) + ret = PAM_SUCCESS; +#endif /* 0 */ + + /* This is where we have been authorized or not. */ +#ifdef DEBUG + if (ret == PAM_SUCCESS) + printf("Authenticated\n"); + else + printf("Not Authenticated\n"); +#endif /* DEBUG */ + + /* close Linux-PAM */ + if (pam_end (pamh, ret) != PAM_SUCCESS) + { + pamh = NULL; + fprintf(stderr, "vtysh_pam: failed to release authenticator\n"); + exit(1); + } + + return ret == PAM_SUCCESS ? 0 : 1; +} +#endif /* USE_PAM */ + +struct user +{ + char *name; + u_char nopassword; +}; + +struct list *userlist; + +struct user * +user_new () +{ + struct user *user; + user = XMALLOC (0, sizeof (struct user)); + memset (user, 0, sizeof (struct user)); + return user; +} + +void +user_free (struct user *user) +{ + XFREE (0, user); +} + +struct user * +user_lookup (char *name) +{ + struct listnode *nn; + struct user *user; + + LIST_LOOP (userlist, user, nn) + { + if (strcmp (user->name, name) == 0) + return user; + } + return NULL; +} + +void +user_config_write () +{ + struct listnode *nn; + struct user *user; + + LIST_LOOP (userlist, user, nn) + { + if (user->nopassword) + printf (" username %s nopassword\n", user->name); + } +} + +struct user * +user_get (char *name) +{ + struct user *user; + user = user_lookup (name); + if (user) + return user; + + user = user_new (); + user->name = strdup (name); + listnode_add (userlist, user); + + return user; +} + +DEFUN (username_nopassword, + username_nopassword_cmd, + "username WORD nopassword", + "\n" + "\n" + "\n") +{ + struct user *user; + user = user_get (argv[0]); + user->nopassword = 1; + return CMD_SUCCESS; +} + +int +vtysh_auth () +{ + struct user *user; + struct passwd *passwd; + + passwd = getpwuid (geteuid ()); + + user = user_lookup (passwd->pw_name); + if (user && user->nopassword) + /* Pass through */; + else + { +#ifdef USE_PAM + if (vtysh_pam (passwd->pw_name)) + exit (0); +#endif /* USE_PAM */ + } + return 0; +} + +void +vtysh_user_init () +{ + userlist = list_new (); + install_element (CONFIG_NODE, &username_nopassword_cmd); +} diff --git a/vtysh/vtysh_user.h b/vtysh/vtysh_user.h new file mode 100644 index 0000000..8d0a4cf --- /dev/null +++ b/vtysh/vtysh_user.h @@ -0,0 +1,27 @@ +/* User authentication for vtysh. + * Copyright (C) 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _VTYSH_USER_H +#define _VTYSH_USER_H + +int vtysh_auth (); + +#endif /* _VTYSH_USER_H */ diff --git a/zebra/ChangeLog b/zebra/ChangeLog new file mode 100644 index 0000000..0c123fe --- /dev/null +++ b/zebra/ChangeLog @@ -0,0 +1,1230 @@ +2003-11-11 Kunihiro Ishiguro + + * rt_netlink.c (netlink_parse_info): Ignore non kernel message. + +2003-02-06 Francois Deppierraz + + * rt_netlink.c (netlink_route_multipath): Set RTM_F_EQUALIZE when + it exists. + +2002-09-28 Akihiro Mizutani + + * zebra_rib.c (static_add_ipv4): Null0 static route is added. + +2002-09-10 Jochen Friedrich + + * rt_netlink.c: Add check for EAGAIN. + * kernel_socket.c: Likewise + +2002-06-12 Israel Keys + + * rt_netlink.c: Setting the NLM_F_ACK flag on the netlink command + message so that we get an ACK for successful netlink commands. + Change the netlink socket to BLOCKING while we wait for a + response; be it an ACK or an NLMSG_ERROR. Change + netlink_parse_info to deal with ACK messages. + +2001-11-01 Jun-ichiro itojun Hagino + + * rtadv.c (rtadv_make_socket): setsockopt(IPV6_CHECKSUM) does not + work for ICMPv6 socket. + +2001-10-24 Kunihiro Ishiguro + + * rib.c (rib_process): Select connected route any case. + +2001-10-23 Kunihiro Ishiguro + + * interface.c (no_ip_address_secondary): Add "no" to command. + +2001-10-18 NOGUCHI Kay + + * ioctl.c (if_prefix_add_ipv6): Set the prefered and valid lifetime + to infinity as the freebsd4.4 workaroud. + +2001-08-26 mihail.balikov@interbgc.com + + * zebra_snmp.c: Fix snmpwalk problem such as IPv4 address + A.B.C.255. + +2001-08-22 NOGUCHI Kay + + * rtadv.c: Do not send RA to loopback interface. + +2001-08-20 Kunihiro Ishiguro + + * ioctl.c (if_set_prefix): Remove Linux 2.0 specific connected + route treatment. + +2001-08-19 Kunihiro Ishiguro + + * zebra-0.92a released. + +2001-08-17 Kunihiro Ishiguro + + * rib.c: Kernel route is treated as EGP routes in nexthop active + check. + +2001-08-15 Kunihiro Ishiguro + + * zebra-0.92 released. + +2001-08-08 "Akihiro Mizutani" + + * rib.c (show_ip_route_prefix_longer): Add longer-prefix option to + show route commands. + +2001-07-29 Yon Uriarte + + * zserv.c (zsend_ipv4_add_multipath): Add + NEXTHOP_TYPE_IPV4_IFINDEX check. + +2001-07-29 NOGUCHI Kay + + * rtadv.c: Apply valid lifetime, preferred lifetime, onilnk flag, + autonomous address-configuration flag patch. + (no_ipv6_nd_suppress_ra): Change "ipv6 nd send-ra" to "no ipv6 nd + suppress-ra". + +2001-07-24 NOGUCHI Kay + + * rtadv.c (ipv6_nd_ra_interval): Add "ipv6 nd ra-interval SECONDS" + command. + +2001-07-24 Jun-ichiro itojun Hagino + + * rt_socket.c (kernel_rtm_ipv4): Add KAME/NetBSD151 equal cost + multicast FIB support both IPv4 and IPv6. + +2001-07-24 Hal Snyder + + * if_ioctl.c (interface_list_ioctl): Fix bug of failing to get the + full list of interfaces on some configurations of OpenBSD. + +2001-07-23 NOGUCHI Kay + + * rtadv.c (ipv6_nd_send_ra): Apply [zebra 9320] to fix "ipv6 nd + send-ra" bug. + (ipv6_nd_ra_lifetime): "ipv6 nd ra-lifetime 0" for default router + availability. + (ipv6_nd_managed_config_flag): "ipv6 nd managed-config-flag" is + added. + (ipv6_nd_other_config_flag): "ipv6 nd other-config-flag" is added. + +2001-07-23 Jun-ichiro itojun Hagino + + * ioctl.c (if_ioctl): Change ioctl argument from int to u_long. + + * rt_ioctl.c: Likewise. + +2001-07-23 Jun-ichiro itojun Hagino + + * kernel_socket.c (rtm_write): Only set RTF_CLONING when the + interface is not p2p. + +2001-04-23 Kunihiro Ishiguro + + * ioctl.c (if_prefix_add_ipv6): Fix argument type. + +2001-04-06 Toshiaki Takada + + * zserv.c (zsend_interface_delete): Use client->obuf instead of + allocating new stream. + +2001-03-10 Kunihiro Ishiguro + + * rt_netlink.c: Revert RTPROT_BOOT change. + +2001-03-08 Kunihiro Ishiguro + + * rt_netlink.c (netlink_route_change): Skip RTPROT_BOOT route. + (netlink_routing_table): Likewise. + +2001-03-07 "Akihiro Mizutani" + + * zserv.c (zsend_ipv4_add_multipath): Send metric value to + protocol daemons. + +2001-02-18 Kunihiro Ishiguro + + * rt_netlink.c (netlink_routing_table): Do not return + tb[RTA_GATEWAY] is NULL. Reported by: "Michael O'Keefe" + . + +2001-02-08 Kunihiro Ishiguro + + * if_ioctl.c (interface_list_ioctl): Call if_add_update(). + Suggested by: Chris Dunlop . + +2001-02-01 Kunihiro Ishiguro + + * rib.c (nexthop_active_ipv4): When nexthop type is + NEXTHOP_TYPE_IPV4_IFINDEX, propery set the ifindex to rifindex. + + * zserv.c: Initialize rtm_table_default with 0. + + * zebra-0.91 is released. + +2001-01-31 Kunihiro Ishiguro + + * kernel_socket.c (rtm_read): Filter cloned route. Suggested by: + Jun-ichiro itojun Hagino + +2001-01-30 Kunihiro Ishiguro + + * connected.c (connected_up_ipv6): When point-to-point destination + address is ::, use local address for connected network. + (connected_down_ipv6): Likewise. + +2001-01-25 Kunihiro Ishiguro + + * zserv.c (zebra_serv): Add missing close() call. Reported by: + David Waitzman . + +2001-01-24 Kunihiro Ishiguro + + * rib.c (rib_lookup_ipv4): New function for checking exact match + IGP route. + +2001-01-23 Kunihiro Ishiguro + + * rib.c (show_ipv6_route_protocol): Fix bug of "show ip route + route-type". + +2001-01-22 Kunihiro Ishiguro + + * interface.c (zebra_interface): Do not call + zebra_interface_add_update for inactive interface. + + * zserv.c (zsend_interface_address_add): Send interface address + flag. + (zsend_interface_address_delete): Likewise. + +2001-01-19 Kunihiro Ishiguro + + * interface.c (if_addr_add): Add flags. + + * connected.c (ifa_add_ipv4): Add new function for interface + address handling. + (ifa_delete_ipv4): Likewise. + +2001-01-16 Kunihiro Ishiguro + + * rib.c (rib_update): Update IPv6 RIB. + + * kernel_socket.c (ifam_read): Call if_refresh() for update + interface flag status. This is for implicit interface up on *BSD. + + * interface.c (if_refresh): Add interface flag refresh function. + + * kernel_socket.c (rtm_read): Fetch link-local address interface + index. + (ifan_read): We need to fetch interface information. Suggested + by: Yasuhiro Ohara . + + * rib.c (static_ipv6_nexthop_same): Add check for + NEXTHOP_TYPE_IPV6_IFNAME. + +2001-01-15 Kunihiro Ishiguro + + * rib.h (NEW_RIB): Turn on NEW_RIB flag. IPv6 new RIB code are + taken into place. + +2001-01-14 Kunihiro Ishiguro + + * rib.c (static_ipv6_write): Display STATIC_IPV6_GATEWAY_IFNAME + configuration. + (rib_delete_ipv6): Handle same route conter for IPv6 connected + route. + (show_ipv6_route_protocol): New command. + (show_ipv6_route_addr): Likewise. + (show_ipv6_route_prefix): Likewise. + (rib_update): Sweep kernel route when it is cleaned up. + + * rt_socket.c (kernel_add_ipv6): Add NEXTHOP_IPV6_IFNAME + treatmenet. + + * rt_netlink.c (kernel_init): Likewise. + + * rt_ioctl.c (kernel_ioctl_ipv6_multipath): Likewise. + + * rib.c (rib_add_ipv4): Cope with same connected route on a + interface. Suggested by: Matthew Grant . + (nexthop_ipv6_ifname_add): Add NEXTHOP_IPV6_IFNAME treatmenet. + + * rib.h (struct new_rib): Add refcnt to keep track on the + reference of same connected route. + + * ioctl.c (if_set_prefix): Add check for GNU_LINUX. + +2001-01-13 Yasuhiro Ohara + + * kernel_socket.c (ifan_read, rtm_type_str): Add RTM_OIFINFO check. + (rtm_type_str): Add RTM_IFANNOUNCE check. + (ifan_read): New function. + (kernel_read): Add case for RTM_IFANNOUNCE. + +2001-01-13 Kunihiro Ishiguro + + * rt_ioctl.c (kernel_ioctl_ipv6_multipath): New function. + + * rt_netlink.c (netlink_route_multipath): IPv6 address ifindex + treatment. + + * connected.c (connected_up_ipv6): Add dest value check. + + * rib.c (nexthop_active_ipv6): Do not touch IPv6 nexthop's + ifindex. + (rib_add_ipv4): Import rib_add_ipv6() same route check code. + (nexthop_active_check): NEXTHOP_TYPE_IPV6_IFINDEX activity is only + checked by ifindex. + + * rt_socket.c (kernel_rtm_ipv6_multipath): New function. + + * redistribute.c (redistribute_add): Use + zsend_ipv6_add_multipath(). + (redistribute_delete_multipath): Use + zsend_ipv6_delete_multipath(). + + * interface.c (ip_address): Check current IP address to avoid + duplicate. + + * rib.c (rib_delete_ipv4): When deleted route is connected route, + check ifindex. + (rib_add_ipv4): When connected route is added do not perform + implicit withdraw. + (rib_delete_ipv4): Check ifindex for connected route. + + * kernel_socket.c (rtm_read): When route has RTF_STATIC, set + ZEBRA_FLAG_STATIC for indicate as persistent route. + (ifam_read): Unset interface index from link-local address when + IPv6 stack is KAME. + + * rib.c (rib_update): Do not delete persistent kernel route. + + * rib.h (struct new_rib): Integrate RIB_FLAG_* to ZEBRA_FLAG_*. + + * rt_socket.c (kernel_add_ipv6_multipath): Add placeholder. + (kernel_delete_ipv6_multipath): Likewise. + + * rt_netlink.c (netlink_talk): Give struct nlsock to netlink_talk. + +2001-01-12 Kunihiro Ishiguro + + * rib.c (rib_update): Revert Matthew Grant's patch + zebra_cvs_newribfix.patch. Use struct rib->ifindex for kernel + interface index. Introduce NEXTHOP_TYPE_IPV4_IFINDEX to support + that. Add support for address deletion situation. + +2001-01-11 Kunihiro Ishiguro + + * interface.c: Remove HAVE_IF_PSEUDO part. + + * rib.h: Likewise. + + * rt_netlink.c (netlink_link_change): Likewise. + +2001-01-10 Kunihiro Ishiguro + + * zserv.c: Remove OLD_RIB codes. + +2001-01-09 Kunihiro Ishiguro + + * zebra-0.90 is released. + +2001-01-09 Matthew Grant + + * interface.c (if_new_intern_ifindex): Allocate a new internal + interface index. + (if_addr_refresh): Fix up ip addresses configured via zebra. + (if_add_update): Handle an interface addition. + (if_delete_update): Handle an interface delete event. + + * rib.c (nexthop_ipv4_add): Add kernel route deletion process when + interface goes down. + +2001-01-08 Kunihiro Ishiguro + + * interface.c (if_dump_vty): When HAVE_NET_RT_IFLIST is defined, + NetBSD also use this function. Suggested by Jasper Wallace + . + +2001-01-07 Kunihiro Ishiguro + + * rib.c (nexthop_active_ipv4): Move back to set methodo to old + one. + +2001-01-05 Kunihiro Ishiguro + + * rib.c (rib_add_ipv4): EBGP multihop set ZEBRA_FLAG_INTERNAL + flag, so treat it. + +2001-01-04 Kunihiro Ishiguro + + * rt_netlink.c (netlink_talk_ipv6): When IPv6 route message is + sent from netlink_cmd, the same message comes from netlink. To + avoid confusion, temporary netlink_talk_ipv6 use netlink.sock + instead of netlink_cmd.sock. + +2001-01-01 Kunihiro Ishiguro + + * zserv.h (ZEBRA_SERV_PATH): Change "/tmp/zebra" to "/tmp/.zebra". + Change "/tmp/zserv" to "/tmp/.zserv". + +2000-12-29 Frank van Maarseveen + + * rt_netlink.c (struct nlsock): Divide kernel message into listen + socket and command socket. + (netlink_talk): Remove socket listen code. Use netlink_parse_info + for read kernel response. + +2000-12-29 Kunihiro Ishiguro + + * rib.c (vty_show_ip_route): Show uptime of the RIP,OSPF,BGP + routes. + +2000-12-27 Kunihiro Ishiguro + + * rt_netlink.c (netlink_route_multipath): Metric value is + reflected to kernel routing table. + + * rt_ioctl.c (kernel_ioctl_ipv4_multipath): Likewise. + + * kernel_socket.c (rtm_write): Likewise. + + * rib.c (nexthop_active_ipv4): Only iBGP route perform recursive + nexthop lookup. + + * rt_ioctl.c (kernel_ioctl_ipv4_multipath): Add ioctl version of + new RIB implementation. + +2000-12-26 Kunihiro Ishiguro + + * rib.h: Remove MULTIPATH_NUM. It is defined by configure script. + +2000-12-25 Michael Rozhavsky + + * rib.c (rib_if_up): Call rib_fib_set instead of RIB_FIB_SET for + proper redistribution. + +2000-12-19 Kunihiro Ishiguro + + * rib.c (nexthop_active_ipv4): Add self lookup nexthop check. + (show_ip_route_protocol): Support new RIB. + + * rt_netlink.c (netlink_route_change): Do not return when gate is + NULL. + +2000-12-18 Kunihiro Ishiguro + + * rib.c (rib_lookup_ipv4_nexthop): IBGP nexthop check function is + updated. + (rib_add_ipv4): Free implicit withdraw route's RIB. + +2000-12-15 Kunihiro Ishiguro + + * rib.c (nexthop_active_ipv4): Check indirect nexthop. + + * redistribute.c (redistribute_add_multipath): Redistribution + works with new rib code. + +2000-12-14 Kunihiro Ishiguro + + * rt_netlink.c (netlink_route_multipath): Check useful nexthop + number. + (netlink_route_multipath): Clear rtnh_flags and rtnh_hops. + + * rib.c (nexthop_active_update): Set flag for the rib's nexthop + activity is changed. + (nexthop_active_check): Before checking interface is up, make it + sure the interface exist. + +2000-11-20 Kunihiro Ishiguro + + * rib.c (ip_route): New RIB prototype. + +2000-11-16 Yon Uriarte + + * zserv.c (zsend_interface_add): Send hardware address when + hw_addr_len is greater than 0. + +2000-11-07 Kunihiro Ishiguro + + * connected.c (connected_up_ipv4): Fix ptop bug. The destination + network should be installed into routing table. + (connected_down_ipv4): Likewise. + (connected_add_ipv4): Change to use connected_up_ipv4. + (connected_delete_ipv4): Likewise. + +2000-11-06 Kunihiro Ishiguro + + * rt_netlink.c (netlink_interface_addr): Revert Harald Welte + 's ptop patch then back to original code to + avoid duplicated connected route problem. Suggested by Frank van + Maarseveen . + + * kernel_socket.c (rtm_read): Make behavior consistent even #ifdef + DEBUG is defined. Reported by Jun-ichiro itojun Hagino + . + +2000-10-23 Jochen Friedrich + + * main.c (main): Call zebra_snmp_init() when it is enabled. + +2000-10-23 Kunihiro Ishiguro + + * zserv.c (zebra_serv_un): UNIX domain socket server of zebra + protocol. + +2000-10-19 Kunihiro Ishiguro + + * rib.c (rib_add_ipv4): Same check bug is fixed. + +2000-10-03 Kunihiro Ishiguro + + * rib.c (rib_if_down): Remove kernel route when the interface goes + down. + + * debug.c: New command "debug zebra kernel" is added. + +2000-10-02 Kunihiro Ishiguro + + * zebra-0.89 is released. + +2000-09-24 Harald Welte + + * rt_netlink.c (netlink_interface_addr): Fix point-to-point address + treatment in netlink interface. + +2000-09-21 David Lipovkov + + * rib.c (rib_if_down): Pull static route only. Protocol daemon + must withdraw routes when interface goes down. + (rib_add_ipv4): Check nexthop when replace route. + +2000-09-21 Kunihiro Ishiguro + + * if_ioctl.c (if_getaddrs): New function for looking up + interface's address by getifaddrs(). + +2000-09-10 Kunihiro Ishiguro + + * connected.c (connected_delete_ipv4): Add check for connected + address is found or not. + (connected_add_ipv6): Reflect IPv6 connected address change to + protocol daemons. + (connected_delete_ipv6): Likewise. + +2000-09-07 David Lipovkov + + * rib.c (rib_delete_ipv4): Reverted the change from pseudo + interface patch to original. Because ospfd deletes routes using + zero ifindex. + +2000-08-17 Kunihiro Ishiguro + + * zebra-0.88 is released. + +2000-08-15 "Akihiro Mizutani" + + * rib.c (show_ip_route_protocol): Help string correction. + (show_ip_route_prefix): Check prefix mask. + (show_ip_route_vty_detail): Display distance and metric. + +2000-08-14 Kunihiro Ishiguro + + * zserv.c (zsend_interface_add): Change ifindex store size from + two octet to four. + (zsend_interface_delete): Likewise. + (zsend_interface_address_add): Likewise. + (zsend_interface_address_delete): Likewise. + (zsend_interface_up): Likewise. + (zsend_interface_down): Likewise. + +2000-08-13 Kunihiro Ishiguro + + * rib.c (rib_add_ipv4): Do not install distance 255 route. + +2000-08-10 Toshiaki Takada + + * interface.c (bandwidth_if), (no_bandwidth_if): Call + zebra_interface_up_update () instead of using if_up() and if_down(). + +2000-08-07 "Akihiro Mizutani" + + * interface.c (bandwidth_if): Fix help string. + +2000-08-07 Matthew Grant + + * interface.c (if_dump_vty): Display bandwidth value. + (bandwidth_if): New command "bandwidth <1-10000000>" is added. + When interface is up, force protocol daemons to recalculate routes + due to cost change. + (no_bandwidth_if): Likewise. + (if_config_write): Output bandwidth configuration. + + * zserv.c (zsend_interface_add): Send bandwidth value. + (zsend_interface_up): Likewise. + (zsend_interface_down): Likewise. + + +2000-08-07 Michael Rozhavsky + + * rib.c (show_ip_route_protocol): "show ip route + (bgp|connected|kernel|ospf|rip|static)" is added. + +2000-08-07 Kunihiro Ishiguro + + * rib.c (rib_lookup_ipv4_nexthop): Check parent node until IGP + nexthop is found. + (rib_add_ipv4_internal): Set fib ifindex to rib ifindex. + +2000-08-06 Kunihiro Ishiguro + + * redistribute.c (redistribute_delete): Fix bug of default route + redistribute treatment. + +2000-08-05 Kunihiro Ishiguro + + * rib.c (rib_init): Install ip_node in rib.c instead of zserv.c. + Change default distance value. + + Old New + ------------------------------------------ + system 10 0 + kernel 20 0 + connected 30 0 + static 40 1 + rip 50 120 + ripng 50 120 + ospf 60 110 + ospf6 49 110 + bgp 70 200(iBGP) 20(eBGP) + ------------------------------------------ + + * zserv.c (client_lookup): Function removed. + (zsend_interface_add): Use client's output buffer. Check ifinfo + flag. + (zsend_interface_delete): Likewise. + Delete ipv4_static_radix and ipv6_static_radix. + +2000-08-02 Kunihiro Ishiguro + + * zserv.h (struct zebra_client): When client request interface + information, ifinfo is set. + + * rib.c: Temporary Revert changes for pseudo interface. + + * rib.h: Likewise. + + * zserv.c: Likewise. + + * interface.c: Likewise. + +2000-08-02 David Lipovkov + + * interface.c (zebra_if_init): Install interface "pseudo" + commands. + + * rib.c (rib_create): ifname argument is added. + (rib_add_ipv4_pseudo): New function is added. + (rib_delete_ipv4_pseudo): Likewise. + + * rib.h : Delete INTERFACE_UNKNOWN definition. Add prototype for + pseudo interface functions. + + * rt_netlink.c (netlink_link_change): Check for pseudo interface. + + * zserv.c (ip_route): When destination is pseudo interface, call + rib_add_ipv4_pseudo(). + + * zserv.c (no_ip_route): Trim "unknown" argument. + +2000-07-26 kunitake@dti.ad.jp + + * if_ioctl.c (if_get_hwaddr): Fix hardware address length from 8 + to 6. + + * rtadv.c (rtadv_send_packet): Fix shift bug for hardware address. + +2000-07-24 Akihiro Mizutani + + * interface.c: Use install_default() for common VTY commands. + +2000-07-23 Kunihiro Ishiguro + + * if_ioctl.c (interface_list_ioctl): A interface list size is + calculated from ifreq->if_addr.sa_len. This is for OpenBSD. + + * ioctl.c (if_get_mtu): Remove codes for SIOCGIFDATA. + +2000-07-09 Chris Dunlop + + * if_ioctl.c (if_get_index): Add check for HAVE_BROKEN_ALIASES. + +2000-07-04 Kunihiro Ishiguro + + * zserv.c (zebra_client_read): Add ZEBRA_REDISTRIBUTE_{ADD,DELETE} + message handling. + +2000-07-02 David Lipovkov + + * zserv.c: "ip route A.B.C.D/M unknown" command is added. + +2000-06-28 Michael Rozhavsky + + * rib.c: Remove old kernel route when new route comes in. + +2000-06-13 David Lipovkov + + * rib.c (rib_if_up): Add check for unknown interface. + +2000-06-13 Kunihiro Ishiguro + + * rib.h: Define INTERFACE_UNKNOWN. + +2000-06-08 Kunihiro Ishiguro + + * Makefile.am (EXTRA_DIST): Move irdp.c until implementation is + finished. + +2000-06-05 David Lipovkov + + * interface.c (if_zebra_delete_hook): Call rib_if_delete(). + + * redistribute.c (zebra_interface_delete_update): New function. + + * redistribute.h (zebra_interface_delete_update): New function + prototype. + + * rib.c (rib_if_delete): New function. Walk down all routes and + delete all on the interface. + + * rib.h: New function prototype. + + * rt_netlink.c (netlink_link_change): Call + zebra_interface_delete_update (). + +2000-05-10 Kunihiro Ishiguro + + * if_ioctl.c (interface_info_ioctl): Check interface's flag before + checking interface's address. + +2000-04-26 Jochen Friedrich + + * GNOME-PRODUCT-ZEBRA-MIB: New file. + + * GNOME-SMI: New file. + +2000-04-23 Kunihiro Ishiguro + + * irdp.c: New file from 1997 development code. + * irdp.h: Likewise. + +2000-04-19 Kunihiro Ishiguro + + * rtadv.c (rtadv_send_packet): Enclose router advertisement + logging with IS_ZEBRA_DEBUG_PACKET. + +2000-04-17 Kunihiro Ishiguro + + * zserv.c (zebra_client_close): Remove client structure from + client_list when connection is terminated. + +2000-03-21 David Lipovkov + + * connected.c (connected_add_ipv4): Allows all necessary structure + updates for connected route, but doesn't insert it into rib if + it's interface is down. + +2000-01-21 Hideto Yamakawa + + * rtread_getmsg.c: Set some definition for Solaris 2.5 and Solaris + 2.5.1. + +2000-01-21 Kunihiro Ishiguro + + * rib.c (no_ipv6_route_ifname): Fix buf of cheking return value + from str2prefix_ipv6(). + +2000-01-14 Kunihiro Ishiguro + + * rt_socket.c: Revert to use RTF_HOST for IPv4 with /32 route and + IPv6 with /128 routes. + (kernel_rtm_ipv4): In case of /32 route's gateway is interface. It + should have mask for cloning. + +1999-12-26 Jochen.Friedrich@genorz.de + + * interface.c (if_dump_vty): Fix a bug of missing VTY_NEWLINE. + +1999-12-23 Alex Zinin + * interface.*: dynamic int up/down support + +1999-12-09 Kunihiro Ishiguro + + * ipforward_proc.c (dropline): Move dropline() from lib/dropline.c + + * rtread_proc.c (proc_route_read): Don't use dropline(). + +1999-12-08 Kunihiro Ishiguro + + * kernel_socket.c (rtm_read): When message is RTM_GET, it has own + process's pid. + +1999-12-04 Kunihiro Ishiguro + + * main.c (main): Change to default log output to ZLOG_STDOUT. + + * zserv.c (zebra_serv): More detailed error print. + +1999-11-30 Kunihiro Ishiguro + + * kernel_socket.c (rtm_read): Check old pid for static route + insertion check. + +1999-11-30 Kunihiro Ishiguro + + * interface.c (if_dump_vty): BSDI/OS uses 64bit for interface + statistics counter. + + * mtu_kvm.c: New file added. + +1999-11-27 Vladimir B. Grebenschikov + + * kernel_socket.c (rtm_write): Set RTF_CLONING flag for + route to the directly connected interface. + +1999-11-27 Kunihiro Ishiguro + + * rt_socket.c: Delete USE_HOST_BIT definition. + +1999-11-21 Michael Handler + + * rtread_getmsg.c: Undef some definition to resolve conflict. + +1999-11-27 Kunihiro Ishiguro + + * kernel_socket.c (rtm_write): Change to use pre stored struct_dl + value for gateway specification. + +1999-11-25 Kunihiro Ishiguro + + * rt_socket.c (kernel_rtm_ipv4): Even mask is 32 under IPv4 or + 128 under IPv6, don't use RTF_HOST. + +1999-11-21 Kunihiro Ishiguro + + * Makefile.am (EXTRA_DIST): Add rtread_getmsg.c. + +1999-11-21 Michael Handler + + * rtread_getmsg.c: Added for Solaris 2.6 support. + +1999-11-18 Kunihiro Ishiguro + + * rtread_sysctl.c (rtm_read_route): RTM_DELETE handling added. + + * rt_socket.c (kernel_read): Better BSD routing socket support. + +1999-10-19 Kunihiro Ishiguro + + * client_main.c: Disable making obsolete zebra test `client' + command. + +1999-10-18 Kunihiro Ishiguro + + * zebra.c: Renamed to zserv.c. + + * zebra.h: Global definitions are moved to lib/zebra.h. Then + renamed to zserv.h. + +1999-10-15 Jordan Mendelson + + * if_ioctl.c: Add Linux 2.2.X's alias support and dynamic + interface. Remove ugly MAX_INTERFACE handling codes. + +1999-09-17 Satosi KOBAYASI + + * Fix serious bug of IPv6 route deletion. + +1999-09-11 Kunihiro Ishiguro + + * ioctl.c (if_set_prefix): Properly set broadcast address. + +1999-09-04 Yasuhiro Ohara + + * rib.c (rib_add_ipv6, rib_delete_ipv6): now protocol daemons + can install connected route to kernel via zebra + +1999-08-24 VOP + + * rib.c: Include "sockunion.h" + +1999-08-22 Kunihiro Ishiguro + + * ipforward.h: New file. + + * zebra.h: Obsolete message ZEBRA_GET_ALL_INTERFACE, + ZEBRA_GET_ONE_INTERFACE, ZEBRA_GET_HOSTINFO are deleted. + +1999-08-18 Kunihiro Ishiguro + + * zebra.h (ZEBRA_INTERFACE_ADDRESS_ADD): + ZEBRA_INTERFACE_{ADD,DELETE} added. + +1999-08-15 Kunihiro Ishiguro + + * rib.c: show ip route A.B.C.D works. + + * zebra.c (zebra_read_ipv4): Add ifindex to zebra messages. + +1999-08-12 Kunihiro Ishiguro + + * zebra.h: New Zebra message ZEBRA_INTERFACE_{ADD,DELETE} added. + +1999-08-09 Kunihiro Ishiguro + + * interface.h: New file. + * Makefile.am: Add interface.h + +1999-08-04 Yasuhiro Ohara + + * redistribute.c (zebra_redistribute): give ifindex to client. + +1999-08-02 Kunihiro Ishiguro + + * main.c (longopts): -k, --keep_kernel option added. + +1999-07-18 Yasuhiro Ohara + + * rt_socket.c (rtm_write): forgot closing socket bug fixed. + +1999-07-17 Yasuhiro Ohara + + * rib.c (show_ipv6_cmd): if rib is link show interface name. + +1999-07-17 Yasuhiro Ohara + + * rt_socket.c (rtm_write): use sockaddr_dl when null gateway. + +1999-07-16 Yasuhiro Ohara + + * rt_socket.c (rtm_write): ipv6 route table bug fixed. + +1999-07-15 Yasuhiro Ohara + + * zebra.c (zebra_read_ipv6): read link prefix from ospf6 support + +1999-07-15 Yasuhiro Ohara + + * rt_socket.c (kernel_rtm_ipv6): gate treatment bug fixed. + +1999-07-15 Kunihiro Ishiguro + + * if_sysctl.c (ifm_read): Clear sockunion argument before fetching + data. Suggested by "Chris P. Ross" + +1999-07-08 HEO SeonMeyong + + * interface.c (if_tun_add): Add KAME's gif tunnel setting codes. + +1999-06-26 Kunihiro Ishiguro + + * zebra.c (zebra_serv): Only accept loopback address connection. + +1999-06-25 Kunihiro Ishiguro + + * zebra.h (ZEBRA_ROUTE_EXTERNAL): Add zebra messages flags + +1999-06-17 Kunihiro Ishiguro + + * ipforward_proc.c: ipforward_on () and ipforward_off () added. + +1999-06-14 Kunihiro Ishiguro + + * ipforward_proc.c (ipforward_ipv6): Check for IPv6 forwarding + using /proc file system is added. + +1999-06-06 Kunihiro Ishiguro + + * if_ioctl.c (if_get_index): Interface index set bug is fixed by + adding #else at the middle of function. Suggested by David Luyer + . + +1999-05-29 + + * rt_ioctl.c: Comment out #include . + +1999-05-26 Kunihiro Ishiguro + + * zebra.h (ZEBRA_ROUTE_MAX): Add new define for the max value of + the sort of routes. + +1999-05-25 Patrick Koppen + + * rt_netlink.c (netlink_socket): Make netlink socket non-blocking. + (netlink_parse_info): If errno is EWOULDBLOCK then continue to + parse the message. + (netlink_talk): Likewise + +1999-05-17 + + * redistribute.c (zebra_check_addr): Added for loopback address + check. + +1999-05-15 Kunihiro Ishiguro + + * rt_netlink.c (netlink_route_change): Tempolary bypass ipv6 route + change treatment. + + * Makefile.am (noinst_HEADERS): redistribute.h added. + + * redistribute.h: New file. + +1999-05-14 Stephen R. van den Berg + + * zebra.c (show_table): Show all table configuration DEFUN. + (config_table): Config table number DEFUN. + + * rt_netlink.c: Add support for multiple routing table. + + * rib.c (rib_weed_table): New function added for delete all + routes from specified routing table. + + * main.c (signal_init): SIGTERM call sigint. + (sigint): Loggging more better message. + +1999-05-09 Kunihiro Ishiguro + + * rt_netlink.c: Change log () to zlog (). + +1999-05-07 + + * zebra.h (ZEBRA_ROUTE_OSPF6): Added for ospf6d route. + +1999-04-20 Kunihiro Ishiguro + + * interface.c: Add `no ip address' command. + +1999-04-10 Kunihiro Ishiguro + + * rt_netlink.c (kernel_read): Function added for asynchronous + zebra between kernel communication. + +1999-03-25 Kunihiro Ishiguro + + * rtread_sysctl.c (rtm_read): Fix address memcopy overrun bug. + Reported by Achim Patzner . + +1999-03-03 Kunihiro Ishiguro + + * Makefile.am: Install configuration sample with 600 permission. + +1999-03-02 Kunihiro Ishiguro + + * Makefile.am: Add -I.. to INCLUDES. + +1999-02-18 Peter Galbavy + + * syslog support added + +1999-02-17 Peter Galbavy + + * if_sysctl.c (interface_list): allocated memory free when unknown + ifm_type is returned. + + * ioctl.c (if_get_mtu): added SIOCGIFDATA treatment. + +1998-12-15 Magnus Ahltorp + + * interface.c: Header include added. + +1998-12-14 Kunihiro Ishiguro + + * rt.h (kernel_delete_ipv6): change int index to unsigned int index. + +1998-12-13 Kunihiro Ishiguro + + * if_ioctl.c (interface_list_ioctl): interface flag must be + checked before check addresses of the interface. + +1998-12-07 Kunihiro Ishiguro + + * Makefile.am (INCLUDES): add @INCLUDES@ for Linux IPv6. + +1998-10-14 Kunihiro Ishiguro + + * ioctl.c: Linux version before 2.1.0 need interface route setup. + +1998-09-15 HEO SeonMeyong + + * change HYDRANGEA to KAME + +1998-09-01 Kunihiro Ishiguro + + * if_ioctl.c (if_addr_ioctl): set address family for getting + interface's address. + (if_get_index): silently return when can't get interface's index. + +1998-08-17 Kunihiro Ishiguro + + * main.c (main): batch mode option '-b' added. + +1998-08-16 Kunihiro Ishiguro + + * ioctl.c (if_set_prefix): add `ip address IPV4ADDR' command. + * interface.c (shutdown_if): add interface shutdown and no + shutdown command. + +1998-08-12 Kunihiro Ishiguro + + * rib.c (rib_add_ipv6): delete rib_add_in6. + +1998-07-27 Kunihiro Ishiguro + + * main.c: retain flag is added. + +1998-07-08 Kunihiro Ishiguro + + * rtable.[ch]: merged with rib.[ch] + +1998-07-07 Kunihiro Ishiguro + + * connected.h: renamed from ifa.h. + +1998-06-09 Kunihiro Ishiguro + + * rename if.c to interface.c + * rename ifa.c to connected.c + + * Porting to Debian GNU/Linux 2.0 (hamm). + +1998-06-08 Kunihiro Ishiguro + + * rt_netlink.c: renamed from krt_netlink.c + + * fib.c: deleted. + * rt_kvm.c: deleted. + * rtread_getmsg.c: deleted. + +1998-06-07 Kunihiro Ishiguro + + * if.c (multicast): add multicast flag [un]set fucntion. + +1998-05-19 Yamshita TAKAO + + * rt_socket.c: Modify for compile on Solaris, but dont't work it. + rt_socket.c have some undefined function, so add directive "IMPLEMENT" + +1998-05-18 Yamshita TAKAO + + * zebra.c: Modify for compile on Solaris. + +1998-05-03 Kunihiro Ishiguro + + * main.c: change CONFDIR to SYSCONFDIR. + +1998-05-01 Kunihiro Ishiguro + + * .cvsignore: added. + +1998-04-02 Kunihiro Ishiguro + + * client.c: moves to ../lib. + +1998-03-30 Kunihiro Ishiguro + + * if_ioctl.c (if_get_addr): Change address copy from memcopy() to + structure assignment. + +1998-03-30 URA Hiroshi + + * if_sysctl.c (ifm_interface_add): sdl->sdl_data copy bug fixed. + +1998-02-23 "Hannes R. Boehm" + + * if.c (if_init): add config_exit_cmd and config_help_cmd. + +1998-01-24 Kunihiro Ishiguro + + * rt_ioctl.c (route_ioctl): EPERM treatment added. + +1998-01-05 Kunihiro Ishiguro + + * rt_socket.c (kernel_read): communication port zebra between + kernel is now handled by kernel_read. + +1998-01-02 Kunihiro Ishiguro + + * main.c (main): zebra [-P port] can specify vty port number. + +1997-12-25 Kunihiro Ishiguro + + * zebra.c: change select will be block. + +1997-12-04 Kunihiro Ishiguro + + * add static route treatment. + +1997-11-25 Kunihiro Ishiguro + + * rt_netlink.c: add netlink support over GNU/Linux system. + +1997-11-23 Kunihiro Ishiguro + + * all inet_addr is changed to inet_aton. + + * zebra.c (ip_route): add ip route command for static routes. + +1997-11-20 Kunihiro Ishiguro + + * if.c (if_flag_dump): Linux port of if_flag_dump and _vty. + +1997-11-19 Kunihiro Ishiguro + + * if.c: add interface command. + +1997-11-18 Kunihiro Ishiguro + + * ipforward_proc.c : Now works on Linux. + +1997-10-25 Kunihiro Ishiguro + + * command.c : add completion feature. + +1997-10-18 Kunihiro Ishiguro + + * vty.c (vty_command): add vty interface. + +1997-10-13 Kunihiro Ishiguro + + * zebra.c: add verbose mode. + +1997-10-12 SonMyong Ho + + * Hydrangea for FreeBSD supported + * in.h: add some prototype. + +1997-10-11 Kunihiro Ishiguro + + * rt_socket.c and rtread.c completely rewritten. + +1997-10-05 Kunihiro Ishiguro + + * rt_socket.c: rename kernel_sock to routing_socket + +1997-10-04 Kunihiro Ishiguro + + * if.c (if_new): interface structure change from linklist to vector. + +1997-10-03 Kunihiro Ishiguro + + * vector.c (vector_init): create vector related function + +1997-09-25 Kunihiro Ishiguro + + * Makefile.in: add tags target + + * start IPv6 support for INRIA FreeBSD. + diff --git a/zebra/GNOME-PRODUCT-ZEBRA-MIB b/zebra/GNOME-PRODUCT-ZEBRA-MIB new file mode 100644 index 0000000..96bcec5 --- /dev/null +++ b/zebra/GNOME-PRODUCT-ZEBRA-MIB @@ -0,0 +1,78 @@ +GNOME-PRODUCT-ZEBRA-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, + OBJECT-IDENTITY + FROM SNMPv2-SMI + gnomeProducts + FROM GNOME-SMI; + +zebra MODULE-IDENTITY + LAST-UPDATED "200004250000Z" + ORGANIZATION "GNOME project" + CONTACT-INFO + "GNU Network Object Model Environment project + + see http://www.gnome.org for contact persons of a particular + area or subproject of GNOME. + + Administrative contact for MIB module: + + Jochen Friedrich + Wingertstr. 70/1 + 68809 Neulussheim + Germany + + email: snmp@gnome.org" + DESCRIPTION + "The product registrations for the various zebra subdeamons. + These registrations are guaranteed to be unique and are used + for SMUX registration by default (if not overridden manually)." + ::= { gnomeProducts 2 } + +zserv OBJECT-IDENTITY + STATUS current + DESCRIPTION + "zserv is part of the zebra project which again is a GNU + endorsed internet routing program. + zserv is the main zebra process which implements routing + entries with the kernel and handles routing updates between + other routing protocols." + ::= { zebra 1 } + +bgpd OBJECT-IDENTITY + STATUS current + DESCRIPTION + "bgpd is part of the zebra project which again is a GNU + endorsed internet routing program." + ::= { zebra 2 } + +ripd OBJECT-IDENTITY + STATUS current + DESCRIPTION + "ripd is part of the zebra project which again is a GNU + endorsed internet routing program." + ::= { zebra 3 } + +ripngd OBJECT-IDENTITY + STATUS current + DESCRIPTION + "ripngd is part of the zebra project which again is a GNU + endorsed internet routing program." + ::= { zebra 4 } + +ospfd OBJECT-IDENTITY + STATUS current + DESCRIPTION + "ospfd is part of the zebra project which again is a GNU + endorsed internet routing program." + ::= { zebra 5 } + +ospf6d OBJECT-IDENTITY + STATUS current + DESCRIPTION + "ospf6d is part of the zebra project which again is a GNU + endorsed internet routing program." + ::= { zebra 6 } + +END diff --git a/zebra/GNOME-SMI b/zebra/GNOME-SMI new file mode 100644 index 0000000..164732b --- /dev/null +++ b/zebra/GNOME-SMI @@ -0,0 +1,53 @@ +GNOME-SMI DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, + OBJECT-IDENTITY, + enterprises + FROM SNMPv2-SMI; + +gnome MODULE-IDENTITY + LAST-UPDATED "9809010000Z" + ORGANIZATION "GNOME project" + CONTACT-INFO + "GNU Network Object Model Environment project + + see http://www.gnome.org for contact persons of a particular + area or subproject of GNOME. + + Administrative contact for MIB module: + + Jochen Friedrich + Wingertstr. 70/1 + 68809 Neulussheim + Germany + + email: snmp@gnome.org" + DESCRIPTION + "The Structure of GNOME." + ::= { enterprises 3317 } -- assigned by IANA + +gnomeProducts OBJECT-IDENTITY + STATUS current + DESCRIPTION + "gnomeProducts is the root OBJECT IDENTIFIER from + which sysObjectID values are assigned." + ::= { gnome 1 } + +gnomeMgmt OBJECT-IDENTITY + STATUS current + DESCRIPTION + "gnomeMgmt defines the subtree for production GNOME related + MIB registrations." + ::= { gnome 2 } + +gnomeTest OBJECT-IDENTITY + STATUS current + DESCRIPTION + "gnomeTest defines the subtree for testing GNOME related + MIB registrations." + ::= { gnome 3 } + +-- more to come if necessary. + +END diff --git a/zebra/Makefile.am b/zebra/Makefile.am new file mode 100644 index 0000000..448eda1 --- /dev/null +++ b/zebra/Makefile.am @@ -0,0 +1,58 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@ +INSTALL_SDATA=@INSTALL@ -m 600 + +LIB_IPV6 = @LIB_IPV6@ + +ipforward = @IPFORWARD@ +if_method = @IF_METHOD@ +if_proc = @IF_PROC@ +rt_method = @RT_METHOD@ +rtread_method = @RTREAD_METHOD@ +kernel_method = @KERNEL_METHOD@ +other_method = @OTHER_METHOD@ + +otherobj = $(ipforward) $(if_method) $(if_proc) $(rt_method) \ + $(rtread_method) $(kernel_method) $(other_method) + +sbin_PROGRAMS = zebra + +zebra_SOURCES = \ + zserv.c main.c interface.c connected.c ioctl.c zebra_rib.c \ + redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \ + irdp_main.c irdp_interface.c irdp_packet.c + +noinst_HEADERS = \ + connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \ + interface.h ipforward.h irdp.h + +zebra_LDADD = ../lib/libzebra.a $(otherobj) $(LIB_IPV6) + +zebra_DEPENDENCIES = $(otherobj) + +sysconf_DATA = zebra.conf.sample + +EXTRA_DIST = $(sysconf_DATA) if_ioctl.c if_netlink.c if_proc.c if_sysctl.c \ + ipforward_aix.c ipforward_ews.c ipforward_proc.c \ + ipforward_solaris.c ipforward_sysctl.c rt_ioctl.c rt_netlink.c \ + rt_socket.c rtread_netlink.c rtread_proc.c rtread_sysctl.c \ + rtread_getmsg.c kernel_socket.c kernel_netlink.c mtu_kvm.c \ + GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB + +#client : client_main.o ../lib/libzebra.a +# $(CC) -g -o client client_main.o ../lib/libzebra.a $(LIBS) $(LIB_IPV6) + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done diff --git a/zebra/Makefile.in b/zebra/Makefile.in new file mode 100644 index 0000000..0d2c782 --- /dev/null +++ b/zebra/Makefile.in @@ -0,0 +1,430 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CPP = @CPP@ +CURSES = @CURSES@ +DEPDIR = @DEPDIR@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LIBPAM = @LIBPAM@ + +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@ +INSTALL_SDATA = @INSTALL@ -m 600 + +ipforward = @IPFORWARD@ +if_method = @IF_METHOD@ +if_proc = @IF_PROC@ +rt_method = @RT_METHOD@ +rtread_method = @RTREAD_METHOD@ +kernel_method = @KERNEL_METHOD@ +other_method = @OTHER_METHOD@ + +otherobj = $(ipforward) $(if_method) $(if_proc) $(rt_method) \ + $(rtread_method) $(kernel_method) $(other_method) + + +sbin_PROGRAMS = zebra + +zebra_SOURCES = \ + zserv.c main.c interface.c connected.c ioctl.c zebra_rib.c \ + redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \ + irdp_main.c irdp_interface.c irdp_packet.c + + +noinst_HEADERS = \ + connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \ + interface.h ipforward.h irdp.h + + +zebra_LDADD = ../lib/libzebra.a $(otherobj) $(LIB_IPV6) + +zebra_DEPENDENCIES = $(otherobj) + +sysconf_DATA = zebra.conf.sample + +EXTRA_DIST = $(sysconf_DATA) if_ioctl.c if_netlink.c if_proc.c if_sysctl.c \ + ipforward_aix.c ipforward_ews.c ipforward_proc.c \ + ipforward_solaris.c ipforward_sysctl.c rt_ioctl.c rt_netlink.c \ + rt_socket.c rtread_netlink.c rtread_proc.c rtread_sysctl.c \ + rtread_getmsg.c kernel_socket.c kernel_netlink.c mtu_kvm.c \ + GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB + +subdir = zebra +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +sbin_PROGRAMS = zebra$(EXEEXT) +PROGRAMS = $(sbin_PROGRAMS) + +am_zebra_OBJECTS = zserv.$(OBJEXT) main.$(OBJEXT) interface.$(OBJEXT) \ + connected.$(OBJEXT) ioctl.$(OBJEXT) zebra_rib.$(OBJEXT) \ + redistribute.$(OBJEXT) debug.$(OBJEXT) rtadv.$(OBJEXT) \ + zebra_snmp.$(OBJEXT) zebra_vty.$(OBJEXT) irdp_main.$(OBJEXT) \ + irdp_interface.$(OBJEXT) irdp_packet.$(OBJEXT) +zebra_OBJECTS = $(am_zebra_OBJECTS) +zebra_LDFLAGS = +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/connected.Po ./$(DEPDIR)/debug.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/interface.Po ./$(DEPDIR)/ioctl.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/irdp_interface.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/irdp_main.Po ./$(DEPDIR)/irdp_packet.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/main.Po ./$(DEPDIR)/redistribute.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/rtadv.Po ./$(DEPDIR)/zebra_rib.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/zebra_snmp.Po ./$(DEPDIR)/zebra_vty.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/zserv.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CFLAGS = @CFLAGS@ +DIST_SOURCES = $(zebra_SOURCES) +DATA = $(sysconf_DATA) + +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in +SOURCES = $(zebra_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign zebra/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) +sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \ + rm -f $(DESTDIR)$(sbindir)/$$f; \ + done + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) +zebra$(EXEEXT): $(zebra_OBJECTS) $(zebra_DEPENDENCIES) + @rm -f zebra$(EXEEXT) + $(LINK) $(zebra_LDFLAGS) $(zebra_OBJECTS) $(zebra_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connected.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioctl.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irdp_interface.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irdp_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irdp_packet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/redistribute.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtadv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_rib.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_snmp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_vty.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zserv.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `cygpath -w $<` +CCDEPMODE = @CCDEPMODE@ +uninstall-info-am: +sysconfDATA_INSTALL = $(INSTALL_DATA) + +uninstall-sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(sysconf_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \ + rm -f $(DESTDIR)$(sysconfdir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(DATA) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-sbinPROGRAMS install-sysconfDATA + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \ + uninstall-sysconfDATA + +.PHONY: GTAGS all all-am check check-am clean clean-generic \ + clean-sbinPROGRAMS distclean distclean-compile distclean-depend \ + distclean-generic distclean-tags distdir dvi dvi-am info \ + info-am install install-am install-data install-data-am \ + install-exec install-exec-am install-info install-info-am \ + install-man install-sbinPROGRAMS install-strip \ + install-sysconfDATA installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic tags uninstall \ + uninstall-am uninstall-info-am uninstall-sbinPROGRAMS \ + uninstall-sysconfDATA + + +#client : client_main.o ../lib/libzebra.a +# $(CC) -g -o client client_main.o ../lib/libzebra.a $(LIBS) $(LIB_IPV6) + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/zebra/connected.c b/zebra/connected.c new file mode 100644 index 0000000..cb43074 --- /dev/null +++ b/zebra/connected.c @@ -0,0 +1,394 @@ +/* + * Address linked list routine. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "linklist.h" +#include "if.h" +#include "table.h" +#include "rib.h" +#include "table.h" +#include "log.h" + +#include "zebra/zserv.h" +#include "zebra/redistribute.h" + +/* If same interface address is already exist... */ +struct connected * +connected_check_ipv4 (struct interface *ifp, struct prefix *p) +{ + struct connected *ifc; + listnode node; + + for (node = listhead (ifp->connected); node; node = nextnode (node)) + { + ifc = getdata (node); + + if (prefix_same (ifc->address, p)) + return ifc; + } + return NULL; +} + +/* Called from if_up(). */ +void +connected_up_ipv4 (struct interface *ifp, struct connected *ifc) +{ + struct prefix_ipv4 p; + struct prefix_ipv4 *addr; + struct prefix_ipv4 *dest; + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + return; + + addr = (struct prefix_ipv4 *) ifc->address; + dest = (struct prefix_ipv4 *) ifc->destination; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = addr->prefixlen; + + /* Point-to-point check. */ + if (if_is_pointopoint (ifp)) + p.prefix = dest->prefix; + else + p.prefix = addr->prefix; + + /* Apply mask to the network. */ + apply_mask_ipv4 (&p); + + /* In case of connected address is 0.0.0.0/0 we treat it tunnel + address. */ + if (prefix_ipv4_any (&p)) + return; + + rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, 0, 0); + + rib_update (); +} + +/* Add connected IPv4 route to the interface. */ +void +connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, + int prefixlen, struct in_addr *broad, char *label) +{ + struct prefix_ipv4 *p; + struct connected *ifc; + struct connected *current; + + /* Make connected structure. */ + ifc = connected_new (); + ifc->ifp = ifp; + ifc->flags = flags; + + /* Allocate new connected address. */ + p = prefix_ipv4_new (); + p->family = AF_INET; + p->prefix = *addr; + p->prefixlen = prefixlen; + ifc->address = (struct prefix *) p; + + /* If there is broadcast or pointopoint address. */ + if (broad) + { + p = prefix_ipv4_new (); + p->family = AF_INET; + p->prefix = *broad; + ifc->destination = (struct prefix *) p; + } + + /* Label of this address. */ + if (label) + ifc->label = strdup (label); + + /* Check same connected route. */ + current = connected_check_ipv4 (ifp, (struct prefix *) ifc->address); + if (current) + { + connected_free (ifc); + ifc = current; + } + else + { + listnode_add (ifp->connected, ifc); + } + + /* Update interface address information to protocol daemon. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + { + SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + zebra_interface_address_add_update (ifp, ifc); + + if (if_is_up(ifp)) + connected_up_ipv4 (ifp, ifc); + } +} + +void +connected_down_ipv4 (struct interface *ifp, struct connected *ifc) +{ + struct prefix_ipv4 p; + struct prefix_ipv4 *addr; + struct prefix_ipv4 *dest; + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + return; + + addr = (struct prefix_ipv4 *)ifc->address; + dest = (struct prefix_ipv4 *)ifc->destination; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp)) + p.prefix = dest->prefix; + else + p.prefix = addr->prefix; + + /* Apply mask to the network. */ + apply_mask_ipv4 (&p); + + /* In case of connected address is 0.0.0.0/0 we treat it tunnel + address. */ + if (prefix_ipv4_any (&p)) + return; + + rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0); + + rib_update (); +} + +/* Delete connected IPv4 route to the interface. */ +void +connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, + int prefixlen, struct in_addr *broad, char *label) +{ + struct prefix_ipv4 p; + struct connected *ifc; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefix = *addr; + p.prefixlen = prefixlen; + + ifc = connected_check_ipv4 (ifp, (struct prefix *) &p); + if (! ifc) + return; + + /* Update interface address information to protocol daemon. */ + if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + { + zebra_interface_address_delete_update (ifp, ifc); + + connected_down_ipv4 (ifp, ifc); + + UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + } + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + { + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + } +} + +#ifdef HAVE_IPV6 +/* If same interface address is already exist... */ +struct connected * +connected_check_ipv6 (struct interface *ifp, struct prefix *p) +{ + struct connected *ifc; + listnode node; + + for (node = listhead (ifp->connected); node; node = nextnode (node)) + { + ifc = getdata (node); + + if (prefix_same (ifc->address, p)) + return ifc; + } + return 0; +} + +void +connected_up_ipv6 (struct interface *ifp, struct connected *ifc) +{ + struct prefix_ipv6 p; + struct prefix_ipv6 *addr; + struct prefix_ipv6 *dest; + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + return; + + addr = (struct prefix_ipv6 *) ifc->address; + dest = (struct prefix_ipv6 *) ifc->destination; + + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp) && dest) + { + if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix)) + p.prefix = addr->prefix; + else + p.prefix = dest->prefix; + } + else + p.prefix = addr->prefix; + + /* Apply mask to the network. */ + apply_mask_ipv6 (&p); + + if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix)) + return; + + rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0); + + rib_update (); +} + +/* Add connected IPv6 route to the interface. */ +void +connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr, + int prefixlen, struct in6_addr *broad) +{ + struct prefix_ipv6 *p; + struct connected *ifc; + struct connected *current; + + /* Make connected structure. */ + ifc = connected_new (); + ifc->ifp = ifp; + + /* Allocate new connected address. */ + p = prefix_ipv6_new (); + p->family = AF_INET6; + IPV6_ADDR_COPY (&p->prefix, addr); + p->prefixlen = prefixlen; + ifc->address = (struct prefix *) p; + + /* If there is broadcast or pointopoint address. */ + if (broad) + { + p = prefix_ipv6_new (); + p->family = AF_INET6; + IPV6_ADDR_COPY (&p->prefix, broad); + ifc->destination = (struct prefix *) p; + } + + current = connected_check_ipv6 (ifp, (struct prefix *) ifc->address); + if (current) + { + connected_free (ifc); + ifc = current; + } + else + { + listnode_add (ifp->connected, ifc); + } + + /* Update interface address information to protocol daemon. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + { + SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + zebra_interface_address_add_update (ifp, ifc); + + if (if_is_up(ifp)) + connected_up_ipv6 (ifp, ifc); + } +} + +void +connected_down_ipv6 (struct interface *ifp, struct connected *ifc) +{ + struct prefix_ipv6 p; + struct prefix_ipv6 *addr; + struct prefix_ipv6 *dest; + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + return; + + addr = (struct prefix_ipv6 *) ifc->address; + dest = (struct prefix_ipv6 *) ifc->destination; + + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = addr->prefixlen; + + if (if_is_pointopoint (ifp) && dest) + { + if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix)) + p.prefix = addr->prefix; + else + p.prefix = dest->prefix; + } + else + p.prefix = addr->prefix; + + apply_mask_ipv6 (&p); + + if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix)) + return; + + rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0); + + rib_update (); +} + +void +connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, + int prefixlen, struct in6_addr *broad) +{ + struct prefix_ipv6 p; + struct connected *ifc; + + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + memcpy (&p.prefix, address, sizeof (struct in6_addr)); + p.prefixlen = prefixlen; + + ifc = connected_check_ipv6 (ifp, (struct prefix *) &p); + if (! ifc) + return; + + /* Update interface address information to protocol daemon. */ + if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + { + zebra_interface_address_delete_update (ifp, ifc); + + connected_down_ipv6 (ifp, ifc); + + UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + } + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + { + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + } +} +#endif /* HAVE_IPV6 */ diff --git a/zebra/connected.h b/zebra/connected.h new file mode 100644 index 0000000..7bf13ba --- /dev/null +++ b/zebra/connected.h @@ -0,0 +1,60 @@ +/* + * Interface's address and mask. + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_CONNECTED_H +#define _ZEBRA_CONNECTED_H + +struct connected * +connected_check_ipv4 (struct interface *ifp, struct prefix *p); + +void +connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, + int prefixlen, struct in_addr *broad, char *label); + +void +connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, + int prefixlen, struct in_addr *broad, char *label); + +void +connected_up_ipv4 (struct interface *, struct connected *); +void +connected_down_ipv4 (struct interface *, struct connected *); + +#ifdef HAVE_IPV6 +struct connected * +connected_check_ipv6 (struct interface *ifp, struct prefix *p); + +void +connected_add_ipv6 (struct interface *ifp, struct in6_addr *address, + int prefixlen, struct in6_addr *broad); +void +connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, + int prefixlen, struct in6_addr *broad); +void +connected_up_ipv6 (struct interface *, struct connected *); + +void +connected_down_ipv6 (struct interface *ifp, struct connected *); + +#endif /* HAVE_IPV6 */ + +#endif /*_ZEBRA_CONNECTED_H */ diff --git a/zebra/debug.c b/zebra/debug.c new file mode 100644 index 0000000..fc99623 --- /dev/null +++ b/zebra/debug.c @@ -0,0 +1,272 @@ +/* + * Zebra debug related function + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "command.h" +#include "debug.h" + +/* For debug statement. */ +unsigned long zebra_debug_event; +unsigned long zebra_debug_packet; +unsigned long zebra_debug_kernel; + +DEFUN (show_debugging_zebra, + show_debugging_zebra_cmd, + "show debugging zebra", + SHOW_STR + "Zebra configuration\n" + "Debugging information\n") +{ + vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE); + + if (IS_ZEBRA_DEBUG_EVENT) + vty_out (vty, " Zebra event debugging is on%s", VTY_NEWLINE); + + if (IS_ZEBRA_DEBUG_PACKET) + { + if (IS_ZEBRA_DEBUG_SEND && IS_ZEBRA_DEBUG_RECV) + { + vty_out (vty, " Zebra packet%s debugging is on%s", + IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + } + else + { + if (IS_ZEBRA_DEBUG_SEND) + vty_out (vty, " Zebra packet send%s debugging is on%s", + IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + else + vty_out (vty, " Zebra packet receive%s debugging is on%s", + IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + } + } + + if (IS_ZEBRA_DEBUG_KERNEL) + vty_out (vty, " Zebra kernel debugging is on%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN (debug_zebra_events, + debug_zebra_events_cmd, + "debug zebra events", + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra events\n") +{ + zebra_debug_event = ZEBRA_DEBUG_EVENT; + return CMD_WARNING; +} + +DEFUN (debug_zebra_packet, + debug_zebra_packet_cmd, + "debug zebra packet", + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra packet\n") +{ + zebra_debug_packet = ZEBRA_DEBUG_PACKET; + zebra_debug_packet |= ZEBRA_DEBUG_SEND; + zebra_debug_packet |= ZEBRA_DEBUG_RECV; + return CMD_SUCCESS; +} + +DEFUN (debug_zebra_packet_direct, + debug_zebra_packet_direct_cmd, + "debug zebra packet (recv|send)", + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n") +{ + zebra_debug_packet = ZEBRA_DEBUG_PACKET; + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + zebra_debug_packet |= ZEBRA_DEBUG_SEND; + if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + zebra_debug_packet |= ZEBRA_DEBUG_RECV; + zebra_debug_packet &= ~ZEBRA_DEBUG_DETAIL; + return CMD_SUCCESS; +} + +DEFUN (debug_zebra_packet_detail, + debug_zebra_packet_detail_cmd, + "debug zebra packet (recv|send) detail", + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n" + "Debug option set detaied information\n") +{ + zebra_debug_packet = ZEBRA_DEBUG_PACKET; + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + zebra_debug_packet |= ZEBRA_DEBUG_SEND; + if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + zebra_debug_packet |= ZEBRA_DEBUG_RECV; + zebra_debug_packet |= ZEBRA_DEBUG_DETAIL; + return CMD_SUCCESS; +} + +DEFUN (debug_zebra_kernel, + debug_zebra_kernel_cmd, + "debug zebra kernel", + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra between kernel interface\n") +{ + zebra_debug_kernel = ZEBRA_DEBUG_KERNEL; + return CMD_SUCCESS; +} + +DEFUN (no_debug_zebra_events, + no_debug_zebra_events_cmd, + "no debug zebra events", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra events\n") +{ + zebra_debug_event = 0; + return CMD_SUCCESS; +} + +DEFUN (no_debug_zebra_packet, + no_debug_zebra_packet_cmd, + "no debug zebra packet", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra packet\n") +{ + zebra_debug_packet = 0; + return CMD_SUCCESS; +} + +DEFUN (no_debug_zebra_packet_direct, + no_debug_zebra_packet_direct_cmd, + "no debug zebra packet (recv|send)", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra packet\n" + "Debug option set for receive packet\n" + "Debug option set for send packet\n") +{ + if (strncmp ("send", argv[0], strlen (argv[0])) == 0) + zebra_debug_packet &= ~ZEBRA_DEBUG_SEND; + if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) + zebra_debug_packet &= ~ZEBRA_DEBUG_RECV; + return CMD_SUCCESS; +} + +DEFUN (no_debug_zebra_kernel, + no_debug_zebra_kernel_cmd, + "no debug zebra kernel", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra between kernel interface\n") +{ + zebra_debug_kernel = 0; + return CMD_SUCCESS; +} + +/* Debug node. */ +struct cmd_node debug_node = +{ + DEBUG_NODE, + "", /* Debug node has no interface. */ + 1 +}; + +int +config_write_debug (struct vty *vty) +{ + int write = 0; + + if (IS_ZEBRA_DEBUG_EVENT) + { + vty_out (vty, "debug zebra events%s", VTY_NEWLINE); + write++; + } + if (IS_ZEBRA_DEBUG_PACKET) + { + if (IS_ZEBRA_DEBUG_SEND && IS_ZEBRA_DEBUG_RECV) + { + vty_out (vty, "debug zebra packet%s%s", + IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + write++; + } + else + { + if (IS_ZEBRA_DEBUG_SEND) + vty_out (vty, "debug zebra packet send%s%s", + IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + else + vty_out (vty, "debug zebra packet recv%s%s", + IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", + VTY_NEWLINE); + write++; + } + } + if (IS_ZEBRA_DEBUG_KERNEL) + { + vty_out (vty, "debug zebra kernel%s", VTY_NEWLINE); + write++; + } + return write; +} + +void +zebra_debug_init () +{ + zebra_debug_event = 0; + zebra_debug_packet = 0; + + install_node (&debug_node, config_write_debug); + + install_element (VIEW_NODE, &show_debugging_zebra_cmd); + + install_element (ENABLE_NODE, &show_debugging_zebra_cmd); + install_element (ENABLE_NODE, &debug_zebra_events_cmd); + install_element (ENABLE_NODE, &debug_zebra_packet_cmd); + install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd); + install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd); + install_element (ENABLE_NODE, &debug_zebra_kernel_cmd); + install_element (ENABLE_NODE, &no_debug_zebra_events_cmd); + install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd); + install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd); + + install_element (CONFIG_NODE, &debug_zebra_events_cmd); + install_element (CONFIG_NODE, &debug_zebra_packet_cmd); + install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd); + install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd); + install_element (CONFIG_NODE, &debug_zebra_kernel_cmd); + install_element (CONFIG_NODE, &no_debug_zebra_events_cmd); + install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd); + install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd); +} diff --git a/zebra/debug.h b/zebra/debug.h new file mode 100644 index 0000000..6eaa957 --- /dev/null +++ b/zebra/debug.h @@ -0,0 +1,52 @@ +/* + * Zebra debug related function + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_DEBUG_H +#define _ZEBRA_DEBUG_H + +/* Debug flags. */ +#define ZEBRA_DEBUG_EVENT 0x01 + +#define ZEBRA_DEBUG_PACKET 0x01 +#define ZEBRA_DEBUG_SEND 0x20 +#define ZEBRA_DEBUG_RECV 0x40 +#define ZEBRA_DEBUG_DETAIL 0x80 + +#define ZEBRA_DEBUG_KERNEL 0x01 + +/* Debug related macro. */ +#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT) + +#define IS_ZEBRA_DEBUG_PACKET (zebra_debug_packet & ZEBRA_DEBUG_PACKET) +#define IS_ZEBRA_DEBUG_SEND (zebra_debug_packet & ZEBRA_DEBUG_SEND) +#define IS_ZEBRA_DEBUG_RECV (zebra_debug_packet & ZEBRA_DEBUG_RECV) +#define IS_ZEBRA_DEBUG_DETAIL (zebra_debug_packet & ZEBRA_DEBUG_DETAIL) + +#define IS_ZEBRA_DEBUG_KERNEL (zebra_debug_kernel & ZEBRA_DEBUG_KERNEL) + +extern unsigned long zebra_debug_event; +extern unsigned long zebra_debug_packet; +extern unsigned long zebra_debug_kernel; + +void zebra_debug_init (); + +#endif /* _ZEBRA_DEBUG_H */ diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c new file mode 100644 index 0000000..46f5301 --- /dev/null +++ b/zebra/if_ioctl.c @@ -0,0 +1,438 @@ +/* + * Interface looking up by ioctl (). + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "sockunion.h" +#include "prefix.h" +#include "ioctl.h" +#include "connected.h" +#include "memory.h" +#include "log.h" + +#include "zebra/interface.h" + +/* Interface looking up using infamous SIOCGIFCONF. */ +int +interface_list_ioctl () +{ + int ret; + int sock; +#define IFNUM_BASE 32 + int ifnum; + struct ifreq *ifreq; + struct ifconf ifconf; + struct interface *ifp; + int n; + int lastlen; + + /* Normally SIOCGIFCONF works with AF_INET socket. */ + sock = socket (AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + { + zlog_warn ("Can't make AF_INET socket stream: %s", strerror (errno)); + return -1; + } + + /* Set initial ifreq count. This will be double when SIOCGIFCONF + fail. Solaris has SIOCGIFNUM. */ +#ifdef SIOCGIFNUM + ret = ioctl (sock, SIOCGIFNUM, &ifnum); + if (ret < 0) + ifnum = IFNUM_BASE; + else + ifnum++; +#else + ifnum = IFNUM_BASE; +#endif /* SIOCGIFNUM */ + + ifconf.ifc_buf = NULL; + + lastlen = 0; + /* Loop until SIOCGIFCONF success. */ + for (;;) + { + ifconf.ifc_len = sizeof (struct ifreq) * ifnum; + ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len); + + ret = ioctl(sock, SIOCGIFCONF, &ifconf); + + if (ret < 0) + { + zlog_warn ("SIOCGIFCONF: %s", strerror(errno)); + goto end; + } + /* Repeatedly get info til buffer fails to grow. */ + if (ifconf.ifc_len > lastlen) + { + lastlen = ifconf.ifc_len; + ifnum += 10; + continue; + } + /* Success. */ + break; + } + + /* Allocate interface. */ + ifreq = ifconf.ifc_req; + +#ifdef OPEN_BSD + for (n = 0; n < ifconf.ifc_len; ) + { + int size; + + ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n); + ifp = if_get_by_name (ifreq->ifr_name); + if_add_update (ifp); + size = ifreq->ifr_addr.sa_len; + if (size < sizeof (ifreq->ifr_addr)) + size = sizeof (ifreq->ifr_addr); + size += sizeof (ifreq->ifr_name); + n += size; + } +#else + for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) + { + ifp = if_get_by_name (ifreq->ifr_name); + if_add_update (ifp); + ifreq++; + } +#endif /* OPEN_BSD */ + + end: + close (sock); + XFREE (MTYPE_TMP, ifconf.ifc_buf); + + return ret; +} + +/* Get interface's index by ioctl. */ +int +if_get_index (struct interface *ifp) +{ + static int if_fake_index = 1; + +#ifdef HAVE_BROKEN_ALIASES + /* Linux 2.2.X does not provide individual interface index for aliases. */ + ifp->ifindex = if_fake_index++; + return ifp->ifindex; +#else +#ifdef SIOCGIFINDEX + int ret; + struct ifreq ifreq; + + ifreq_set_name (&ifreq, ifp); + + ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq); + if (ret < 0) + { + /* Linux 2.0.X does not have interface index. */ + ifp->ifindex = if_fake_index++; + return ifp->ifindex; + } + + /* OK we got interface index. */ +#ifdef ifr_ifindex + ifp->ifindex = ifreq.ifr_ifindex; +#else + ifp->ifindex = ifreq.ifr_index; +#endif + return ifp->ifindex; + +#else + ifp->ifindex = if_fake_index++; + return ifp->ifindex; +#endif /* SIOCGIFINDEX */ +#endif /* HAVE_BROKEN_ALIASES */ +} + +#ifdef SIOCGIFHWADDR +int +if_get_hwaddr (struct interface *ifp) +{ + int ret; + struct ifreq ifreq; + int i; + + strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); + ifreq.ifr_addr.sa_family = AF_INET; + + /* Fetch Hardware address if available. */ + ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq); + if (ret < 0) + ifp->hw_addr_len = 0; + else + { + memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6); + + for (i = 0; i < 6; i++) + if (ifp->hw_addr[i] != 0) + break; + + if (i == 6) + ifp->hw_addr_len = 0; + else + ifp->hw_addr_len = 6; + } + return 0; +} +#endif /* SIOCGIFHWADDR */ + +#ifdef HAVE_GETIFADDRS +#include + +int +if_getaddrs () +{ + int ret; + struct ifaddrs *ifap; + struct ifaddrs *ifapfree; + struct interface *ifp; + int prefixlen; + + ret = getifaddrs (&ifap); + if (ret != 0) + { + zlog_err ("getifaddrs(): %s", strerror (errno)); + return -1; + } + + for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) + { + ifp = if_lookup_by_name (ifap->ifa_name); + if (ifp == NULL) + { + zlog_err ("if_getaddrs(): Can't lookup interface %s\n", + ifap->ifa_name); + continue; + } + + if (ifap->ifa_addr->sa_family == AF_INET) + { + struct sockaddr_in *addr; + struct sockaddr_in *mask; + struct sockaddr_in *dest; + struct in_addr *dest_pnt; + + addr = (struct sockaddr_in *) ifap->ifa_addr; + mask = (struct sockaddr_in *) ifap->ifa_netmask; + prefixlen = ip_masklen (mask->sin_addr); + + dest_pnt = NULL; + + if (ifap->ifa_flags & IFF_POINTOPOINT) + { + dest = (struct sockaddr_in *) ifap->ifa_dstaddr; + dest_pnt = &dest->sin_addr; + } + + if (ifap->ifa_flags & IFF_BROADCAST) + { + dest = (struct sockaddr_in *) ifap->ifa_broadaddr; + dest_pnt = &dest->sin_addr; + } + + connected_add_ipv4 (ifp, 0, &addr->sin_addr, + prefixlen, dest_pnt, NULL); + } +#ifdef HAVE_IPV6 + if (ifap->ifa_addr->sa_family == AF_INET6) + { + struct sockaddr_in6 *addr; + struct sockaddr_in6 *mask; + struct sockaddr_in6 *dest; + struct in6_addr *dest_pnt; + + addr = (struct sockaddr_in6 *) ifap->ifa_addr; + mask = (struct sockaddr_in6 *) ifap->ifa_netmask; + prefixlen = ip6_masklen (mask->sin6_addr); + + dest_pnt = NULL; + + if (ifap->ifa_flags & IFF_POINTOPOINT) + { + if (ifap->ifa_dstaddr) + { + dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr; + dest_pnt = &dest->sin6_addr; + } + } + + if (ifap->ifa_flags & IFF_BROADCAST) + { + if (ifap->ifa_broadaddr) + { + dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr; + dest_pnt = &dest->sin6_addr; + } + } + + connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, dest_pnt); + } +#endif /* HAVE_IPV6 */ + } + + freeifaddrs (ifapfree); + + return 0; +} +#else /* HAVE_GETIFADDRS */ +/* Interface address lookup by ioctl. This function only looks up + IPv4 address. */ +int +if_get_addr (struct interface *ifp) +{ + int ret; + struct ifreq ifreq; + struct sockaddr_in addr; + struct sockaddr_in mask; + struct sockaddr_in dest; + struct in_addr *dest_pnt; + u_char prefixlen; + + /* Interface's name and address family. */ + strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); + ifreq.ifr_addr.sa_family = AF_INET; + + /* Interface's address. */ + ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq); + if (ret < 0) + { + if (errno != EADDRNOTAVAIL) + { + zlog_warn ("SIOCGIFADDR fail: %s", strerror (errno)); + return ret; + } + return 0; + } + memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); + + /* Interface's network mask. */ + ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq); + if (ret < 0) + { + if (errno != EADDRNOTAVAIL) + { + zlog_warn ("SIOCGIFNETMASK fail: %s", strerror (errno)); + return ret; + } + return 0; + } +#ifdef ifr_netmask + memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in)); +#else + memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); +#endif /* ifr_netmask */ + prefixlen = ip_masklen (mask.sin_addr); + + /* Point to point or borad cast address pointer init. */ + dest_pnt = NULL; + + if (ifp->flags & IFF_POINTOPOINT) + { + ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq); + if (ret < 0) + { + if (errno != EADDRNOTAVAIL) + { + zlog_warn ("SIOCGIFDSTADDR fail: %s", strerror (errno)); + return ret; + } + return 0; + } + memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in)); + dest_pnt = &dest.sin_addr; + } + if (ifp->flags & IFF_BROADCAST) + { + ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq); + if (ret < 0) + { + if (errno != EADDRNOTAVAIL) + { + zlog_warn ("SIOCGIFBRDADDR fail: %s", strerror (errno)); + return ret; + } + return 0; + } + memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in)); + dest_pnt = &dest.sin_addr; + } + + + /* Set address to the interface. */ + connected_add_ipv4 (ifp, 0, &addr.sin_addr, prefixlen, dest_pnt, NULL); + + return 0; +} +#endif /* HAVE_GETIFADDRS */ + +/* Fetch interface information via ioctl(). */ +static void +interface_info_ioctl () +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; node = nextnode (node)) + { + ifp = getdata (node); + + if_get_index (ifp); +#ifdef SIOCGIFHWADDR + if_get_hwaddr (ifp); +#endif /* SIOCGIFHWADDR */ + if_get_flags (ifp); +#ifndef HAVE_GETIFADDRS + if_get_addr (ifp); +#endif /* ! HAVE_GETIFADDRS */ + if_get_mtu (ifp); + if_get_metric (ifp); + } +} + +/* Lookup all interface information. */ +void +interface_list () +{ + /* Linux can do both proc & ioctl, ioctl is the only way to get + interface aliases in 2.2 series kernels. */ +#ifdef HAVE_PROC_NET_DEV + interface_list_proc (); +#endif /* HAVE_PROC_NET_DEV */ + interface_list_ioctl (); + + /* After listing is done, get index, address, flags and other + interface's information. */ + interface_info_ioctl (); + +#ifdef HAVE_GETIFADDRS + if_getaddrs (); +#endif /* HAVE_GETIFADDRS */ + +#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6) + /* Linux provides interface's IPv6 address via + /proc/net/if_inet6. */ + ifaddr_proc_ipv6 (); +#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */ +} diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c new file mode 100644 index 0000000..c9c1476 --- /dev/null +++ b/zebra/if_netlink.c @@ -0,0 +1,33 @@ +/* + * Interface looking up by netlink. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +/* Extern from rt_netlink.c */ +void interface_lookup_netlink (); + +/* Interface information read by netlink. */ +void +interface_list () +{ + interface_lookup_netlink (); +} diff --git a/zebra/if_proc.c b/zebra/if_proc.c new file mode 100644 index 0000000..6c47d43 --- /dev/null +++ b/zebra/if_proc.c @@ -0,0 +1,247 @@ +/* Interface name and statistics get function using proc file system + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "prefix.h" +#include "log.h" + +#include "zebra/ioctl.h" +#include "zebra/connected.h" +#include "zebra/interface.h" + +/* Proc filesystem one line buffer. */ +#define PROCBUFSIZ 1024 + +/* Path to device proc file system. */ +#ifndef _PATH_PROC_NET_DEV +#define _PATH_PROC_NET_DEV "/proc/net/dev" +#endif /* _PATH_PROC_NET_DEV */ + +/* Return statistics data pointer. */ +static char * +interface_name_cut (char *buf, char **name) +{ + char *stat; + + /* Skip white space. Line will include header spaces. */ + while (*buf == ' ') + buf++; + *name = buf; + + /* Cut interface name. */ + stat = strrchr (buf, ':'); + *stat++ = '\0'; + + return stat; +} + +/* Fetch each statistics field. */ +static int +ifstat_dev_fields (int version, char *buf, struct interface *ifp) +{ + switch (version) + { + case 3: + sscanf(buf, + "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld", + &ifp->stats.rx_bytes, + &ifp->stats.rx_packets, + &ifp->stats.rx_errors, + &ifp->stats.rx_dropped, + &ifp->stats.rx_fifo_errors, + &ifp->stats.rx_frame_errors, + &ifp->stats.rx_compressed, + &ifp->stats.rx_multicast, + + &ifp->stats.tx_bytes, + &ifp->stats.tx_packets, + &ifp->stats.tx_errors, + &ifp->stats.tx_dropped, + &ifp->stats.tx_fifo_errors, + &ifp->stats.collisions, + &ifp->stats.tx_carrier_errors, + &ifp->stats.tx_compressed); + break; + case 2: + sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld", + &ifp->stats.rx_bytes, + &ifp->stats.rx_packets, + &ifp->stats.rx_errors, + &ifp->stats.rx_dropped, + &ifp->stats.rx_fifo_errors, + &ifp->stats.rx_frame_errors, + + &ifp->stats.tx_bytes, + &ifp->stats.tx_packets, + &ifp->stats.tx_errors, + &ifp->stats.tx_dropped, + &ifp->stats.tx_fifo_errors, + &ifp->stats.collisions, + &ifp->stats.tx_carrier_errors); + ifp->stats.rx_multicast = 0; + break; + case 1: + sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld", + &ifp->stats.rx_packets, + &ifp->stats.rx_errors, + &ifp->stats.rx_dropped, + &ifp->stats.rx_fifo_errors, + &ifp->stats.rx_frame_errors, + + &ifp->stats.tx_packets, + &ifp->stats.tx_errors, + &ifp->stats.tx_dropped, + &ifp->stats.tx_fifo_errors, + &ifp->stats.collisions, + &ifp->stats.tx_carrier_errors); + ifp->stats.rx_bytes = 0; + ifp->stats.tx_bytes = 0; + ifp->stats.rx_multicast = 0; + break; + } + return 0; +} + +/* Update interface's statistics. */ +int +ifstat_update_proc () +{ + FILE *fp; + char buf[PROCBUFSIZ]; + int version; + struct interface *ifp; + char *stat; + char *name; + + /* Open /proc/net/dev. */ + fp = fopen (_PATH_PROC_NET_DEV, "r"); + if (fp == NULL) + { + zlog_warn ("Can't open proc file %s: %s", + _PATH_PROC_NET_DEV, strerror (errno)); + return -1; + } + + /* Drop header lines. */ + fgets (buf, PROCBUFSIZ, fp); + fgets (buf, PROCBUFSIZ, fp); + + /* To detect proc format veresion, parse second line. */ + if (strstr (buf, "compressed")) + version = 3; + else if (strstr (buf, "bytes")) + version = 2; + else + version = 1; + + /* Update each interface's statistics. */ + while (fgets (buf, PROCBUFSIZ, fp) != NULL) + { + stat = interface_name_cut (buf, &name); + ifp = if_get_by_name (name); + ifstat_dev_fields (version, stat, ifp); + } + fclose(fp); + return 0; +} + +/* Interface structure allocation by proc filesystem. */ +int +interface_list_proc () +{ + FILE *fp; + char buf[PROCBUFSIZ]; + struct interface *ifp; + char *name; + + /* Open /proc/net/dev. */ + fp = fopen (_PATH_PROC_NET_DEV, "r"); + if (fp == NULL) + { + zlog_warn ("Can't open proc file %s: %s", + _PATH_PROC_NET_DEV, strerror (errno)); + return -1; + } + + /* Drop header lines. */ + fgets (buf, PROCBUFSIZ, fp); + fgets (buf, PROCBUFSIZ, fp); + + /* Only allocate interface structure. Other jobs will be done in + if_ioctl.c. */ + while (fgets (buf, PROCBUFSIZ, fp) != NULL) + { + interface_name_cut (buf, &name); + ifp = if_get_by_name (name); + if_add_update (ifp); + } + fclose(fp); + return 0; +} + +#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6) + +#ifndef _PATH_PROC_NET_IF_INET6 +#define _PATH_PROC_NET_IF_INET6 "/proc/net/if_inet6" +#endif /* _PATH_PROC_NET_IF_INET6 */ + +int +ifaddr_proc_ipv6 () +{ + FILE *fp; + char buf[PROCBUFSIZ]; + int n; + char addr[33]; + char ifname[20]; + int ifindex, plen, scope, status; + struct interface *ifp; + struct prefix_ipv6 p; + + /* Open proc file system. */ + fp = fopen (_PATH_PROC_NET_IF_INET6, "r"); + if (fp == NULL) + { + zlog_warn ("Can't open proc file %s: %s", + _PATH_PROC_NET_IF_INET6, strerror (errno)); + return -1; + } + + /* Get interface's IPv6 address. */ + while (fgets (buf, PROCBUFSIZ, fp) != NULL) + { + n = sscanf (buf, "%32s %02x %02x %02x %02x %20s", + addr, &ifindex, &plen, &scope, &status, ifname); + if (n != 6) + continue; + + ifp = if_get_by_name (ifname); + + /* Fetch interface's IPv6 address. */ + str2in6_addr (addr, &p.prefix); + p.prefixlen = plen; + + connected_add_ipv6 (ifp, &p.prefix, p.prefixlen, NULL); + } + return 0; +} +#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */ diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c new file mode 100644 index 0000000..1441dfc --- /dev/null +++ b/zebra/if_sysctl.c @@ -0,0 +1,148 @@ +/* + * Get interface's address and mask information by sysctl() function. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "sockunion.h" +#include "prefix.h" +#include "connected.h" +#include "memory.h" +#include "ioctl.h" +#include "log.h" + +int +ifstat_update_sysctl () +{ + caddr_t ref, buf, end; + size_t bufsiz; + struct if_msghdr *ifm; + struct interface *ifp; + +#define MIBSIZ 6 + int mib[MIBSIZ] = + { + CTL_NET, + PF_ROUTE, + 0, + 0, /* AF_INET & AF_INET6 */ + NET_RT_IFLIST, + 0 + }; + + /* Query buffer size. */ + if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) + { + zlog_warn ("sysctl() error by %s", strerror (errno)); + return -1; + } + + /* We free this memory at the end of this function. */ + ref = buf = XMALLOC (MTYPE_TMP, bufsiz); + + /* Fetch interface informations into allocated buffer. */ + if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) + { + zlog (NULL, LOG_WARNING, "sysctl error by %s", strerror (errno)); + return -1; + } + + /* Parse both interfaces and addresses. */ + for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) + { + ifm = (struct if_msghdr *) buf; + if (ifm->ifm_type == RTM_IFINFO) + { + ifp = if_lookup_by_index (ifm->ifm_index); + if (ifp) + ifp->stats = ifm->ifm_data; + } + } + + /* Free sysctl buffer. */ + XFREE (MTYPE_TMP, ref); + + return 0; +} + +/* Interface listing up function using sysctl(). */ +void +interface_list () +{ + caddr_t ref, buf, end; + size_t bufsiz; + struct if_msghdr *ifm; + int ifm_read (struct if_msghdr *); + int ifam_read (struct ifa_msghdr *); + +#define MIBSIZ 6 + int mib[MIBSIZ] = + { + CTL_NET, + PF_ROUTE, + 0, + 0, /* AF_INET & AF_INET6 */ + NET_RT_IFLIST, + 0 + }; + + /* Query buffer size. */ + if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) + { + zlog (NULL, LOG_WARNING, "sysctl() error by %s", strerror (errno)); + return; + } + + /* We free this memory at the end of this function. */ + ref = buf = XMALLOC (MTYPE_TMP, bufsiz); + + /* Fetch interface informations into allocated buffer. */ + if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) + { + zlog (NULL, LOG_WARNING, "sysctl error by %s", strerror (errno)); + return; + } + + /* Parse both interfaces and addresses. */ + for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) + { + ifm = (struct if_msghdr *) buf; + + switch (ifm->ifm_type) + { + case RTM_IFINFO: + ifm_read (ifm); + break; + case RTM_NEWADDR: + ifam_read ((struct ifa_msghdr *) ifm); + break; + default: + zlog_info ("interfaces_list(): unexpected message type"); + XFREE (MTYPE_TMP, ref); + return; + break; + } + } + + /* Free sysctl buffer. */ + XFREE (MTYPE_TMP, ref); +} diff --git a/zebra/interface.c b/zebra/interface.c new file mode 100644 index 0000000..91edab0 --- /dev/null +++ b/zebra/interface.c @@ -0,0 +1,1391 @@ +/* + * Interface function. + * Copyright (C) 1997, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "vty.h" +#include "sockunion.h" +#include "prefix.h" +#include "command.h" +#include "memory.h" +#include "ioctl.h" +#include "connected.h" +#include "log.h" +#include "zclient.h" + +#include "zebra/interface.h" +#include "zebra/rtadv.h" +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/debug.h" + +/* Allocate a new internal interface index + * This works done from the top so that %d macros + * print a - sign! + */ +static unsigned int +if_new_intern_ifindex (void) +{ + /* Start here so that first one assigned is 0xFFFFFFFF */ + static unsigned int ifindex = IFINDEX_INTERNBASE + 1; + + for (;;) + { + ifindex--; + if ( ifindex <= IFINDEX_INTERNBASE ) + ifindex = 0xFFFFFFFF; + + if (if_lookup_by_index(ifindex) == NULL) + return ifindex; + } +} + +/* Called when new interface is added. */ +int +if_zebra_new_hook (struct interface *ifp) +{ + struct zebra_if *zebra_if; + + zebra_if = XMALLOC (MTYPE_TMP, sizeof (struct zebra_if)); + memset (zebra_if, 0, sizeof (struct zebra_if)); + + zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC; + zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_UNSPEC; + +#ifdef RTADV + { + /* Set default router advertise values. */ + struct rtadvconf *rtadv; + + rtadv = &zebra_if->rtadv; + + rtadv->AdvSendAdvertisements = 0; + rtadv->MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL; + rtadv->MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL; + rtadv->AdvIntervalTimer = 0; + rtadv->AdvManagedFlag = 0; + rtadv->AdvOtherConfigFlag = 0; + rtadv->AdvLinkMTU = 0; + rtadv->AdvReachableTime = 0; + rtadv->AdvRetransTimer = 0; + rtadv->AdvCurHopLimit = 0; + rtadv->AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME; + + rtadv->AdvPrefixList = list_new (); + } +#endif /* RTADV */ + + ifp->info = zebra_if; + return 0; +} + +/* Called when interface is deleted. */ +int +if_zebra_delete_hook (struct interface *ifp) +{ + if (ifp->info) + XFREE (MTYPE_TMP, ifp->info); + return 0; +} + +/* Wake up configured address if it is not in current kernel + address. */ +void +if_addr_wakeup (struct interface *ifp) +{ + struct listnode *node; + struct connected *ifc; + struct prefix *p; + int ret; + + for (node = listhead (ifp->connected); node; nextnode (node)) + { + ifc = getdata (node); + p = ifc->address; + + if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED) + && ! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + { + /* Address check. */ + if (p->family == AF_INET) + { + if (! if_is_up (ifp)) + { + if_set_flags (ifp, IFF_UP | IFF_RUNNING); + if_refresh (ifp); + } + + ret = if_set_prefix (ifp, ifc); + if (ret < 0) + { + zlog_warn ("Can't set interface's address: %s", + strerror(errno)); + continue; + } + SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + zebra_interface_address_add_update (ifp, ifc); + + if (if_is_up(ifp)) + connected_up_ipv4 (ifp, ifc); + } +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + { + if (! if_is_up (ifp)) + { + if_set_flags (ifp, IFF_UP | IFF_RUNNING); + if_refresh (ifp); + } + + ret = if_prefix_add_ipv6 (ifp, ifc); + if (ret < 0) + { + zlog_warn ("Can't set interface's address: %s", + strerror(errno)); + continue; + } + SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + zebra_interface_address_add_update (ifp, ifc); + + if (if_is_up(ifp)) + connected_up_ipv6 (ifp, ifc); + } +#endif /* HAVE_IPV6 */ + } + } +} + +/* Handle interface addition */ +void +if_add_update (struct interface *ifp) +{ + zebra_interface_add_update (ifp); + + if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + SET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); + + if_addr_wakeup (ifp); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("interface %s index %d becomes active.", + ifp->name, ifp->ifindex); + } + else + { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("interface %s index %d is added.", ifp->name, ifp->ifindex); + } +} + +/* Handle an interface delete event */ +void +if_delete_update (struct interface *ifp) +{ + struct listnode *node; + struct listnode *next; + struct connected *ifc; + struct prefix *p; + + if (if_is_up(ifp)) + { + zlog_err ("interface %s index %d is still up while being deleted.", + ifp->name, ifp->ifindex); + return; + } + + /* Mark interface as inactive */ + UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("interface %s index %d is now inactive.", + ifp->name, ifp->ifindex); + + /* Delete connected routes from the kernel. */ + if (ifp->connected) + { + for (node = listhead (ifp->connected); node; node = next) + { + next = node->next; + ifc = getdata (node); + p = ifc->address; + + if (p->family == AF_INET) + connected_down_ipv4 (ifp, ifc); +#ifdef HAVE_IPV6 + else if (p->family == AF_INET6) + connected_down_ipv6 (ifp, ifc); +#endif /* HAVE_IPV6 */ + + zebra_interface_address_delete_update (ifp, ifc); + + UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + { + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + } + } + } + zebra_interface_delete_update (ifp); +} + +/* Interface is up. */ +void +if_up (struct interface *ifp) +{ + listnode node; + listnode next; + struct connected *ifc; + struct prefix *p; + + /* Notify the protocol daemons. */ + zebra_interface_up_update (ifp); + + /* Install connected routes to the kernel. */ + if (ifp->connected) + { + for (node = listhead (ifp->connected); node; node = next) + { + next = node->next; + ifc = getdata (node); + p = ifc->address; + + if (p->family == AF_INET) + connected_up_ipv4 (ifp, ifc); +#ifdef HAVE_IPV6 + else if (p->family == AF_INET6) + connected_up_ipv6 (ifp, ifc); +#endif /* HAVE_IPV6 */ + } + } + + /* Examine all static routes. */ + rib_update (); +} + +/* Interface goes down. We have to manage different behavior of based + OS. */ +void +if_down (struct interface *ifp) +{ + listnode node; + listnode next; + struct connected *ifc; + struct prefix *p; + + /* Notify to the protocol daemons. */ + zebra_interface_down_update (ifp); + + /* Delete connected routes from the kernel. */ + if (ifp->connected) + { + for (node = listhead (ifp->connected); node; node = next) + { + next = node->next; + ifc = getdata (node); + p = ifc->address; + + if (p->family == AF_INET) + connected_down_ipv4 (ifp, ifc); +#ifdef HAVE_IPV6 + else if (p->family == AF_INET6) + connected_down_ipv6 (ifp, ifc); +#endif /* HAVE_IPV6 */ + } + } + + /* Examine all static routes which direct to the interface. */ + rib_update (); +} + +void +if_refresh (struct interface *ifp) +{ + if (if_is_up (ifp)) + { + if_get_flags (ifp); + if (! if_is_up (ifp)) + if_down (ifp); + } + else + { + if_get_flags (ifp); + if (if_is_up (ifp)) + if_up (ifp); + } +} + +/* Printout flag information into vty */ +void +if_flag_dump_vty (struct vty *vty, unsigned long flag) +{ + int separator = 0; + +#define IFF_OUT_VTY(X, Y) \ + if ((X) && (flag & (X))) \ + { \ + if (separator) \ + vty_out (vty, ","); \ + else \ + separator = 1; \ + vty_out (vty, Y); \ + } + + vty_out (vty, "<"); + IFF_OUT_VTY (IFF_UP, "UP"); + IFF_OUT_VTY (IFF_BROADCAST, "BROADCAST"); + IFF_OUT_VTY (IFF_DEBUG, "DEBUG"); + IFF_OUT_VTY (IFF_LOOPBACK, "LOOPBACK"); + IFF_OUT_VTY (IFF_POINTOPOINT, "POINTOPOINT"); + IFF_OUT_VTY (IFF_NOTRAILERS, "NOTRAILERS"); + IFF_OUT_VTY (IFF_RUNNING, "RUNNING"); + IFF_OUT_VTY (IFF_NOARP, "NOARP"); + IFF_OUT_VTY (IFF_PROMISC, "PROMISC"); + IFF_OUT_VTY (IFF_ALLMULTI, "ALLMULTI"); + IFF_OUT_VTY (IFF_OACTIVE, "OACTIVE"); + IFF_OUT_VTY (IFF_SIMPLEX, "SIMPLEX"); + IFF_OUT_VTY (IFF_LINK0, "LINK0"); + IFF_OUT_VTY (IFF_LINK1, "LINK1"); + IFF_OUT_VTY (IFF_LINK2, "LINK2"); + IFF_OUT_VTY (IFF_MULTICAST, "MULTICAST"); + vty_out (vty, ">"); +} + +/* Output prefix string to vty. */ +int +prefix_vty_out (struct vty *vty, struct prefix *p) +{ + char str[INET6_ADDRSTRLEN]; + + inet_ntop (p->family, &p->u.prefix, str, sizeof (str)); + vty_out (vty, "%s", str); + return strlen (str); +} + +/* Dump if address information to vty. */ +void +connected_dump_vty (struct vty *vty, struct connected *connected) +{ + struct prefix *p; + struct interface *ifp; + + /* Set interface pointer. */ + ifp = connected->ifp; + + /* Print interface address. */ + p = connected->address; + vty_out (vty, " %s ", prefix_family_str (p)); + prefix_vty_out (vty, p); + vty_out (vty, "/%d", p->prefixlen); + + /* If there is destination address, print it. */ + p = connected->destination; + if (p) + { + if (p->family == AF_INET) + if (ifp->flags & IFF_BROADCAST) + { + vty_out (vty, " broadcast "); + prefix_vty_out (vty, p); + } + + if (ifp->flags & IFF_POINTOPOINT) + { + vty_out (vty, " pointopoint "); + prefix_vty_out (vty, p); + } + } + + if (CHECK_FLAG (connected->flags, ZEBRA_IFA_SECONDARY)) + vty_out (vty, " secondary"); + + if (connected->label) + vty_out (vty, " %s", connected->label); + + vty_out (vty, "%s", VTY_NEWLINE); +} + +#ifdef RTADV +/* Dump interface ND information to vty. */ +void +nd_dump_vty (struct vty *vty, struct interface *ifp) +{ + struct zebra_if *zif; + struct rtadvconf *rtadv; + + zif = (struct zebra_if *) ifp->info; + rtadv = &zif->rtadv; + + if (rtadv->AdvSendAdvertisements) + { + vty_out (vty, " ND advertised reachable time is %d milliseconds%s", + rtadv->AdvReachableTime, VTY_NEWLINE); + vty_out (vty, " ND advertised retransmit interval is %d milliseconds%s", + rtadv->AdvRetransTimer, VTY_NEWLINE); + vty_out (vty, " ND router advertisements are sent every %d seconds%s", + rtadv->MaxRtrAdvInterval, VTY_NEWLINE); + vty_out (vty, " ND router advertisements live for %d seconds%s", + rtadv->AdvDefaultLifetime, VTY_NEWLINE); + if (rtadv->AdvManagedFlag) + vty_out (vty, " Hosts use DHCP to obtain routable addresses.%s", + VTY_NEWLINE); + else + vty_out (vty, " Hosts use stateless autoconfig for addresses.%s", + VTY_NEWLINE); + } +} +#endif /* RTADV */ + +/* Interface's information print out to vty interface. */ +void +if_dump_vty (struct vty *vty, struct interface *ifp) +{ +#ifdef HAVE_SOCKADDR_DL + struct sockaddr_dl *sdl; +#endif /* HAVE_SOCKADDR_DL */ + struct connected *connected; + listnode node; + + vty_out (vty, "Interface %s%s", ifp->name, + VTY_NEWLINE); + if (ifp->desc) + vty_out (vty, " Description: %s%s", ifp->desc, + VTY_NEWLINE); + if (ifp->ifindex <= 0) + { + vty_out(vty, " index %d pseudo interface%s", ifp->ifindex, VTY_NEWLINE); + return; + } + else if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + vty_out(vty, " index %d inactive interface%s", + ifp->ifindex, + VTY_NEWLINE); + return; + } + + vty_out (vty, " index %d metric %d mtu %d ", + ifp->ifindex, ifp->metric, ifp->mtu); + if_flag_dump_vty (vty, ifp->flags); + vty_out (vty, "%s", VTY_NEWLINE); + + /* Hardware address. */ +#ifdef HAVE_SOCKADDR_DL + sdl = &ifp->sdl; + if (sdl != NULL && sdl->sdl_alen != 0) + { + int i; + u_char *ptr; + + vty_out (vty, " HWaddr: "); + for (i = 0, ptr = LLADDR (sdl); i < sdl->sdl_alen; i++, ptr++) + vty_out (vty, "%s%02x", i == 0 ? "" : ":", *ptr); + vty_out (vty, "%s", VTY_NEWLINE); + } +#else + if (ifp->hw_addr_len != 0) + { + int i; + + vty_out (vty, " HWaddr: "); + for (i = 0; i < ifp->hw_addr_len; i++) + vty_out (vty, "%s%02x", i == 0 ? "" : ":", ifp->hw_addr[i]); + vty_out (vty, "%s", VTY_NEWLINE); + } +#endif /* HAVE_SOCKADDR_DL */ + + /* Bandwidth in kbps */ + if (ifp->bandwidth != 0) + { + vty_out(vty, " bandwidth %u kbps", ifp->bandwidth); + vty_out(vty, "%s", VTY_NEWLINE); + } + + for (node = listhead (ifp->connected); node; nextnode (node)) + { + connected = getdata (node); + if (CHECK_FLAG (connected->conf, ZEBRA_IFC_REAL)) + connected_dump_vty (vty, connected); + } + +#ifdef RTADV + nd_dump_vty (vty, ifp); +#endif /* RTADV */ + +#ifdef HAVE_PROC_NET_DEV + /* Statistics print out using proc file system. */ + vty_out (vty, " input packets %lu, bytes %lu, dropped %lu," + " multicast packets %lu%s", + ifp->stats.rx_packets, ifp->stats.rx_bytes, + ifp->stats.rx_dropped, ifp->stats.rx_multicast, VTY_NEWLINE); + + vty_out (vty, " input errors %lu, length %lu, overrun %lu," + " CRC %lu, frame %lu, fifo %lu, missed %lu%s", + ifp->stats.rx_errors, ifp->stats.rx_length_errors, + ifp->stats.rx_over_errors, ifp->stats.rx_crc_errors, + ifp->stats.rx_frame_errors, ifp->stats.rx_fifo_errors, + ifp->stats.rx_missed_errors, VTY_NEWLINE); + + vty_out (vty, " output packets %lu, bytes %lu, dropped %lu%s", + ifp->stats.tx_packets, ifp->stats.tx_bytes, + ifp->stats.tx_dropped, VTY_NEWLINE); + + vty_out (vty, " output errors %lu, aborted %lu, carrier %lu," + " fifo %lu, heartbeat %lu, window %lu%s", + ifp->stats.tx_errors, ifp->stats.tx_aborted_errors, + ifp->stats.tx_carrier_errors, ifp->stats.tx_fifo_errors, + ifp->stats.tx_heartbeat_errors, ifp->stats.tx_window_errors, + VTY_NEWLINE); + + vty_out (vty, " collisions %lu%s", ifp->stats.collisions, VTY_NEWLINE); +#endif /* HAVE_PROC_NET_DEV */ + +#ifdef HAVE_NET_RT_IFLIST +#if defined (__bsdi__) || defined (__NetBSD__) + /* Statistics print out using sysctl (). */ + vty_out (vty, " input packets %qu, bytes %qu, dropped %qu," + " multicast packets %qu%s", + ifp->stats.ifi_ipackets, ifp->stats.ifi_ibytes, + ifp->stats.ifi_iqdrops, ifp->stats.ifi_imcasts, + VTY_NEWLINE); + + vty_out (vty, " input errors %qu%s", + ifp->stats.ifi_ierrors, VTY_NEWLINE); + + vty_out (vty, " output packets %qu, bytes %qu, multicast packets %qu%s", + ifp->stats.ifi_opackets, ifp->stats.ifi_obytes, + ifp->stats.ifi_omcasts, VTY_NEWLINE); + + vty_out (vty, " output errors %qu%s", + ifp->stats.ifi_oerrors, VTY_NEWLINE); + + vty_out (vty, " collisions %qu%s", + ifp->stats.ifi_collisions, VTY_NEWLINE); +#else + /* Statistics print out using sysctl (). */ + vty_out (vty, " input packets %lu, bytes %lu, dropped %lu," + " multicast packets %lu%s", + ifp->stats.ifi_ipackets, ifp->stats.ifi_ibytes, + ifp->stats.ifi_iqdrops, ifp->stats.ifi_imcasts, + VTY_NEWLINE); + + vty_out (vty, " input errors %lu%s", + ifp->stats.ifi_ierrors, VTY_NEWLINE); + + vty_out (vty, " output packets %lu, bytes %lu, multicast packets %lu%s", + ifp->stats.ifi_opackets, ifp->stats.ifi_obytes, + ifp->stats.ifi_omcasts, VTY_NEWLINE); + + vty_out (vty, " output errors %lu%s", + ifp->stats.ifi_oerrors, VTY_NEWLINE); + + vty_out (vty, " collisions %lu%s", + ifp->stats.ifi_collisions, VTY_NEWLINE); +#endif /* __bsdi__ || __NetBSD__ */ +#endif /* HAVE_NET_RT_IFLIST */ +} + +/* Check supported address family. */ +int +if_supported_family (int family) +{ + if (family == AF_INET) + return 1; +#ifdef HAVE_IPV6 + if (family == AF_INET6) + return 1; +#endif /* HAVE_IPV6 */ + return 0; +} + +/* Wrapper hook point for zebra daemon so that ifindex can be set + * DEFUN macro not used as extract.pl HAS to ignore this + * See also interface_cmd in lib/if.c + */ +DEFUN_NOSH (zebra_interface, + zebra_interface_cmd, + "interface IFNAME", + "Select an interface to configure\n" + "Interface's name\n") +{ + int ret; + struct interface * ifp; + + /* Call lib interface() */ + ret = interface_cmd.func (self, vty, argc, argv); + + ifp = vty->index; + + /* Set ifindex + this only happens if interface is NOT in kernel */ + if (ifp->ifindex == 0) + { + ifp->ifindex = if_new_intern_ifindex (); + UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); + } + + return ret; +} + +DEFUN (no_zebra_interface, + no_zebra_interface_cmd, + "no interface IFNAME", + "Delete a pseudo interface's configuration\n" + "Interface's name\n") +{ + struct interface *ifp; + + ifp = if_lookup_by_name(argv[0]); + + if (ifp == NULL) + { + vty_out (vty, "Inteface %s does not exist%s", + argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + vty_out(vty, "Only inactive interfaces can be deleted%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Delete interface */ + if_delete(ifp); + + return CMD_SUCCESS; +} + +struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", + 1 +}; + +/* Show all or specified interface to vty. */ +DEFUN (show_interface, show_interface_cmd, + "show interface [IFNAME]", + SHOW_STR + "Interface status and configuration\n" + "Inteface name\n") +{ + listnode node; + struct interface *ifp; + +#ifdef HAVE_PROC_NET_DEV + /* If system has interface statistics via proc file system, update + statistics. */ + ifstat_update_proc (); +#endif /* HAVE_PROC_NET_DEV */ +#ifdef HAVE_NET_RT_IFLIST + ifstat_update_sysctl (); +#endif /* HAVE_NET_RT_IFLIST */ + + /* Specified interface print. */ + if (argc != 0) + { + ifp = if_lookup_by_name (argv[0]); + if (ifp == NULL) + { + vty_out (vty, "%% Can't find interface %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + if_dump_vty (vty, ifp); + return CMD_SUCCESS; + } + + /* All interface print. */ + for (node = listhead (iflist); node; nextnode (node)) + if_dump_vty (vty, getdata (node)); + + return CMD_SUCCESS; +} + +DEFUN (multicast, + multicast_cmd, + "multicast", + "Set multicast flag to interface\n") +{ + int ret; + struct interface *ifp; + struct zebra_if *if_data; + + ifp = (struct interface *) vty->index; + ret = if_set_flags (ifp, IFF_MULTICAST); + if (ret < 0) + { + vty_out (vty, "Can't set multicast flag%s", VTY_NEWLINE); + return CMD_WARNING; + } + if_refresh (ifp); + if_data = ifp->info; + if_data->multicast = IF_ZEBRA_MULTICAST_ON; + + return CMD_SUCCESS; +} + +DEFUN (no_multicast, + no_multicast_cmd, + "no multicast", + NO_STR + "Unset multicast flag to interface\n") +{ + int ret; + struct interface *ifp; + struct zebra_if *if_data; + + ifp = (struct interface *) vty->index; + ret = if_unset_flags (ifp, IFF_MULTICAST); + if (ret < 0) + { + vty_out (vty, "Can't unset multicast flag%s", VTY_NEWLINE); + return CMD_WARNING; + } + if_refresh (ifp); + if_data = ifp->info; + if_data->multicast = IF_ZEBRA_MULTICAST_OFF; + + return CMD_SUCCESS; +} + +DEFUN (shutdown_if, + shutdown_if_cmd, + "shutdown", + "Shutdown the selected interface\n") +{ + int ret; + struct interface *ifp; + struct zebra_if *if_data; + + ifp = (struct interface *) vty->index; + ret = if_unset_flags (ifp, IFF_UP); + if (ret < 0) + { + vty_out (vty, "Can't shutdown interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + if_refresh (ifp); + if_data = ifp->info; + if_data->shutdown = IF_ZEBRA_SHUTDOWN_ON; + + return CMD_SUCCESS; +} + +DEFUN (no_shutdown_if, + no_shutdown_if_cmd, + "no shutdown", + NO_STR + "Shutdown the selected interface\n") +{ + int ret; + struct interface *ifp; + struct zebra_if *if_data; + + ifp = (struct interface *) vty->index; + ret = if_set_flags (ifp, IFF_UP | IFF_RUNNING); + if (ret < 0) + { + vty_out (vty, "Can't up interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + if_refresh (ifp); + if_data = ifp->info; + if_data->shutdown = IF_ZEBRA_SHUTDOWN_OFF; + + return CMD_SUCCESS; +} + +DEFUN (bandwidth_if, + bandwidth_if_cmd, + "bandwidth <1-10000000>", + "Set bandwidth informational parameter\n" + "Bandwidth in kilobits\n") +{ + struct interface *ifp; + unsigned int bandwidth; + + ifp = (struct interface *) vty->index; + bandwidth = strtol(argv[0], NULL, 10); + + /* bandwidth range is <1-10000000> */ + if (bandwidth < 1 || bandwidth > 10000000) + { + vty_out (vty, "Bandwidth is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ifp->bandwidth = bandwidth; + + /* force protocols to recalculate routes due to cost change */ + if (if_is_up (ifp)) + zebra_interface_up_update (ifp); + + return CMD_SUCCESS; +} + +DEFUN (no_bandwidth_if, + no_bandwidth_if_cmd, + "no bandwidth", + NO_STR + "Set bandwidth informational parameter\n") +{ + struct interface *ifp; + + ifp = (struct interface *) vty->index; + + ifp->bandwidth = 0; + + /* force protocols to recalculate routes due to cost change */ + if (if_is_up (ifp)) + zebra_interface_up_update (ifp); + + return CMD_SUCCESS; +} + +ALIAS (no_bandwidth_if, + no_bandwidth_if_val_cmd, + "no bandwidth <1-10000000>", + NO_STR + "Set bandwidth informational parameter\n" + "Bandwidth in kilobits\n"); + +int +ip_address_install (struct vty *vty, struct interface *ifp, char *addr_str, + char *peer_str, char *label, int secondary) +{ + struct prefix_ipv4 cp; + struct connected *ifc; + struct prefix_ipv4 *p; + struct in_addr mask; + int ret; + + ret = str2prefix_ipv4 (addr_str, &cp); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); + return CMD_WARNING; + } + + ifc = connected_check_ipv4 (ifp, (struct prefix *) &cp); + if (! ifc) + { + ifc = connected_new (); + ifc->ifp = ifp; + + /* Address. */ + p = prefix_ipv4_new (); + *p = cp; + ifc->address = (struct prefix *) p; + + /* Broadcast. */ + if (p->prefixlen <= 30) + { + p = prefix_ipv4_new (); + *p = cp; + masklen2ip (p->prefixlen, &mask); + p->prefix.s_addr |= ~mask.s_addr; + ifc->destination = (struct prefix *) p; + } + + /* Secondary. */ + if (secondary) + SET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY); + + /* Label. */ + if (label) + ifc->label = strdup (label); + + /* Add to linked list. */ + listnode_add (ifp->connected, ifc); + } + + /* This address is configured from zebra. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED); + + /* In case of this route need to install kernel. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) + && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + /* Some system need to up the interface to set IP address. */ + if (! if_is_up (ifp)) + { + if_set_flags (ifp, IFF_UP | IFF_RUNNING); + if_refresh (ifp); + } + + ret = if_set_prefix (ifp, ifc); + if (ret < 0) + { + vty_out (vty, "%% Can't set interface IP address: %s.%s", + strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* IP address propery set. */ + SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + /* Update interface address information to protocol daemon. */ + zebra_interface_address_add_update (ifp, ifc); + + /* If interface is up register connected route. */ + if (if_is_up(ifp)) + connected_up_ipv4 (ifp, ifc); + } + + return CMD_SUCCESS; +} + +int +ip_address_uninstall (struct vty *vty, struct interface *ifp, char *addr_str, + char *peer_str, char *label, int secondry) +{ + struct prefix_ipv4 cp; + struct connected *ifc; + int ret; + + /* Convert to prefix structure. */ + ret = str2prefix_ipv4 (addr_str, &cp); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check current interface address. */ + ifc = connected_check_ipv4 (ifp, (struct prefix *) &cp); + if (! ifc) + { + vty_out (vty, "%% Can't find address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* This is not configured address. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + return CMD_WARNING; + + /* This is not real address or interface is not active. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) + || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + return CMD_WARNING; + } + + /* This is real route. */ + ret = if_unset_prefix (ifp, ifc); + if (ret < 0) + { + vty_out (vty, "%% Can't unset interface IP address: %s.%s", + strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Redistribute this information. */ + zebra_interface_address_delete_update (ifp, ifc); + + /* Remove connected route. */ + connected_down_ipv4 (ifp, ifc); + + /* Free address information. */ + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + + return CMD_SUCCESS; +} + +DEFUN (ip_address, + ip_address_cmd, + "ip address A.B.C.D/M", + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n") +{ + return ip_address_install (vty, vty->index, argv[0], NULL, NULL, 0); +} + +DEFUN (no_ip_address, + no_ip_address_cmd, + "no ip address A.B.C.D/M", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP Address (e.g. 10.0.0.1/8)") +{ + return ip_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 0); +} + +#ifdef HAVE_NETLINK +DEFUN (ip_address_secondary, + ip_address_secondary_cmd, + "ip address A.B.C.D/M secondary", + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n" + "Secondary IP address\n") +{ + return ip_address_install (vty, vty->index, argv[0], NULL, NULL, 1); +} + +DEFUN (ip_address_label, + ip_address_label_cmd, + "ip address A.B.C.D/M label LINE", + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n" + "Label of this address\n" + "Label\n") +{ + return ip_address_install (vty, vty->index, argv[0], NULL, argv[1], 1); +} + +DEFUN (no_ip_address_secondary, + no_ip_address_secondary_cmd, + "no ip address A.B.C.D/M secondary", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n" + "Secondary IP address\n") +{ + return ip_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 1); +} + +DEFUN (no_ip_address_label, + no_ip_address_label_cmd, + "no ip address A.B.C.D/M label LINE", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n" + "Label of this address\n" + "Label\n") +{ + return ip_address_uninstall (vty, vty->index, argv[0], NULL, argv[1], 1); +} +#endif /* HAVE_NETLINK */ + +#ifdef HAVE_IPV6 +int +ipv6_address_install (struct vty *vty, struct interface *ifp, char *addr_str, + char *peer_str, char *label, int secondary) +{ + struct prefix_ipv6 cp; + struct connected *ifc; + struct prefix_ipv6 *p; + int ret; + + ret = str2prefix_ipv6 (addr_str, &cp); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); + return CMD_WARNING; + } + + ifc = connected_check_ipv6 (ifp, (struct prefix *) &cp); + if (! ifc) + { + ifc = connected_new (); + ifc->ifp = ifp; + + /* Address. */ + p = prefix_ipv6_new (); + *p = cp; + ifc->address = (struct prefix *) p; + + /* Secondary. */ + if (secondary) + SET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY); + + /* Label. */ + if (label) + ifc->label = strdup (label); + + /* Add to linked list. */ + listnode_add (ifp->connected, ifc); + } + + /* This address is configured from zebra. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED); + + /* In case of this route need to install kernel. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) + && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + /* Some system need to up the interface to set IP address. */ + if (! if_is_up (ifp)) + { + if_set_flags (ifp, IFF_UP | IFF_RUNNING); + if_refresh (ifp); + } + + ret = if_prefix_add_ipv6 (ifp, ifc); + + if (ret < 0) + { + vty_out (vty, "%% Can't set interface IP address: %s.%s", + strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* IP address propery set. */ + SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + /* Update interface address information to protocol daemon. */ + zebra_interface_address_add_update (ifp, ifc); + + /* If interface is up register connected route. */ + if (if_is_up(ifp)) + connected_up_ipv6 (ifp, ifc); + } + + return CMD_SUCCESS; +} + +int +ipv6_address_uninstall (struct vty *vty, struct interface *ifp, char *addr_str, + char *peer_str, char *label, int secondry) +{ + struct prefix_ipv6 cp; + struct connected *ifc; + int ret; + + /* Convert to prefix structure. */ + ret = str2prefix_ipv6 (addr_str, &cp); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Check current interface address. */ + ifc = connected_check_ipv6 (ifp, (struct prefix *) &cp); + if (! ifc) + { + vty_out (vty, "%% Can't find address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* This is not configured address. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + return CMD_WARNING; + + /* This is not real address or interface is not active. */ + if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) + || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + return CMD_WARNING; + } + + /* This is real route. */ + ret = if_prefix_delete_ipv6 (ifp, ifc); + if (ret < 0) + { + vty_out (vty, "%% Can't unset interface IP address: %s.%s", + strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + /* Redistribute this information. */ + zebra_interface_address_delete_update (ifp, ifc); + + /* Remove connected route. */ + connected_down_ipv6 (ifp, ifc); + + /* Free address information. */ + listnode_delete (ifp->connected, ifc); + connected_free (ifc); + + return CMD_SUCCESS; +} + +DEFUN (ipv6_address, + ipv6_address_cmd, + "ipv6 address X:X::X:X/M", + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IPv6 address (e.g. 3ffe:506::1/48)\n") +{ + return ipv6_address_install (vty, vty->index, argv[0], NULL, NULL, 0); +} + +DEFUN (no_ipv6_address, + no_ipv6_address_cmd, + "no ipv6 address X:X::X:X/M", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IPv6 address (e.g. 3ffe:506::1/48)\n") +{ + return ipv6_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 0); +} +#endif /* HAVE_IPV6 */ + +#ifdef KAME +DEFUN (ip_tunnel, + ip_tunnel_cmd, + "ip tunnel IP_address IP_address", + "KAME ip tunneling configuration commands\n" + "Set FROM IP address and TO IP address\n") +{ + return CMD_SUCCESS; +} + +DEFUN (no_ip_tunnel, no_ip_tunnel_cmd, + "no ip tunnel", + NO_STR + "Set FROM IP address and TO IP address\n") +{ + return CMD_SUCCESS; +} +#endif /* KAME */ + +int +if_config_write (struct vty *vty) +{ + listnode node; + struct interface *ifp; + char buf[BUFSIZ]; + + for (node = listhead (iflist); node; nextnode (node)) + { + struct zebra_if *if_data; + listnode addrnode; + struct connected *ifc; + struct prefix *p; + + ifp = getdata (node); + if_data = ifp->info; + + vty_out (vty, "interface %s%s", ifp->name, + VTY_NEWLINE); + + if (ifp->desc) + vty_out (vty, " description %s%s", ifp->desc, + VTY_NEWLINE); + + /* Assign bandwidth here to avoid unnecessary interface flap + while processing config script */ + if (ifp->bandwidth != 0) + vty_out(vty, " bandwidth %u%s", ifp->bandwidth, VTY_NEWLINE); + + for (addrnode = listhead (ifp->connected); addrnode; nextnode (addrnode)) + { + ifc = getdata (addrnode); + if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) + { + p = ifc->address; + vty_out (vty, " ip%s address %s/%d", + p->family == AF_INET ? "" : "v6", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen); + + if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY)) + vty_out (vty, " secondary"); + + if (ifc->label) + vty_out (vty, " label %s", ifc->label); + + vty_out (vty, "%s", VTY_NEWLINE); + } + } + + if (if_data) + { + if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) + vty_out (vty, " shutdown%s", VTY_NEWLINE); + + if (if_data->multicast != IF_ZEBRA_MULTICAST_UNSPEC) + vty_out (vty, " %smulticast%s", + if_data->multicast == IF_ZEBRA_MULTICAST_ON ? "" : "no ", + VTY_NEWLINE); + } + +#ifdef RTADV + rtadv_config_write (vty, ifp); +#endif /* RTADV */ + +#ifdef HAVE_IRDP + irdp_config_write (vty, ifp); +#endif /* IRDP */ + + vty_out (vty, "!%s", VTY_NEWLINE); + } + return 0; +} + +/* Allocate and initialize interface vector. */ +void +zebra_if_init () +{ + /* Initialize interface and new hook. */ + if_init (); + if_add_hook (IF_NEW_HOOK, if_zebra_new_hook); + if_add_hook (IF_DELETE_HOOK, if_zebra_delete_hook); + + /* Install configuration write function. */ + install_node (&interface_node, if_config_write); + + install_element (VIEW_NODE, &show_interface_cmd); + install_element (ENABLE_NODE, &show_interface_cmd); + install_element (CONFIG_NODE, &zebra_interface_cmd); + install_element (CONFIG_NODE, &no_zebra_interface_cmd); + install_default (INTERFACE_NODE); + install_element (INTERFACE_NODE, &interface_desc_cmd); + install_element (INTERFACE_NODE, &no_interface_desc_cmd); + install_element (INTERFACE_NODE, &multicast_cmd); + install_element (INTERFACE_NODE, &no_multicast_cmd); + install_element (INTERFACE_NODE, &shutdown_if_cmd); + install_element (INTERFACE_NODE, &no_shutdown_if_cmd); + install_element (INTERFACE_NODE, &bandwidth_if_cmd); + install_element (INTERFACE_NODE, &no_bandwidth_if_cmd); + install_element (INTERFACE_NODE, &no_bandwidth_if_val_cmd); + install_element (INTERFACE_NODE, &ip_address_cmd); + install_element (INTERFACE_NODE, &no_ip_address_cmd); +#ifdef HAVE_IPV6 + install_element (INTERFACE_NODE, &ipv6_address_cmd); + install_element (INTERFACE_NODE, &no_ipv6_address_cmd); +#endif /* HAVE_IPV6 */ +#ifdef KAME + install_element (INTERFACE_NODE, &ip_tunnel_cmd); + install_element (INTERFACE_NODE, &no_ip_tunnel_cmd); +#endif /* KAME */ +#ifdef HAVE_NETLINK + install_element (INTERFACE_NODE, &ip_address_secondary_cmd); + install_element (INTERFACE_NODE, &ip_address_label_cmd); + install_element (INTERFACE_NODE, &no_ip_address_secondary_cmd); + install_element (INTERFACE_NODE, &no_ip_address_label_cmd); +#endif /* HAVE_NETLINK */ +} diff --git a/zebra/interface.h b/zebra/interface.h new file mode 100644 index 0000000..f28adb3 --- /dev/null +++ b/zebra/interface.h @@ -0,0 +1,186 @@ +/* Interface function header. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* For interface multicast configuration. */ +#define IF_ZEBRA_MULTICAST_UNSPEC 0 +#define IF_ZEBRA_MULTICAST_ON 1 +#define IF_ZEBRA_MULTICAST_OFF 2 + +/* For interface shutdown configuration. */ +#define IF_ZEBRA_SHUTDOWN_UNSPEC 0 +#define IF_ZEBRA_SHUTDOWN_ON 1 +#define IF_ZEBRA_SHUTDOWN_OFF 2 + +/* Router advertisement feature. */ +#if (defined(LINUX_IPV6) && (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)) || defined(KAME) +#define RTADV +#endif + +#ifdef RTADV +/* Router advertisement parameter. From RFC2461. */ +struct rtadvconf +{ + /* A flag indicating whether or not the router sends periodic Router + Advertisements and responds to Router Solicitations. + Default: FALSE */ + int AdvSendAdvertisements; + + /* The maximum time allowed between sending unsolicited multicast + Router Advertisements from the interface, in seconds. MUST be no + less than 4 seconds and no greater than 1800 seconds. + + Default: 600 seconds */ + int MaxRtrAdvInterval; +#define RTADV_MAX_RTR_ADV_INTERVAL 600 + + /* The minimum time allowed between sending unsolicited multicast + Router Advertisements from the interface, in seconds. MUST be no + less than 3 seconds and no greater than .75 * MaxRtrAdvInterval. + + Default: 0.33 * MaxRtrAdvInterval */ + int MinRtrAdvInterval; +#define RTADV_MIN_RTR_ADV_INTERVAL (0.33 * RTADV_MAX_RTR_ADV_INTERVAL) + + /* Unsolicited Router Advertisements' interval timer. */ + int AdvIntervalTimer; + + /* The TRUE/FALSE value to be placed in the "Managed address + configuration" flag field in the Router Advertisement. See + [ADDRCONF]. + + Default: FALSE */ + int AdvManagedFlag; + + + /* The TRUE/FALSE value to be placed in the "Other stateful + configuration" flag field in the Router Advertisement. See + [ADDRCONF]. + + Default: FALSE */ + int AdvOtherConfigFlag; + + /* The value to be placed in MTU options sent by the router. A + value of zero indicates that no MTU options are sent. + + Default: 0 */ + int AdvLinkMTU; + + + /* The value to be placed in the Reachable Time field in the Router + Advertisement messages sent by the router. The value zero means + unspecified (by this router). MUST be no greater than 3,600,000 + milliseconds (1 hour). + + Default: 0 */ + u_int32_t AdvReachableTime; +#define RTADV_MAX_REACHABLE_TIME 3600000 + + + /* The value to be placed in the Retrans Timer field in the Router + Advertisement messages sent by the router. The value zero means + unspecified (by this router). + + Default: 0 */ + int AdvRetransTimer; + + /* The default value to be placed in the Cur Hop Limit field in the + Router Advertisement messages sent by the router. The value + should be set to that current diameter of the Internet. The + value zero means unspecified (by this router). + + Default: The value specified in the "Assigned Numbers" RFC + [ASSIGNED] that was in effect at the time of implementation. */ + int AdvCurHopLimit; + + /* The value to be placed in the Router Lifetime field of Router + Advertisements sent from the interface, in seconds. MUST be + either zero or between MaxRtrAdvInterval and 9000 seconds. A + value of zero indicates that the router is not to be used as a + default router. + + Default: 3 * MaxRtrAdvInterval */ + int AdvDefaultLifetime; +#define RTADV_ADV_DEFAULT_LIFETIME (3 * RTADV_MAX_RTR_ADV_INTERVAL) + + + /* A list of prefixes to be placed in Prefix Information options in + Router Advertisement messages sent from the interface. + + Default: all prefixes that the router advertises via routing + protocols as being on-link for the interface from which the + advertisement is sent. The link-local prefix SHOULD NOT be + included in the list of advertised prefixes. */ + list AdvPrefixList; +}; + +#endif /* RTADV */ + +/* `zebra' daemon local interface structure. */ +struct zebra_if +{ + /* Shutdown configuration. */ + u_char shutdown; + + /* Multicast configuration. */ + u_char multicast; + + /* Router advertise configuration. */ + u_char rtadv_enable; + + /* Interface's address. */ + list address; + +#ifdef RTADV + struct rtadvconf rtadv; +#endif /* RTADV */ + +#ifdef HAVE_IRDP +#include "irdp.h" + struct irdp_interface irdp; +#endif + +}; + +void if_delete_update (struct interface *ifp); +void if_add_update (struct interface *ifp); +void if_up (struct interface *); +void if_down (struct interface *); +void if_refresh (struct interface *); +void zebra_interface_up_update (struct interface *ifp); +void zebra_interface_down_update (struct interface *ifp); + +#ifdef HAVE_PROC_NET_DEV +int ifstat_update_proc (); +#endif /* HAVE_PROC_NET_DEV */ +#ifdef HAVE_NET_RT_IFLIST +void ifstat_update_sysctl (); + +#endif /* HAVE_NET_RT_IFLIST */ +#ifdef HAVE_PROC_NET_DEV +int interface_list_proc (); +#endif /* HAVE_PROC_NET_DEV */ +#ifdef HAVE_PROC_NET_IF_INET6 +int ifaddr_proc_ipv6 (); +#endif /* HAVE_PROC_NET_IF_INET6 */ + +#ifdef BSDI +int if_kvm_get_mtu (struct interface *); +#endif /* BSDI */ diff --git a/zebra/ioctl.c b/zebra/ioctl.c new file mode 100644 index 0000000..13afba2 --- /dev/null +++ b/zebra/ioctl.c @@ -0,0 +1,540 @@ +/* + * Common ioctl functions. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "if.h" +#include "prefix.h" +#include "ioctl.h" +#include "log.h" + +#include "zebra/rib.h" +#include "zebra/rt.h" + +/* clear and set interface name string */ +void +ifreq_set_name (struct ifreq *ifreq, struct interface *ifp) +{ + strncpy (ifreq->ifr_name, ifp->name, IFNAMSIZ); +} + +/* call ioctl system call */ +int +if_ioctl (u_long request, caddr_t buffer) +{ + int sock; + int ret = 0; + int err = 0; + + sock = socket (AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + { + perror ("socket"); + exit (1); + } + + ret = ioctl (sock, request, buffer); + if (ret < 0) + { + err = errno; + } + close (sock); + + if (ret < 0) + { + errno = err; + return ret; + } + return 0; +} + +#ifdef HAVE_IPV6 +int +if_ioctl_ipv6 (u_long request, caddr_t buffer) +{ + int sock; + int ret = 0; + int err = 0; + + sock = socket (AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + perror ("socket"); + exit (1); + } + + ret = ioctl (sock, request, buffer); + if (ret < 0) + { + err = errno; + } + close (sock); + + if (ret < 0) + { + errno = err; + return ret; + } + return 0; +} +#endif /* HAVE_IPV6 */ + +/* + * get interface metric + * -- if value is not avaliable set -1 + */ +void +if_get_metric (struct interface *ifp) +{ +#ifdef SIOCGIFMETRIC + struct ifreq ifreq; + + ifreq_set_name (&ifreq, ifp); + + if (if_ioctl (SIOCGIFMETRIC, (caddr_t) &ifreq) < 0) + return; + ifp->metric = ifreq.ifr_metric; + if (ifp->metric == 0) + ifp->metric = 1; +#else /* SIOCGIFMETRIC */ + ifp->metric = -1; +#endif /* SIOCGIFMETRIC */ +} + +/* get interface MTU */ +void +if_get_mtu (struct interface *ifp) +{ + struct ifreq ifreq; + + ifreq_set_name (&ifreq, ifp); + +#if defined(SIOCGIFMTU) + if (if_ioctl (SIOCGIFMTU, (caddr_t) & ifreq) < 0) + { + zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)"); + ifp->mtu = -1; + return; + } + +#ifdef SUNOS_5 + ifp->mtu = ifreq.ifr_metric; +#else + ifp->mtu = ifreq.ifr_mtu; +#endif /* SUNOS_5 */ + +#else + zlog (NULL, LOG_INFO, "Can't lookup mtu on this system"); + ifp->mtu = -1; +#endif +} + +#ifdef HAVE_NETLINK +/* Interface address setting via netlink interface. */ +int +if_set_prefix (struct interface *ifp, struct connected *ifc) +{ + return kernel_address_add_ipv4 (ifp, ifc); +} + +/* Interface address is removed using netlink interface. */ +int +if_unset_prefix (struct interface *ifp, struct connected *ifc) +{ + return kernel_address_delete_ipv4 (ifp, ifc); +} +#else /* ! HAVE_NETLINK */ +#ifdef HAVE_IFALIASREQ +/* Set up interface's IP address, netmask (and broadcas? ). *BSD may + has ifaliasreq structure. */ +int +if_set_prefix (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct ifaliasreq addreq; + struct sockaddr_in addr; + struct sockaddr_in mask; + struct prefix_ipv4 *p; + + p = (struct prefix_ipv4 *) ifc->address; + + memset (&addreq, 0, sizeof addreq); + strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + + memset (&addr, 0, sizeof (struct sockaddr_in)); + addr.sin_addr = p->prefix; + addr.sin_family = p->family; +#ifdef HAVE_SIN_LEN + addr.sin_len = sizeof (struct sockaddr_in); +#endif + memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in)); + + memset (&mask, 0, sizeof (struct sockaddr_in)); + masklen2ip (p->prefixlen, &mask.sin_addr); + mask.sin_family = p->family; +#ifdef HAVE_SIN_LEN + mask.sin_len = sizeof (struct sockaddr_in); +#endif + memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in)); + + ret = if_ioctl (SIOCAIFADDR, (caddr_t) &addreq); + if (ret < 0) + return ret; + return 0; +} + +/* Set up interface's IP address, netmask (and broadcas? ). *BSD may + has ifaliasreq structure. */ +int +if_unset_prefix (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct ifaliasreq addreq; + struct sockaddr_in addr; + struct sockaddr_in mask; + struct prefix_ipv4 *p; + + p = (struct prefix_ipv4 *)ifc->address; + + memset (&addreq, 0, sizeof addreq); + strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + + memset (&addr, 0, sizeof (struct sockaddr_in)); + addr.sin_addr = p->prefix; + addr.sin_family = p->family; +#ifdef HAVE_SIN_LEN + addr.sin_len = sizeof (struct sockaddr_in); +#endif + memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in)); + + memset (&mask, 0, sizeof (struct sockaddr_in)); + masklen2ip (p->prefixlen, &mask.sin_addr); + mask.sin_family = p->family; +#ifdef HAVE_SIN_LEN + mask.sin_len = sizeof (struct sockaddr_in); +#endif + memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in)); + + ret = if_ioctl (SIOCDIFADDR, (caddr_t) &addreq); + if (ret < 0) + return ret; + return 0; +} +#else +/* Set up interface's address, netmask (and broadcas? ). Linux or + Solaris uses ifname:number semantics to set IP address aliases. */ +int +if_set_prefix (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct ifreq ifreq; + struct sockaddr_in addr; + struct sockaddr_in broad; + struct sockaddr_in mask; + struct prefix_ipv4 ifaddr; + struct prefix_ipv4 *p; + + p = (struct prefix_ipv4 *) ifc->address; + + ifaddr = *p; + + ifreq_set_name (&ifreq, ifp); + + addr.sin_addr = p->prefix; + addr.sin_family = p->family; + memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in)); + ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq); + if (ret < 0) + return ret; + + /* We need mask for make broadcast addr. */ + masklen2ip (p->prefixlen, &mask.sin_addr); + + if (if_is_broadcast (ifp)) + { + apply_mask_ipv4 (&ifaddr); + addr.sin_addr = ifaddr.prefix; + + broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr); + broad.sin_family = p->family; + + memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in)); + ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) &ifreq); + if (ret < 0) + return ret; + } + + mask.sin_family = p->family; +#ifdef SUNOS_5 + memcpy (&mask, &ifreq.ifr_addr, sizeof (mask)); +#else + memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in)); +#endif /* SUNOS5 */ + ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) &ifreq); + if (ret < 0) + return ret; + + return 0; +} + +/* Set up interface's address, netmask (and broadcas? ). Linux or + Solaris uses ifname:number semantics to set IP address aliases. */ +int +if_unset_prefix (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct ifreq ifreq; + struct sockaddr_in addr; + struct prefix_ipv4 *p; + + p = (struct prefix_ipv4 *) ifc->address; + + ifreq_set_name (&ifreq, ifp); + + memset (&addr, 0, sizeof (struct sockaddr_in)); + addr.sin_family = p->family; + memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in)); + ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq); + if (ret < 0) + return ret; + + return 0; +} +#endif /* HAVE_IFALIASREQ */ +#endif /* HAVE_NETLINK */ + +/* get interface flags */ +void +if_get_flags (struct interface *ifp) +{ + int ret; + struct ifreq ifreq; + + ifreq_set_name (&ifreq, ifp); + + ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq); + if (ret < 0) + { + perror ("ioctl"); + return; + } + + ifp->flags = ifreq.ifr_flags & 0x0000ffff; +} + +/* Set interface flags */ +int +if_set_flags (struct interface *ifp, unsigned long flags) +{ + int ret; + struct ifreq ifreq; + + ifreq_set_name (&ifreq, ifp); + + ifreq.ifr_flags = ifp->flags; + ifreq.ifr_flags |= flags; + + ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq); + + if (ret < 0) + { + zlog_info ("can't set interface flags"); + return ret; + } + return 0; +} + +/* Unset interface's flag. */ +int +if_unset_flags (struct interface *ifp, unsigned long flags) +{ + int ret; + struct ifreq ifreq; + + ifreq_set_name (&ifreq, ifp); + + ifreq.ifr_flags = ifp->flags; + ifreq.ifr_flags &= ~flags; + + ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq); + + if (ret < 0) + { + zlog_info ("can't unset interface flags"); + return ret; + } + return 0; +} + +#ifdef HAVE_IPV6 + +#ifdef LINUX_IPV6 +#ifndef _LINUX_IN6_H +/* linux/include/net/ipv6.h */ +struct in6_ifreq +{ + struct in6_addr ifr6_addr; + u_int32_t ifr6_prefixlen; + int ifr6_ifindex; +}; +#endif /* _LINUX_IN6_H */ + +/* Interface's address add/delete functions. */ +int +if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct prefix_ipv6 *p; + struct in6_ifreq ifreq; + + p = (struct prefix_ipv6 *) ifc->address; + + memset (&ifreq, 0, sizeof (struct in6_ifreq)); + + memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr)); + ifreq.ifr6_ifindex = ifp->ifindex; + ifreq.ifr6_prefixlen = p->prefixlen; + + ret = if_ioctl_ipv6 (SIOCSIFADDR, (caddr_t) &ifreq); + + return ret; +} + +int +if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct prefix_ipv6 *p; + struct in6_ifreq ifreq; + + p = (struct prefix_ipv6 *) ifc->address; + + memset (&ifreq, 0, sizeof (struct in6_ifreq)); + + memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr)); + ifreq.ifr6_ifindex = ifp->ifindex; + ifreq.ifr6_prefixlen = p->prefixlen; + + ret = if_ioctl_ipv6 (SIOCDIFADDR, (caddr_t) &ifreq); + + return ret; +} +#else /* LINUX_IPV6 */ +#ifdef HAVE_IN6_ALIASREQ +#ifndef ND6_INFINITE_LIFETIME +#define ND6_INFINITE_LIFETIME 0xffffffffL +#endif /* ND6_INFINITE_LIFETIME */ +int +if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct in6_aliasreq addreq; + struct sockaddr_in6 addr; + struct sockaddr_in6 mask; + struct prefix_ipv6 *p; + + p = (struct prefix_ipv6 * ) ifc->address; + + memset (&addreq, 0, sizeof addreq); + strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + + memset (&addr, 0, sizeof (struct sockaddr_in6)); + addr.sin6_addr = p->prefix; + addr.sin6_family = p->family; +#ifdef HAVE_SIN_LEN + addr.sin6_len = sizeof (struct sockaddr_in6); +#endif + memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6)); + + memset (&mask, 0, sizeof (struct sockaddr_in6)); + masklen2ip6 (p->prefixlen, &mask.sin6_addr); + mask.sin6_family = p->family; +#ifdef HAVE_SIN_LEN + mask.sin6_len = sizeof (struct sockaddr_in6); +#endif + memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6)); + + addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; + addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; + + ret = if_ioctl_ipv6 (SIOCAIFADDR_IN6, (caddr_t) &addreq); + if (ret < 0) + return ret; + return 0; +} + +int +if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) +{ + int ret; + struct in6_aliasreq addreq; + struct sockaddr_in6 addr; + struct sockaddr_in6 mask; + struct prefix_ipv6 *p; + + p = (struct prefix_ipv6 *) ifc->address; + + memset (&addreq, 0, sizeof addreq); + strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + + memset (&addr, 0, sizeof (struct sockaddr_in6)); + addr.sin6_addr = p->prefix; + addr.sin6_family = p->family; +#ifdef HAVE_SIN_LEN + addr.sin6_len = sizeof (struct sockaddr_in6); +#endif + memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6)); + + memset (&mask, 0, sizeof (struct sockaddr_in6)); + masklen2ip6 (p->prefixlen, &mask.sin6_addr); + mask.sin6_family = p->family; +#ifdef HAVE_SIN_LEN + mask.sin6_len = sizeof (struct sockaddr_in6); +#endif + memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6)); + + addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; + addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; + + ret = if_ioctl_ipv6 (SIOCDIFADDR_IN6, (caddr_t) &addreq); + if (ret < 0) + return ret; + return 0; +} +#else +int +if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) +{ + return 0; +} + +int +if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) +{ + return 0; +} +#endif /* HAVE_IN6_ALIASREQ */ + +#endif /* LINUX_IPV6 */ + +#endif /* HAVE_IPV6 */ diff --git a/zebra/ioctl.h b/zebra/ioctl.h new file mode 100644 index 0000000..157fc44 --- /dev/null +++ b/zebra/ioctl.h @@ -0,0 +1,46 @@ +/* + * Common ioctl functions. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_IOCTL_H +#define _ZEBRA_IOCTL_H + +/* Prototypes. */ +void ifreq_set_name (struct ifreq *, struct interface *); +int if_ioctl (u_long, caddr_t); + +int if_set_flags (struct interface *, unsigned long); +int if_unset_flags (struct interface *, unsigned long); +void if_get_flags (struct interface *); + +int if_set_prefix (struct interface *, struct connected *); +int if_unset_prefix (struct interface *, struct connected *); + +void if_get_metric (struct interface *); +void if_get_mtu (struct interface *); + +#ifdef HAVE_IPV6 +int if_prefix_add_ipv6 (struct interface *, struct connected *); +int if_prefix_delete_ipv6 (struct interface *, struct connected *); + +#endif /* HAVE_IPV6 */ + +#endif /* _ZEBRA_IOCTL_H */ diff --git a/zebra/ipforward.h b/zebra/ipforward.h new file mode 100644 index 0000000..a772337 --- /dev/null +++ b/zebra/ipforward.h @@ -0,0 +1,35 @@ +/* IP forward settings. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_IPFORWARD_H +#define _ZEBRA_IPFORWARD_H + +int ipforward (); +int ipforward_on (); +int ipforward_off (); + +#ifdef HAVE_IPV6 +int ipforward_ipv6 (); +int ipforward_ipv6_on (); +int ipforward_ipv6_off (); +#endif /* HAVE_IPV6 */ + +#endif /* _ZEBRA_IPFORWARD_H */ diff --git a/zebra/ipforward_aix.c b/zebra/ipforward_aix.c new file mode 100644 index 0000000..c79e7f1 --- /dev/null +++ b/zebra/ipforward_aix.c @@ -0,0 +1,64 @@ +/* + * ipforward value get function for aix. + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +int +ipforward () +{ + int fd, ret; + int af = AF_INET; + char netopt[] = "ipforwarding"; + struct optreq oq; + + fd = socket(af, SOCK_DGRAM, 0); + if (fd < 0) { + /* need logging here */ + return -1; + } + + strcpy (oq.name, netopt); + oq.getnext = 0; + + ret = ioctl (fd, SIOCGNETOPT, (caddr_t)&oq); + close(fd); + + if (ret < 0) { + /* need logging here */ + return -1; + } + + ret = atoi (oq.data); + return ret; +} + +int +ipforward_on () +{ + ; +} + +int +ipforward_off () +{ + ; +} diff --git a/zebra/ipforward_ews.c b/zebra/ipforward_ews.c new file mode 100644 index 0000000..c872000 --- /dev/null +++ b/zebra/ipforward_ews.c @@ -0,0 +1,60 @@ +/* + * Ipforward value get function for NEC EWS. + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +int +ipforward () +{ + int fd; + char buf[BUFSIZ]; + struct mioc_rksym rks; + + fd = open ("/dev/kmem", O_RDWR); + if (fd < 0) { + /* need logging here */ + return -1; + } + + rks.mirk_symname = "ipforwarding"; + rks.mirk_buf = buf; + rks.mirk_buflen = sizeof (int); + + if (ioctl (fd, MIOC_READKSYM, &rks) < 0) { + /* need logging here */ + return -1; + } + close (fd); + return *(int *)buf; +} + +int +ipforward_on () +{ + ; +} + +int +ipforward_off () +{ + ; +} diff --git a/zebra/ipforward_proc.c b/zebra/ipforward_proc.c new file mode 100644 index 0000000..eb8cef0 --- /dev/null +++ b/zebra/ipforward_proc.c @@ -0,0 +1,155 @@ +/* + * Fetch ipforward value by reading /proc filesystem. + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +char proc_net_snmp[] = "/proc/net/snmp"; + +static void +dropline (FILE *fp) +{ + int c; + + while ((c = getc (fp)) != '\n') + ; +} + +int +ipforward () +{ + FILE *fp; + int ipforwarding = 0; + char *pnt; + char buf[10]; + + fp = fopen (proc_net_snmp, "r"); + + if (fp == NULL) + return -1; + + /* We don't care about the first line. */ + dropline (fp); + + /* Get ip_statistics.IpForwarding : + 1 => ip forwarding enabled + 2 => ip forwarding off. */ + pnt = fgets (buf, 6, fp); + sscanf (buf, "Ip: %d", &ipforwarding); + + if (ipforwarding == 1) + return 1; + + return 0; +} + +/* char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/conf/all/forwarding"; */ +char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/ip_forward"; + +int +ipforward_on () +{ + FILE *fp; + + fp = fopen (proc_ipv4_forwarding, "w"); + + if (fp == NULL) + return -1; + + fprintf (fp, "1\n"); + + fclose (fp); + + return ipforward (); +} + +int +ipforward_off () +{ + FILE *fp; + + fp = fopen (proc_ipv4_forwarding, "w"); + + if (fp == NULL) + return -1; + + fprintf (fp, "0\n"); + + fclose (fp); + + return ipforward (); +} +#ifdef HAVE_IPV6 + +char proc_ipv6_forwarding[] = "/proc/sys/net/ipv6/conf/all/forwarding"; + +int +ipforward_ipv6 () +{ + FILE *fp; + char buf[5]; + int ipforwarding = 0; + + fp = fopen (proc_ipv6_forwarding, "r"); + + if (fp == NULL) + return -1; + + fgets (buf, 2, fp); + sscanf (buf, "%d", &ipforwarding); + + return ipforwarding; +} + +int +ipforward_ipv6_on () +{ + FILE *fp; + + fp = fopen (proc_ipv6_forwarding, "w"); + + if (fp == NULL) + return -1; + + fprintf (fp, "1\n"); + + fclose (fp); + + return ipforward_ipv6 (); +} + +int +ipforward_ipv6_off () +{ + FILE *fp; + + fp = fopen (proc_ipv6_forwarding, "w"); + + if (fp == NULL) + return -1; + + fprintf (fp, "0\n"); + + fclose (fp); + + return ipforward_ipv6 (); +} +#endif /* HAVE_IPV6 */ diff --git a/zebra/ipforward_solaris.c b/zebra/ipforward_solaris.c new file mode 100644 index 0000000..99b0e1a --- /dev/null +++ b/zebra/ipforward_solaris.c @@ -0,0 +1,77 @@ +/* + * ipforward value get function for solaris. + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "memory.h" + +int +ipforward () +{ + int fd, ret; + int ipforwarding = 0; + char forward[] = "ip_forwarding"; + char *buf; + struct strioctl si; + + buf = (char *) XMALLOC (MTYPE_TMP, sizeof forward + 1); + strcpy (buf, forward); + + fd = open ("/dev/ip", O_RDWR); + if (fd < 0) { + free (buf); + /* need logging here */ + /* "I can't get ipforwarding value because can't open /dev/ip" */ + return -1; + } + + si.ic_cmd = ND_GET; + si.ic_timout = 0; + si.ic_len = strlen (buf) + 1; + si.ic_dp = (caddr_t) buf; + + ret = ioctl (fd, I_STR, &si); + close (fd); + + if (ret < 0) { + free (buf); + /* need logging here */ + /* can't get ipforwarding value : ioctl failed */ + return -1; + } + + ipforwarding = atoi (buf); + free (buf); + return ipforwarding; +} + +int +ipforward_on () +{ + return 0; +} + +int +ipforward_off () +{ + return 0; +} diff --git a/zebra/ipforward_sysctl.c b/zebra/ipforward_sysctl.c new file mode 100644 index 0000000..828eb86 --- /dev/null +++ b/zebra/ipforward_sysctl.c @@ -0,0 +1,146 @@ +/* IP forward control by sysctl function. + * Copyright (C) 1997, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#ifdef NRL +#include +#endif /* NRL */ + +#include "log.h" + +#define MIB_SIZ 4 + +/* IPv4 forwarding control MIB. */ +int mib[MIB_SIZ] = +{ + CTL_NET, + PF_INET, + IPPROTO_IP, + IPCTL_FORWARDING +}; + +int +ipforward () +{ + int len; + int ipforwarding = 0; + + len = sizeof ipforwarding; + if (sysctl (mib, MIB_SIZ, &ipforwarding, &len, 0, 0) < 0) + { + zlog_warn ("Can't get ipforwarding value"); + return -1; + } + return ipforwarding; +} + +int +ipforward_on () +{ + int len; + int ipforwarding = 1; + + len = sizeof ipforwarding; + if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) + { + zlog_warn ("Can't set ipforwarding on"); + return -1; + } + return ipforwarding; +} + +int +ipforward_off () +{ + int len; + int ipforwarding = 0; + + len = sizeof ipforwarding; + if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) + { + zlog_warn ("Can't set ipforwarding on"); + return -1; + } + return ipforwarding; +} + +#ifdef HAVE_IPV6 + +/* IPv6 forwarding control MIB. */ +int mib_ipv6[MIB_SIZ] = +{ + CTL_NET, + PF_INET6, +#if defined(KAME) || (defined(__bsdi__) && _BSDI_VERSION >= 199802 ) || defined(NRL) + IPPROTO_IPV6, + IPV6CTL_FORWARDING +#else /* NOT KAME */ + IPPROTO_IP, + IP6CTL_FORWARDING +#endif /* KAME */ +}; + +int +ipforward_ipv6 () +{ + int len; + int ip6forwarding = 0; + + len = sizeof ip6forwarding; + if (sysctl (mib_ipv6, MIB_SIZ, &ip6forwarding, &len, 0, 0) < 0) + { + zlog_warn ("can't get ip6forwarding value"); + return -1; + } + return ip6forwarding; +} + +int +ipforward_ipv6_on () +{ + int len; + int ip6forwarding = 1; + + len = sizeof ip6forwarding; + if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) + { + zlog_warn ("can't get ip6forwarding value"); + return -1; + } + return ip6forwarding; +} + +int +ipforward_ipv6_off () +{ + int len; + int ip6forwarding = 0; + + len = sizeof ip6forwarding; + if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) + { + zlog_warn ("can't get ip6forwarding value"); + return -1; + } + return ip6forwarding; +} +#endif /* HAVE_IPV6 */ diff --git a/zebra/irdp.h b/zebra/irdp.h new file mode 100644 index 0000000..d93d913 --- /dev/null +++ b/zebra/irdp.h @@ -0,0 +1,149 @@ +/* ICMP Router Discovery Messages + * Copyright (C) 1997, 2000 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* + * This file is modified and completed for the Zebra IRDP implementation + * by Robert Olsson, Swedish University of Agricultural Sciences + */ + +#ifndef _IRDP_H +#define _IRDP_H + +#define TRUE 1 +#define FALSE 0 + +/* ICMP Messages */ +#ifndef ICMP_ROUTERADVERT +#define ICMP_ROUTERADVERT 9 +#endif /* ICMP_ROUTERADVERT */ + +#ifndef ICMP_ROUTERSOLICIT +#define ICMP_ROUTERSOLICIT 10 +#endif /* ICMP_ROUTERSOLICT */ + +/* Multicast groups */ +#ifndef INADDR_ALLHOSTS_GROUP +#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */ +#endif /* INADDR_ALLHOSTS_GROUP */ + +#ifndef INADDR_ALLRTRS_GROUP +#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */ +#endif /* INADDR_ALLRTRS_GROUP */ + +/* Default irdp packet interval */ +#define IRDP_DEFAULT_INTERVAL 300 + +/* Router constants from RFC1256 */ +#define MAX_INITIAL_ADVERT_INTERVAL 16 +#define MAX_INITIAL_ADVERTISEMENTS 3 +#define MAX_RESPONSE_DELAY 2 + +#define IRDP_MAXADVERTINTERVAL 600 +#define IRDP_MINADVERTINTERVAL 450 /* 0.75*600 */ +#define IRDP_LIFETIME 1350 /* 3*450 */ +#define IRDP_PREFERENCE 0 + +#define ICMP_MINLEN 8 + +#define IRDP_LAST_ADVERT_MESSAGES 2 /* The last adverts with Holdtime 0 */ + +#define IRDP_RX_BUF 1500 + +/* + Comments comes from RFC1256 ICMP Router Discovery Messages. + + The IP destination address to be used for multicast Router + Advertisements sent from the interface. The only permissible + values are the all-systems multicast address, 224.0.0.1, or the + limited-broadcast address, 255.255.255.255. (The all-systems + address is preferred wherever possible, i.e., on any link where + all listening hosts support IP multicast.) + + Default: 224.0.0.1 if the router supports IP multicast on the + interface, else 255.255.255.255 + + The maximum time allowed between sending multicast Router + Advertisements from the interface, in seconds. Must be no less + than 4 seconds and no greater than 1800 seconds. + + Default: 600 seconds + + The minimum time allowed between sending unsolicited multicast + Router Advertisements from the interface, in seconds. Must be no + less than 3 seconds and no greater than MaxAdvertisementInterval. + + Default: 0.75 * MaxAdvertisementInterval + + The value to be placed in the Lifetime field of Router + Advertisements sent from the interface, in seconds. Must be no + less than MaxAdvertisementInterval and no greater than 9000 + seconds. + + Default: 3 * MaxAdvertisementInterval + + The preferability of the address as a default router address, + relative to other router addresses on the same subnet. A 32-bit, + signed, twos-complement integer, with higher values meaning more + preferable. The minimum value (hex 80000000) is used to indicate + that the address, even though it may be advertised, is not to be + used by neighboring hosts as a default router address. + + Default: 0 +*/ + +struct irdp_interface +{ + unsigned long MaxAdvertInterval; + unsigned long MinAdvertInterval; + unsigned long Preference; + + u_int32_t flags; + +#define IF_ACTIVE (1<<0) /* ICMP Active */ +#define IF_BROADCAST (1<<1) /* 255.255.255.255 */ +#define IF_SOLICIT (1<<2) /* Solicit active */ +#define IF_DEBUG_MESSAGES (1<<3) +#define IF_DEBUG_PACKET (1<<4) +#define IF_DEBUG_MISC (1<<5) +#define IF_SHUTDOWN (1<<6) + + struct interface *ifp; + struct thread *t_advertise; + unsigned long irdp_sent; + u_int16_t Lifetime; + + list AdvPrefList; + +}; + +struct Adv +{ + struct in_addr ip; + int pref; +}; + + +#endif /* _IRDP_H */ + + + + + diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c new file mode 100644 index 0000000..4f63f78 --- /dev/null +++ b/zebra/irdp_interface.c @@ -0,0 +1,784 @@ +/* + * + * Copyright (C) 2000 Robert Olsson. + * Swedish University of Agricultural Sciences + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* + * This work includes work with the following copywrite: + * + * Copyright (C) 1997, 2000 Kunihiro Ishiguro + * + */ + +/* + * Thanks to Jens Låås at Swedish University of Agricultural Sciences + * for reviewing and tests. + */ + + +#include + +#ifdef HAVE_IRDP + +#include "if.h" +#include "vty.h" +#include "sockunion.h" +#include "prefix.h" +#include "command.h" +#include "memory.h" +#include "stream.h" +#include "ioctl.h" +#include "connected.h" +#include "log.h" +#include "zclient.h" +#include "thread.h" +#include "zebra/interface.h" +#include "zebra/rtadv.h" +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/irdp.h" +#include +#include "if.h" +#include "sockunion.h" +#include "log.h" + + +/* Master of threads. */ +extern struct thread_master *master; + +int in_cksum (void *ptr, int nbytes); +extern int irdp_sock; +int irdp_send_thread(struct thread *t_advert); +char *inet_2a(u_int32_t a, char *b); +void irdp_advert_off(struct interface *ifp); + + +char b1[16], b2[16], b3[16], b4[16]; /* For inet_2a */ + +struct prefix *irdp_get_prefix(struct interface *ifp) +{ + listnode node; + struct connected *ifc; + + if(ifp->connected) + for (node = listhead (ifp->connected); node; nextnode (node)) { + ifc = getdata (node); + return ifc->address; + } + return NULL; +} + +/* Join to the add/leave multicast group. */ +int if_group (struct interface *ifp, + int sock, + u_int32_t group, + int add_leave) +{ + struct zebra_if *zi; + struct ip_mreq m; + struct prefix *p; + int ret; + + zi = ifp->info; + + bzero (&m, sizeof (m)); + m.imr_multiaddr.s_addr = htonl (group); + p = irdp_get_prefix(ifp); + + if(!p) { + zlog_warn ("IRDP: can't get address for %s", ifp->name); + return 1; + } + + m.imr_interface = p->u.prefix4; + + ret = setsockopt (sock, IPPROTO_IP, add_leave, + (char *) &m, sizeof (struct ip_mreq)); + if (ret < 0) + zlog_warn ("IRDP: %s can't setsockopt %s: %s", + add_leave == IP_ADD_MEMBERSHIP? "join group":"leave group", + inet_2a(group, b1), + strerror (errno)); + + return ret; +} + +int if_add_group (struct interface *ifp) +{ + struct zebra_if *zi= ifp->info; + struct irdp_interface *irdp = &zi->irdp; + int ret; + + ret = if_group (ifp, irdp_sock, INADDR_ALLRTRS_GROUP, IP_ADD_MEMBERSHIP); + if (ret < 0) { + return ret; + } + + if(irdp->flags & IF_DEBUG_MISC ) + zlog_warn("IRDP: Adding group %s for %s\n", + inet_2a(htonl(INADDR_ALLRTRS_GROUP), b1), + ifp->name); + return 0; +} +int if_drop_group (struct interface *ifp) +{ + struct zebra_if *zi= ifp->info; + struct irdp_interface *irdp = &zi->irdp; + int ret; + + ret = if_group (ifp, irdp_sock, INADDR_ALLRTRS_GROUP, IP_DROP_MEMBERSHIP); + if (ret < 0) + return ret; + + if(irdp->flags & IF_DEBUG_MISC) + zlog_warn("IRDP: Leaving group %s for %s\n", + inet_2a(htonl(INADDR_ALLRTRS_GROUP), b1), + ifp->name); + return 0; +} + +struct interface *get_iflist_ifp(int idx) +{ + listnode node; + struct interface *ifp; + + for (node = listhead (iflist); node; nextnode (node)) { + ifp = getdata (node); + if(ifp->ifindex == idx) return ifp; + } + return NULL; +} + +void +if_set_defaults(struct interface *ifp) +{ + struct zebra_if *zi=ifp->info; + struct irdp_interface *irdp=&zi->irdp; + + irdp->MaxAdvertInterval = IRDP_MAXADVERTINTERVAL; + irdp->MinAdvertInterval = IRDP_MINADVERTINTERVAL; + irdp->Preference = IRDP_PREFERENCE; + irdp->Lifetime = IRDP_LIFETIME; +} + + +struct Adv *Adv_new () +{ + struct Adv *new; + new = XMALLOC (MTYPE_TMP, sizeof (struct Adv)); + memset (new, 0, sizeof (struct Adv)); + return new; +} + +void Adv_free (struct Adv *adv) +{ + XFREE (MTYPE_TMP, adv); +} + +void irdp_if_start(struct interface *ifp, int multicast, int set_defaults) +{ + struct zebra_if *zi= ifp->info; + struct irdp_interface *irdp = &zi->irdp; + listnode node; + u_int32_t timer, seed; + + if (irdp->flags & IF_ACTIVE ) { + zlog_warn("IRDP: Interface is already active %s\n", ifp->name); + return; + } + irdp->flags |= IF_ACTIVE; + + if(!multicast) + irdp->flags |= IF_BROADCAST; + + if_add_update(ifp); + + if (! (ifp->flags & IFF_UP)) { + zlog_warn("IRDP: Interface is down %s\n", ifp->name); + } + + /* Shall we cancel if_start if if_add_group fails? */ + + if( multicast) { + if_add_group(ifp); + + if (! (ifp->flags & (IFF_MULTICAST|IFF_ALLMULTI))) { + zlog_warn("IRDP: Interface not multicast enabled %s\n", ifp->name); + } + } + + if(set_defaults) + if_set_defaults(ifp); + + irdp->irdp_sent = 0; + + /* The spec suggests this for randomness */ + + seed = 0; + if( ifp->connected) + for (node = listhead (ifp->connected); node; nextnode (node)) + { + struct connected *ifc = getdata (node); + seed = ifc->address->u.prefix4.s_addr; + } + + srandom(seed); + timer = (random () % IRDP_DEFAULT_INTERVAL) + 1; + + irdp->AdvPrefList = list_new(); + irdp->AdvPrefList->del = (void *) Adv_free; /* Destructor */ + + + /* And this for startup. Speed limit from 1991 :-). But it's OK*/ + + if(irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS && + timer > MAX_INITIAL_ADVERT_INTERVAL ) + timer= MAX_INITIAL_ADVERT_INTERVAL; + + + if(irdp->flags & IF_DEBUG_MISC) + zlog_warn("IRDP: Init timer for %s set to %u\n", + ifp->name, + timer); + + irdp->t_advertise = thread_add_timer(master, + irdp_send_thread, + ifp, + timer); +} + +void irdp_if_stop(struct interface *ifp) +{ + struct zebra_if *zi=ifp->info; + struct irdp_interface *irdp=&zi->irdp; + + if (irdp == NULL) { + zlog_warn ("Interface %s structure is NULL", ifp->name); + return; + } + + if (! (irdp->flags & IF_ACTIVE )) { + zlog_warn("Interface is not active %s\n", ifp->name); + return; + } + + if(! (irdp->flags & IF_BROADCAST)) + if_drop_group(ifp); + + irdp_advert_off(ifp); + + list_delete(irdp->AdvPrefList); + irdp->AdvPrefList=NULL; + + irdp->flags = 0; +} + + +void irdp_if_shutdown(struct interface *ifp) +{ + struct zebra_if *zi= ifp->info; + struct irdp_interface *irdp = &zi->irdp; + + if (irdp->flags & IF_SHUTDOWN ) { + zlog_warn("IRDP: Interface is already shutdown %s\n", ifp->name); + return; + } + + irdp->flags |= IF_SHUTDOWN; + irdp->flags &= ~IF_ACTIVE; + + if(! (irdp->flags & IF_BROADCAST)) + if_drop_group(ifp); + + /* Tell the hosts we are out of service */ + irdp_advert_off(ifp); +} + +void irdp_if_no_shutdown(struct interface *ifp) +{ + struct zebra_if *zi= ifp->info; + struct irdp_interface *irdp = &zi->irdp; + + if (! (irdp->flags & IF_SHUTDOWN )) { + zlog_warn("IRDP: Interface is not shutdown %s\n", ifp->name); + return; + } + + irdp->flags &= ~IF_SHUTDOWN; + + irdp_if_start(ifp, irdp->flags & IF_BROADCAST? FALSE : TRUE, FALSE); + +} + + +/* Write configuration to user */ + +void irdp_config_write (struct vty *vty, struct interface *ifp) +{ + struct zebra_if *zi=ifp->info; + struct irdp_interface *irdp=&zi->irdp; + struct Adv *adv; + listnode node; + + if(irdp->flags & IF_ACTIVE || irdp->flags & IF_SHUTDOWN) { + + if( irdp->flags & IF_SHUTDOWN) + vty_out (vty, " ip irdp shutdown %s", VTY_NEWLINE); + + if( irdp->flags & IF_BROADCAST) + vty_out (vty, " ip irdp broadcast%s", VTY_NEWLINE); + else + vty_out (vty, " ip irdp multicast%s", VTY_NEWLINE); + + vty_out (vty, " ip irdp preference %ld%s", + irdp->Preference, VTY_NEWLINE); + + for (node = listhead (irdp->AdvPrefList); node; nextnode (node)) { + adv = getdata (node); + vty_out (vty, " ip irdp address %s preference %d%s", + inet_2a(adv->ip.s_addr, b1), + adv->pref, + VTY_NEWLINE); + + } + + vty_out (vty, " ip irdp holdtime %d%s", + irdp->Lifetime, VTY_NEWLINE); + + vty_out (vty, " ip irdp minadvertinterval %ld%s", + irdp->MinAdvertInterval, VTY_NEWLINE); + + vty_out (vty, " ip irdp maxadvertinterval %ld%s", + irdp->MaxAdvertInterval, VTY_NEWLINE); + + } +} + + +DEFUN (ip_irdp_multicast, + ip_irdp_multicast_cmd, + "ip irdp multicast", + IP_STR + "ICMP Router discovery on this interface using multicast\n") +{ + struct interface *ifp; + + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + irdp_if_start(ifp, TRUE, TRUE); + return CMD_SUCCESS; +} + +DEFUN (ip_irdp_broadcast, + ip_irdp_broadcast_cmd, + "ip irdp broadcast", + IP_STR + "ICMP Router discovery on this interface using broadcast\n") +{ + struct interface *ifp; + + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + irdp_if_start(ifp, FALSE, TRUE); + return CMD_SUCCESS; +} + +DEFUN (ip_irdp_no, + ip_irdp_cmd_no, + "no ip irdp", + IP_STR + "Disable ICMP Router discovery on this interface\n") +{ + struct interface *ifp; + + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + irdp_if_stop(ifp); + return CMD_SUCCESS; +} + +DEFUN (ip_irdp_shutdown, + ip_irdp_shutdown_cmd, + "ip irdp shutdown", + IP_STR + "ICMP Router discovery shutdown on this interface\n") +{ + struct interface *ifp; + + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + irdp_if_shutdown(ifp); + return CMD_SUCCESS; +} + +DEFUN (ip_irdp_no_shutdown, + ip_irdp_no_shutdown_cmd, + "no ip irdp shutdown", + IP_STR + "ICMP Router discovery no shutdown on this interface\n") +{ + struct interface *ifp; + + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + irdp_if_no_shutdown(ifp); + return CMD_SUCCESS; +} + +DEFUN (ip_irdp_holdtime, + ip_irdp_holdtime_cmd, + "ip irdp holdtime <0-9000>", + IP_STR + "ICMP Router discovery on this interface\n" + "Set holdtime value\n" + "Holdtime value in seconds. Default is 1800 seconds\n") +{ + struct interface *ifp; + struct zebra_if *zi; + struct irdp_interface *irdp; + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + zi=ifp->info; + irdp=&zi->irdp; + + irdp->Lifetime = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN (ip_irdp_minadvertinterval, + ip_irdp_minadvertinterval_cmd, + "ip irdp minadvertinterval <3-1800>", + IP_STR + "ICMP Router discovery on this interface\n" + "Set minimum time between advertisement\n" + "Minimum advertisement interval in seconds\n") +{ + struct interface *ifp; + struct zebra_if *zi; + struct irdp_interface *irdp; + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + zi=ifp->info; + irdp=&zi->irdp; + + if( atoi(argv[0]) <= irdp->MaxAdvertInterval) { + irdp->MinAdvertInterval = atoi(argv[0]); + + return CMD_SUCCESS; + } + + vty_out (vty, "ICMP warning maxadvertinterval is greater or equal than minadvertinterval%s", + VTY_NEWLINE); + + vty_out (vty, "Please correct!%s", + VTY_NEWLINE); + return CMD_WARNING; +} + +DEFUN (ip_irdp_maxadvertinterval, + ip_irdp_maxadvertinterval_cmd, + "ip irdp maxadvertinterval <4-1800>", + IP_STR + "ICMP Router discovery on this interface\n" + "Set maximum time between advertisement\n" + "Maximum advertisement interval in seconds\n") +{ + struct interface *ifp; + struct zebra_if *zi; + struct irdp_interface *irdp; + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + zi=ifp->info; + irdp=&zi->irdp; + + + if( irdp->MinAdvertInterval <= atoi(argv[0]) ) { + irdp->MaxAdvertInterval = atoi(argv[0]); + + return CMD_SUCCESS; + } + + vty_out (vty, "ICMP warning maxadvertinterval is greater or equal than minadvertinterval%s", + VTY_NEWLINE); + + vty_out (vty, "Please correct!%s", + VTY_NEWLINE); + return CMD_WARNING; +} + +DEFUN (ip_irdp_preference, + ip_irdp_preference_cmd, + + /* DEFUN needs to be fixed for negative ranages... + Be positive for now. :-) + + "ip irdp preference <-2147483648-2147483647>", + */ + + + "ip irdp preference <0-2147483647>", + IP_STR + "ICMP Router discovery on this interface\n" + "Set default preference level for this interface\n" + "Preference level\n") +{ + struct interface *ifp; + struct zebra_if *zi; + struct irdp_interface *irdp; + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + zi=ifp->info; + irdp=&zi->irdp; + + irdp->Preference = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN (ip_irdp_address_preference, + ip_irdp_address_preference_cmd, + "ip irdp address A.B.C.D preference <0-2147483647>", + IP_STR + "Alter ICMP Router discovery preference this interface\n" + "Specify IRDP non-default preference to advertise\n" + "Set IRDP address for advertise\n" + "Preference level\n") +{ + listnode node; + struct in_addr ip; + int pref; + int ret; + struct interface *ifp; + struct zebra_if *zi; + struct irdp_interface *irdp; + struct Adv *adv; + + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + zi=ifp->info; + irdp=&zi->irdp; + + ret = inet_aton(argv[0], &ip); + if(!ret) return CMD_WARNING; + + pref = atoi(argv[1]); + + for (node = listhead (irdp->AdvPrefList); node; nextnode (node)) { + adv = getdata (node); + if(adv->ip.s_addr == ip.s_addr) return CMD_SUCCESS; + } + + adv = Adv_new(); + adv->ip = ip; + adv->pref = pref; + listnode_add(irdp->AdvPrefList, adv); + + return CMD_SUCCESS; + +} + +DEFUN (ip_irdp_address_preference_no, + ip_irdp_address_preference_cmd_no, + "no ip irdp address A.B.C.D preference <0-2147483647>", + IP_STR + "Alter ICMP Router discovery preference this interface\n" + "Removes IRDP non-default preference\n" + "Select IRDP address\n" + "Old preference level\n") +{ + listnode node; + struct in_addr ip; + int pref; + int ret; + struct interface *ifp; + struct zebra_if *zi; + struct irdp_interface *irdp; + struct Adv *adv; + + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + zi=ifp->info; + irdp=&zi->irdp; + + ret = inet_aton(argv[0], &ip); + if(!ret) return CMD_WARNING; + + pref = atoi(argv[1]); + + for (node = listhead (irdp->AdvPrefList); node; nextnode (node)) { + adv = getdata (node); + if(adv->ip.s_addr == ip.s_addr ) { + listnode_delete(irdp->AdvPrefList, adv); + break; + } + } + + return CMD_SUCCESS; + + +} + +DEFUN (ip_irdp_debug_messages, + ip_irdp_debug_messages_cmd, + "ip irdp debug messages", + IP_STR + "ICMP Router discovery debug Averts. and Solicits (short)\n") +{ + struct interface *ifp; + struct zebra_if *zi; + struct irdp_interface *irdp; + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + zi=ifp->info; + irdp=&zi->irdp; + + irdp->flags |= IF_DEBUG_MESSAGES; + + return CMD_SUCCESS; +} + +DEFUN (ip_irdp_debug_misc, + ip_irdp_debug_misc_cmd, + "ip irdp debug misc", + IP_STR + "ICMP Router discovery debug Averts. and Solicits (short)\n") +{ + struct interface *ifp; + struct zebra_if *zi; + struct irdp_interface *irdp; + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + zi=ifp->info; + irdp=&zi->irdp; + + irdp->flags |= IF_DEBUG_MISC; + + return CMD_SUCCESS; +} + +DEFUN (ip_irdp_debug_packet, + ip_irdp_debug_packet_cmd, + "ip irdp debug packet", + IP_STR + "ICMP Router discovery debug Averts. and Solicits (short)\n") +{ + struct interface *ifp; + struct zebra_if *zi; + struct irdp_interface *irdp; + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + zi=ifp->info; + irdp=&zi->irdp; + + irdp->flags |= IF_DEBUG_PACKET; + + return CMD_SUCCESS; +} + + +DEFUN (ip_irdp_debug_disable, + ip_irdp_debug_disable_cmd, + "ip irdp debug disable", + IP_STR + "ICMP Router discovery debug Averts. and Solicits (short)\n") +{ + struct interface *ifp; + struct zebra_if *zi; + struct irdp_interface *irdp; + ifp = (struct interface *) vty->index; + if(!ifp) { + return CMD_WARNING; + } + + zi=ifp->info; + irdp=&zi->irdp; + + irdp->flags &= ~IF_DEBUG_PACKET; + irdp->flags &= ~IF_DEBUG_MESSAGES; + irdp->flags &= ~IF_DEBUG_MISC; + + return CMD_SUCCESS; +} + +void +irdp_if_init () +{ + install_element (INTERFACE_NODE, &ip_irdp_broadcast_cmd); + install_element (INTERFACE_NODE, &ip_irdp_multicast_cmd); + install_element (INTERFACE_NODE, &ip_irdp_cmd_no); + install_element (INTERFACE_NODE, &ip_irdp_shutdown_cmd); + install_element (INTERFACE_NODE, &ip_irdp_no_shutdown_cmd); + install_element (INTERFACE_NODE, &ip_irdp_holdtime_cmd); + install_element (INTERFACE_NODE, &ip_irdp_maxadvertinterval_cmd); + install_element (INTERFACE_NODE, &ip_irdp_minadvertinterval_cmd); + install_element (INTERFACE_NODE, &ip_irdp_preference_cmd); + install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd); + install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd_no); + + install_element (INTERFACE_NODE, &ip_irdp_debug_messages_cmd); + install_element (INTERFACE_NODE, &ip_irdp_debug_misc_cmd); + install_element (INTERFACE_NODE, &ip_irdp_debug_packet_cmd); + install_element (INTERFACE_NODE, &ip_irdp_debug_disable_cmd); +} + +#endif /* HAVE_IRDP */ diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c new file mode 100644 index 0000000..720163c --- /dev/null +++ b/zebra/irdp_main.c @@ -0,0 +1,347 @@ +/* + * + * Copyright (C) 2000 Robert Olsson. + * Swedish University of Agricultural Sciences + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* + * This work includes work with the following copywrite: + * + * Copyright (C) 1997, 2000 Kunihiro Ishiguro + * + */ + +/* + * Thanks to Jens Låås at Swedish University of Agricultural Sciences + * for reviewing and tests. + */ + + +#include + +#ifdef HAVE_IRDP + +#include "if.h" +#include "vty.h" +#include "sockunion.h" +#include "prefix.h" +#include "command.h" +#include "memory.h" +#include "stream.h" +#include "ioctl.h" +#include "connected.h" +#include "log.h" +#include "zclient.h" +#include "thread.h" +#include "zebra/interface.h" +#include "zebra/rtadv.h" +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/irdp.h" +#include + +#include "if.h" +#include "sockunion.h" +#include "log.h" + +/* GLOBAL VARS */ + +/* Master of threads. */ +extern struct thread_master *master; +struct thread *t_irdp_raw; + +/* Timer interval of irdp. */ +int irdp_timer_interval = IRDP_DEFAULT_INTERVAL; + +int irdp_read_raw(struct thread *r); +int in_cksum (void *ptr, int nbytes); +extern int irdp_sock; +void send_packet(struct interface *ifp, + struct stream *s, + u_int32_t dst, + struct prefix *p, + u_int32_t ttl); + +void irdp_if_init (); + +char * +inet_2a(u_int32_t a, char *b) +{ + sprintf(b, "%u.%u.%u.%u", + (a ) & 0xFF, + (a>> 8) & 0xFF, + (a>>16) & 0xFF, + (a>>24) & 0xFF); + return b; +} + +int +irdp_sock_init (void) +{ + int ret, i; + + irdp_sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (irdp_sock < 0) { + zlog_warn ("IRDP: can't create irdp socket %s", strerror(errno)); + return irdp_sock; + }; + + i = 1; + ret = setsockopt (irdp_sock, IPPROTO_IP, IP_TTL, + (void *) &i, sizeof (i)); + if (ret < 0) { + zlog_warn ("IRDP: can't do irdp sockopt %s", strerror(errno)); + return ret; + }; + + i = 1; + ret = setsockopt (irdp_sock, IPPROTO_IP, IP_PKTINFO, + (void *) &i, sizeof (i)); + if (ret < 0) { + zlog_warn ("IRDP: can't do irdp sockopt %s", strerror(errno)); + return ret; + }; + + t_irdp_raw = thread_add_read (master, irdp_read_raw, NULL, irdp_sock); + + return irdp_sock; +} + + +int get_pref(struct irdp_interface *irdp, struct prefix *p) +{ + listnode node; + struct Adv *adv; + + /* Use default preference or use the override pref */ + + if( irdp->AdvPrefList == NULL ) return irdp->Preference; + + for (node = listhead (irdp->AdvPrefList); node; nextnode (node)) { + adv = getdata (node); + if( p->u.prefix4.s_addr == adv->ip.s_addr ) + return adv->pref; + } + return irdp->Preference; +} + +/* Make ICMP Router Advertisement Message. */ +int make_advertisement_packet (struct interface *ifp, + struct prefix *p, + struct stream *s) +{ + struct zebra_if *zi=ifp->info; + struct irdp_interface *irdp=&zi->irdp; + int size; + int pref; + u_int16_t checksum; + + pref = get_pref(irdp, p); + + stream_putc (s, ICMP_ROUTERADVERT); /* Type. */ + stream_putc (s, 0); /* Code. */ + stream_putw (s, 0); /* Checksum. */ + stream_putc (s, 1); /* Num address. */ + stream_putc (s, 2); /* Address Entry Size. */ + + if(irdp->flags & IF_SHUTDOWN) + stream_putw (s, 0); + else + stream_putw (s, irdp->Lifetime); + + stream_putl (s, htonl(p->u.prefix4.s_addr)); /* Router address. */ + stream_putl (s, pref); + + /* in_cksum return network byte order value */ + size = 16; + checksum = in_cksum (s->data, size); + stream_putw_at (s, 2, htons(checksum)); + + return size; +} + +void irdp_send(struct interface *ifp, + struct prefix *p, + struct stream *s) +{ + struct zebra_if *zi=ifp->info; + struct irdp_interface *irdp=&zi->irdp; + u_int32_t dst; + u_int32_t ttl=1; + + if (! (ifp->flags & IFF_UP)) return; + + if (irdp->flags & IF_BROADCAST) + dst =INADDR_BROADCAST ; + else + dst = htonl(INADDR_ALLHOSTS_GROUP); + + if(irdp->flags & IF_DEBUG_MESSAGES) + zlog_warn("IRDP: TX Advert on %s %s/%d Holdtime=%d Preference=%d", + ifp->name, + inet_ntoa(p->u.prefix4), + p->prefixlen, + irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime, + get_pref(irdp, p)); + + send_packet (ifp, s, dst, p, ttl); +} + +void irdp_advertisement (struct interface *ifp, + struct prefix *p) +{ + struct stream *s; + s = stream_new (128); + make_advertisement_packet (ifp, p, s); + irdp_send(ifp, p, s); +} + +int irdp_send_thread(struct thread *t_advert) +{ + u_int32_t timer, tmp; + struct interface *ifp = THREAD_ARG (t_advert); + struct zebra_if *zi=ifp->info; + struct irdp_interface *irdp=&zi->irdp; + struct prefix *p; + listnode node; + struct connected *ifc; + + irdp->flags &= ~IF_SOLICIT; + + if(ifp->connected) + for (node = listhead (ifp->connected); node; nextnode (node)) { + ifc = getdata (node); + + p = ifc->address; + + irdp_advertisement(ifp, p); + irdp->irdp_sent++; + + } + + tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval; + timer = (random () % tmp ) + 1; + timer = irdp->MinAdvertInterval + timer; + + if(irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS && + timer > MAX_INITIAL_ADVERT_INTERVAL ) + timer= MAX_INITIAL_ADVERT_INTERVAL; + + if(irdp->flags & IF_DEBUG_MISC) + zlog_warn("IRDP: New timer for %s set to %u\n", ifp->name, timer); + + irdp->t_advertise = thread_add_timer(master, irdp_send_thread, ifp, timer); + return 0; +} + +void irdp_advert_off(struct interface *ifp) +{ + struct zebra_if *zi=ifp->info; + struct irdp_interface *irdp=&zi->irdp; + listnode node; + int i; + struct connected *ifc; + struct prefix *p; + + if(irdp->t_advertise) thread_cancel(irdp->t_advertise); + irdp->t_advertise = NULL; + + if(ifp->connected) + for (node = listhead (ifp->connected); node; nextnode (node)) { + ifc = getdata (node); + + p = ifc->address; + + /* Output some packets with Lifetime 0 + we should add a wait... + */ + + for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++) { + + irdp->irdp_sent++; + irdp_advertisement(ifp, p); + } + } +} + + +void process_solicit (struct interface *ifp) +{ + struct zebra_if *zi=ifp->info; + struct irdp_interface *irdp=&zi->irdp; + u_int32_t timer; + + /* When SOLICIT is active we reject further incoming solicits + this keeps down the answering rate so we don't have think + about DoS attacks here. */ + + if( irdp->flags & IF_SOLICIT) return; + + irdp->flags |= IF_SOLICIT; + if(irdp->t_advertise) thread_cancel(irdp->t_advertise); + irdp->t_advertise = NULL; + + timer = (random () % MAX_RESPONSE_DELAY) + 1; + + irdp->t_advertise = thread_add_timer(master, + irdp_send_thread, + ifp, + timer); +} + +void irdp_finish() +{ + + listnode node; + struct interface *ifp; + struct zebra_if *zi; + struct irdp_interface *irdp; + + zlog_warn("IRDP: Received shutdown notification."); + + for (node = listhead (iflist); node; node = nextnode (node)) + { + ifp = getdata(node); + zi= ifp->info; + if(! zi) continue; + irdp = &zi->irdp; + if(!irdp) continue; + + if(irdp->flags & IF_ACTIVE ) { + irdp->flags |= IF_SHUTDOWN; + irdp_advert_off(ifp); + } + } +} + +void irdp_init() +{ + irdp_sock_init(); + irdp_if_init (); +} + + + +#endif /* HAVE_IRDP */ + + + + diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c new file mode 100644 index 0000000..156de4d --- /dev/null +++ b/zebra/irdp_packet.c @@ -0,0 +1,365 @@ +/* + * + * Copyright (C) 2000 Robert Olsson. + * Swedish University of Agricultural Sciences + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* + * This work includes work with the following copywrite: + * + * Copyright (C) 1997, 2000 Kunihiro Ishiguro + * + */ + +/* + * Thanks to Jens Låås at Swedish University of Agricultural Sciences + * for reviewing and tests. + */ + + +#include + + +#ifdef HAVE_IRDP + +#include "if.h" +#include "vty.h" +#include "sockunion.h" +#include "prefix.h" +#include "command.h" +#include "memory.h" +#include "stream.h" +#include "ioctl.h" +#include "connected.h" +#include "log.h" +#include "zclient.h" +#include "thread.h" +#include "zebra/interface.h" +#include "zebra/rtadv.h" +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/irdp.h" +#include +#include "if.h" +#include "sockunion.h" +#include "log.h" + + + +/* GLOBAL VARS */ + +int irdp_sock; +char b1[16], b2[16], b3[16], b4[16]; /* For inet_2a */ + + +extern struct thread_master *master; +extern struct thread *t_irdp_raw; +extern struct interface *get_iflist_ifp(int idx); +int in_cksum (void *ptr, int nbytes); +void process_solicit (struct interface *ifp); + +void parse_irdp_packet(char *p, + int len, + struct interface *ifp) +{ + struct ip *ip = (struct ip *)p ; + struct icmphdr *icmp; + struct in_addr src; + int ip_hlen, ip_len; + struct zebra_if *zi; + struct irdp_interface *irdp; + + zi = ifp->info; + if(!zi) return; + + irdp = &zi->irdp; + if(!irdp) return; + + ip_hlen = ip->ip_hl*4; + ip_len = ntohs(ip->ip_len); + len = len - ip_hlen; + src = ip->ip_src; + + if(ip_len < ICMP_MINLEN) { + zlog_err ("IRDP: RX ICMP packet too short from %s\n", + inet_ntoa (src)); + return; + } + + /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen + + len of IP-header) 14+20 */ + + if(ip_len > IRDP_RX_BUF-34) { + zlog_err ("IRDP: RX ICMP packet too long from %s\n", + inet_ntoa (src)); + return; + } + + + if (in_cksum (ip, ip_len)) { + zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored", + inet_ntoa (src)); + return; + } + + icmp = (struct icmphdr *) (p+ip_hlen); + + + /* Handle just only IRDP */ + + if( icmp->type == ICMP_ROUTERADVERT); + else if( icmp->type == ICMP_ROUTERSOLICIT); + else return; + + + if (icmp->code != 0) { + zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code, silently ignored", + icmp->type, + inet_ntoa (src)); + return; + } + + if(ip->ip_dst.s_addr == INADDR_BROADCAST && + irdp->flags & IF_BROADCAST); + + else if ( ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP && + ! (irdp->flags & IF_BROADCAST)); + + else { /* ERROR */ + + zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %s\n", + inet_ntoa (src), + ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP? + "multicast" : inet_ntoa(ip->ip_dst), + ifp->name, + irdp->flags & IF_BROADCAST? + "broadcast" : "multicast"); + + zlog_warn ("IRDP: Please correct settings\n"); + return; + } + + switch (icmp->type) + { + case ICMP_ROUTERADVERT: + break; + + case ICMP_ROUTERSOLICIT: + + if(irdp->flags & IF_DEBUG_MESSAGES) + zlog_warn ("IRDP: RX Solicit on %s from %s\n", + ifp->name, + inet_ntoa (src)); + + process_solicit(ifp); + break; + + default: + zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored", + icmp->type, + inet_ntoa (src)); + } +} + +int irdp_recvmsg (int sock, + u_char *buf, + int size, + int *ifindex) +{ + struct msghdr msg; + struct iovec iov; + struct cmsghdr *ptr; + char adata[1024]; + int ret; + + msg.msg_name = (void *)0; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = (void *) adata; + msg.msg_controllen = sizeof adata; + + iov.iov_base = buf; + iov.iov_len = size; + + ret = recvmsg (sock, &msg, 0); + if (ret < 0) { + zlog_warn("IRDP: recvmsg: read error %s", strerror(errno)); + return ret; + } + + if (msg.msg_flags & MSG_TRUNC) { + zlog_warn("IRDP: recvmsg: truncated message"); + return ret; + } + if (msg.msg_flags & MSG_CTRUNC) { + zlog_warn("IRDP: recvmsg: truncated control message"); + return ret; + } + + for (ptr = CMSG_FIRSTHDR(&msg); ptr ; ptr = CMSG_NXTHDR(&msg, ptr)) + if (ptr->cmsg_level == SOL_IP && ptr->cmsg_type == IP_PKTINFO) + { + struct in_pktinfo *pktinfo; + pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr); + *ifindex = pktinfo->ipi_ifindex; + } + return ret; +} + +int irdp_read_raw(struct thread *r) +{ + struct interface *ifp; + struct zebra_if *zi; + struct irdp_interface *irdp; + char buf[IRDP_RX_BUF]; + int ret, ifindex; + + int irdp_sock = THREAD_FD (r); + t_irdp_raw = thread_add_read (master, irdp_read_raw, NULL, irdp_sock); + + ret = irdp_recvmsg (irdp_sock, buf, IRDP_RX_BUF, &ifindex); + + if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret); + + ifp = get_iflist_ifp(ifindex); + if(! ifp ) return ret; + + zi= ifp->info; + if(! zi ) return ret; + + irdp = &zi->irdp; + if(! irdp ) return ret; + + if(! (irdp->flags & IF_ACTIVE)) { + + if(irdp->flags & IF_DEBUG_MISC) + zlog_warn("IRDP: RX ICMP for disabled interface %s\n", + ifp->name); + return 0; + } + + if(irdp->flags & IF_DEBUG_PACKET) { + int i; + zlog_warn("IRDP: RX (idx %d) ", ifindex); + for(i=0; i < ret; i++) zlog_warn( "IRDP: RX %x ", buf[i]&0xFF); + } + + parse_irdp_packet(buf, ret, ifp); + return ret; +} + +void send_packet(struct interface *ifp, + struct stream *s, + u_int32_t dst, + struct prefix *p, + u_int32_t ttl) +{ + static struct sockaddr_in sockdst = {AF_INET}; + struct ip *ip; + struct icmphdr *icmp; + struct msghdr *msg; + struct cmsghdr *cmsg; + struct iovec iovector; + char msgbuf[256]; + char buf[256]; + struct in_pktinfo *pktinfo; + u_long src; + int on; + + if (! (ifp->flags & IFF_UP)) return; + + if(!p) src = ntohl(p->u.prefix4.s_addr); + else src = 0; /* Is filled in */ + + ip = (struct ip *) buf; + ip->ip_hl = sizeof(struct ip) >> 2; + ip->ip_v = IPVERSION; + ip->ip_tos = 0xC0; + ip->ip_off = 0L; + ip->ip_p = 1; /* IP_ICMP */ + ip->ip_ttl = ttl; + ip->ip_src.s_addr = src; + ip->ip_dst.s_addr = dst; + icmp = (struct icmphdr *) (buf + 20); + + /* Merge IP header with icmp packet */ + + stream_get(icmp, s, s->putp); + + /* icmp->checksum is already calculated */ + ip->ip_len = sizeof(struct ip) + s->putp; + stream_free(s); + + on = 1; + if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL, + (char *) &on, sizeof(on)) < 0) + zlog_warn("sendto %s", strerror (errno)); + + + if(dst == INADDR_BROADCAST ) { + on = 1; + if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST, + (char *) &on, sizeof(on)) < 0) + zlog_warn("sendto %s", strerror (errno)); + } + + if(dst != INADDR_BROADCAST) { + on = 0; + if( setsockopt(irdp_sock,IPPROTO_IP, IP_MULTICAST_LOOP, + (char *)&on,sizeof(on)) < 0) + zlog_warn("sendto %s", strerror (errno)); + } + + bzero(&sockdst,sizeof(sockdst)); + sockdst.sin_family=AF_INET; + sockdst.sin_addr.s_addr = dst; + + cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr)); + cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo); + cmsg->cmsg_level = SOL_IP; + cmsg->cmsg_type = IP_PKTINFO; + pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg); + pktinfo->ipi_ifindex = ifp->ifindex; + pktinfo->ipi_spec_dst.s_addr = src; + pktinfo->ipi_addr.s_addr = src; + + iovector.iov_base = (void *) buf; + iovector.iov_len = ip->ip_len; + msg = (struct msghdr *) msgbuf; + msg->msg_name = &sockdst; + msg->msg_namelen = sizeof(sockdst); + msg->msg_iov = &iovector; + msg->msg_iovlen = 1; + msg->msg_control = cmsg; + msg->msg_controllen = cmsg->cmsg_len; + + if (sendmsg(irdp_sock, msg, 0) < 0) { + zlog_warn("sendto %s", strerror (errno)); + } + /* printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */ +} + + +#endif /* HAVE_IRDP */ + + + diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c new file mode 100644 index 0000000..23b2153 --- /dev/null +++ b/zebra/kernel_netlink.c @@ -0,0 +1,20 @@ +/* Kernel communication using netlink interface. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c new file mode 100644 index 0000000..3b15548 --- /dev/null +++ b/zebra/kernel_socket.c @@ -0,0 +1,812 @@ +/* Kernel communication using routing socket. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "prefix.h" +#include "sockunion.h" +#include "connected.h" +#include "memory.h" +#include "ioctl.h" +#include "log.h" +#include "str.h" +#include "table.h" +#include "rib.h" + +#include "zebra/interface.h" +#include "zebra/zserv.h" +#include "zebra/debug.h" + +/* Socket length roundup function. */ +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + +/* And this macro is wrapper for handling sa_len. */ +#ifdef HAVE_SA_LEN +#define WRAPUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len) +#else +#define WRAPUP(X) ROUNDUP(sizeof (struct sockaddr)) +#endif /* HAVE_SA_LEN */ + +/* Routing socket message types. */ +struct message rtm_type_str[] = +{ + {RTM_ADD, "RTM_ADD"}, + {RTM_DELETE, "RTM_DELETE"}, + {RTM_CHANGE, "RTM_CHANGE"}, + {RTM_GET, "RTM_GET"}, + {RTM_LOSING, "RTM_LOSING"}, + {RTM_REDIRECT, "RTM_REDIRECT"}, + {RTM_MISS, "RTM_MISS"}, + {RTM_LOCK, "RTM_LOCK"}, + {RTM_OLDADD, "RTM_OLDADD"}, + {RTM_OLDDEL, "RTM_OLDDEL"}, + {RTM_RESOLVE, "RTM_RESOLVE"}, + {RTM_NEWADDR, "RTM_NEWADDR"}, + {RTM_DELADDR, "RTM_DELADDR"}, + {RTM_IFINFO, "RTM_IFINFO"}, +#ifdef RTM_OIFINFO + {RTM_OIFINFO, "RTM_OIFINFO"}, +#endif /* RTM_OIFINFO */ +#ifdef RTM_NEWMADDR + {RTM_NEWMADDR, "RTM_NEWMADDR"}, +#endif /* RTM_NEWMADDR */ +#ifdef RTM_DELMADDR + {RTM_DELMADDR, "RTM_DELMADDR"}, +#endif /* RTM_DELMADDR */ +#ifdef RTM_IFANNOUNCE + {RTM_IFANNOUNCE, "RTM_IFANNOUNCE"}, +#endif /* RTM_IFANNOUNCE */ + {0, NULL} +}; + +struct message rtm_flag_str[] = +{ + {RTF_UP, "UP"}, + {RTF_GATEWAY, "GATEWAY"}, + {RTF_HOST, "HOST"}, + {RTF_REJECT, "REJECT"}, + {RTF_DYNAMIC, "DYNAMIC"}, + {RTF_MODIFIED, "MODIFIED"}, + {RTF_DONE, "DONE"}, +#ifdef RTF_MASK + {RTF_MASK, "MASK"}, +#endif /* RTF_MASK */ + {RTF_CLONING, "CLONING"}, + {RTF_XRESOLVE, "XRESOLVE"}, + {RTF_LLINFO, "LLINFO"}, + {RTF_STATIC, "STATIC"}, + {RTF_BLACKHOLE, "BLACKHOLE"}, + {RTF_PROTO1, "PROTO1"}, + {RTF_PROTO2, "PROTO2"}, +#ifdef RTF_PRCLONING + {RTF_PRCLONING, "PRCLONING"}, +#endif /* RTF_PRCLONING */ +#ifdef RTF_WASCLONED + {RTF_WASCLONED, "WASCLONED"}, +#endif /* RTF_WASCLONED */ +#ifdef RTF_PROTO3 + {RTF_PROTO3, "PROTO3"}, +#endif /* RTF_PROTO3 */ +#ifdef RTF_PINNED + {RTF_PINNED, "PINNED"}, +#endif /* RTF_PINNED */ +#ifdef RTF_LOCAL + {RTF_LOCAL, "LOCAL"}, +#endif /* RTF_LOCAL */ +#ifdef RTF_BROADCAST + {RTF_BROADCAST, "BROADCAST"}, +#endif /* RTF_BROADCAST */ +#ifdef RTF_MULTICAST + {RTF_MULTICAST, "MULTICAST"}, +#endif /* RTF_MULTICAST */ + {0, NULL} +}; + +/* Kernel routing update socket. */ +int routing_sock = -1; + +/* Yes I'm checking ugly routing socket behavior. */ +/* #define DEBUG */ + +/* Supported address family check. */ +static int +af_check (int family) +{ + if (family == AF_INET) + return 1; +#ifdef HAVE_IPV6 + if (family == AF_INET6) + return 1; +#endif /* HAVE_IPV6 */ + return 0; +} + +/* Dump routing table flag for debug purpose. */ +void +rtm_flag_dump (int flag) +{ + struct message *mes; + static char buf[BUFSIZ]; + + buf[0] = '0'; + for (mes = rtm_flag_str; mes->key != 0; mes++) + { + if (mes->key & flag) + { + strlcat (buf, mes->str, BUFSIZ); + strlcat (buf, " ", BUFSIZ); + } + } + zlog_info ("Kernel: %s", buf); +} + +#ifdef RTM_IFANNOUNCE +/* Interface adding function */ +int +ifan_read (struct if_announcemsghdr *ifan) +{ + struct interface *ifp; + + ifp = if_lookup_by_index (ifan->ifan_index); + if (ifp == NULL && ifan->ifan_what == IFAN_ARRIVAL) + { + /* Create Interface */ + ifp = if_get_by_name (ifan->ifan_name); + ifp->ifindex = ifan->ifan_index; + + if_add_update (ifp); + } + else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE) + { + if_delete_update (ifp); + if_delete (ifp); + } + + if_get_flags (ifp); + if_get_mtu (ifp); + if_get_metric (ifp); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("interface %s index %d", ifp->name, ifp->ifindex); + + return 0; +} +#endif /* RTM_IFANNOUNCE */ + +/* Interface adding function called from interface_list. */ +int +ifm_read (struct if_msghdr *ifm) +{ + struct interface *ifp; + struct sockaddr_dl *sdl = NULL; + + sdl = (struct sockaddr_dl *)(ifm + 1); + + /* Use sdl index. */ + ifp = if_lookup_by_index (ifm->ifm_index); + + if (ifp == NULL) + { + /* Check interface's address.*/ + if (! (ifm->ifm_addrs & RTA_IFP)) + { + zlog_warn ("There must be RTA_IFP address for ifindex %d\n", + ifm->ifm_index); + return -1; + } + + ifp = if_create (); + + strncpy (ifp->name, sdl->sdl_data, sdl->sdl_nlen); + ifp->ifindex = ifm->ifm_index; + ifp->flags = ifm->ifm_flags; +#if defined(__bsdi__) + if_kvm_get_mtu (ifp); +#else + if_get_mtu (ifp); +#endif /* __bsdi__ */ + if_get_metric (ifp); + + /* Fetch hardware address. */ + if (sdl->sdl_family != AF_LINK) + { + zlog_warn ("sockaddr_dl->sdl_family is not AF_LINK"); + return -1; + } + memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl)); + + if_add_update (ifp); + } + else + { + /* There is a case of promisc, allmulti flag modification. */ + if (if_is_up (ifp)) + { + ifp->flags = ifm->ifm_flags; + if (! if_is_up (ifp)) + if_down (ifp); + } + else + { + ifp->flags = ifm->ifm_flags; + if (if_is_up (ifp)) + if_up (ifp); + } + } + +#ifdef HAVE_NET_RT_IFLIST + ifp->stats = ifm->ifm_data; +#endif /* HAVE_NET_RT_IFLIST */ + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("interface %s index %d", ifp->name, ifp->ifindex); + + return 0; +} + +/* Address read from struct ifa_msghdr. */ +void +ifam_read_mesg (struct ifa_msghdr *ifm, + union sockunion *addr, + union sockunion *mask, + union sockunion *dest) +{ + caddr_t pnt, end; + + pnt = (caddr_t)(ifm + 1); + end = ((caddr_t)ifm) + ifm->ifam_msglen; + +#define IFAMADDRGET(X,R) \ + if (ifm->ifam_addrs & (R)) \ + { \ + int len = WRAPUP(pnt); \ + if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \ + memcpy ((caddr_t)(X), pnt, len); \ + pnt += len; \ + } +#define IFAMMASKGET(X,R) \ + if (ifm->ifam_addrs & (R)) \ + { \ + int len = WRAPUP(pnt); \ + if ((X) != NULL) \ + memcpy ((caddr_t)(X), pnt, len); \ + pnt += len; \ + } + + /* Be sure structure is cleared */ + memset (mask, 0, sizeof (union sockunion)); + memset (addr, 0, sizeof (union sockunion)); + memset (dest, 0, sizeof (union sockunion)); + + /* We fetch each socket variable into sockunion. */ + IFAMADDRGET (NULL, RTA_DST); + IFAMADDRGET (NULL, RTA_GATEWAY); + IFAMMASKGET (mask, RTA_NETMASK); + IFAMADDRGET (NULL, RTA_GENMASK); + IFAMADDRGET (NULL, RTA_IFP); + IFAMADDRGET (addr, RTA_IFA); + IFAMADDRGET (NULL, RTA_AUTHOR); + IFAMADDRGET (dest, RTA_BRD); + + /* Assert read up end point matches to end point */ + if (pnt != end) + zlog_warn ("ifam_read() doesn't read all socket data"); +} + +/* Interface's address information get. */ +int +ifam_read (struct ifa_msghdr *ifam) +{ + struct interface *ifp; + union sockunion addr, mask, gate; + + /* Check does this interface exist or not. */ + ifp = if_lookup_by_index (ifam->ifam_index); + if (ifp == NULL) + { + zlog_warn ("no interface for index %d", ifam->ifam_index); + return -1; + } + + /* Allocate and read address information. */ + ifam_read_mesg (ifam, &addr, &mask, &gate); + + /* Check interface flag for implicit up of the interface. */ + if_refresh (ifp); + + /* Add connected address. */ + switch (sockunion_family (&addr)) + { + case AF_INET: + if (ifam->ifam_type == RTM_NEWADDR) + connected_add_ipv4 (ifp, 0, &addr.sin.sin_addr, + ip_masklen (mask.sin.sin_addr), + &gate.sin.sin_addr, NULL); + else + connected_delete_ipv4 (ifp, 0, &addr.sin.sin_addr, + ip_masklen (mask.sin.sin_addr), + &gate.sin.sin_addr, NULL); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + /* Unset interface index from link-local address when IPv6 stack + is KAME. */ + if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr)) + SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0); + + if (ifam->ifam_type == RTM_NEWADDR) + connected_add_ipv6 (ifp, + &addr.sin6.sin6_addr, + ip6_masklen (mask.sin6.sin6_addr), + &gate.sin6.sin6_addr); + else + connected_delete_ipv6 (ifp, + &addr.sin6.sin6_addr, + ip6_masklen (mask.sin6.sin6_addr), + &gate.sin6.sin6_addr); + break; +#endif /* HAVE_IPV6 */ + default: + /* Unsupported family silently ignore... */ + break; + } + return 0; +} + +/* Interface function for reading kernel routing table information. */ +int +rtm_read_mesg (struct rt_msghdr *rtm, + union sockunion *dest, + union sockunion *mask, + union sockunion *gate) +{ + caddr_t pnt, end; + + /* Pnt points out socket data start point. */ + pnt = (caddr_t)(rtm + 1); + end = ((caddr_t)rtm) + rtm->rtm_msglen; + + /* rt_msghdr version check. */ + if (rtm->rtm_version != RTM_VERSION) + zlog (NULL, LOG_WARNING, + "Routing message version different %d should be %d." + "This may cause problem\n", rtm->rtm_version, RTM_VERSION); + +#define RTMADDRGET(X,R) \ + if (rtm->rtm_addrs & (R)) \ + { \ + int len = WRAPUP (pnt); \ + if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \ + memcpy ((caddr_t)(X), pnt, len); \ + pnt += len; \ + } +#define RTMMASKGET(X,R) \ + if (rtm->rtm_addrs & (R)) \ + { \ + int len = WRAPUP (pnt); \ + if ((X) != NULL) \ + memcpy ((caddr_t)(X), pnt, len); \ + pnt += len; \ + } + + /* Be sure structure is cleared */ + memset (dest, 0, sizeof (union sockunion)); + memset (gate, 0, sizeof (union sockunion)); + memset (mask, 0, sizeof (union sockunion)); + + /* We fetch each socket variable into sockunion. */ + RTMADDRGET (dest, RTA_DST); + RTMADDRGET (gate, RTA_GATEWAY); + RTMMASKGET (mask, RTA_NETMASK); + RTMADDRGET (NULL, RTA_GENMASK); + RTMADDRGET (NULL, RTA_IFP); + RTMADDRGET (NULL, RTA_IFA); + RTMADDRGET (NULL, RTA_AUTHOR); + RTMADDRGET (NULL, RTA_BRD); + + /* If there is netmask information set it's family same as + destination family*/ + if (rtm->rtm_addrs & RTA_NETMASK) + mask->sa.sa_family = dest->sa.sa_family; + + /* Assert read up to the end of pointer. */ + if (pnt != end) + zlog (NULL, LOG_WARNING, "rtm_read() doesn't read all socket data."); + + return rtm->rtm_flags; +} + +void +rtm_read (struct rt_msghdr *rtm) +{ + int flags; + u_char zebra_flags; + union sockunion dest, mask, gate; + + zebra_flags = 0; + + /* Discard self send message. */ + if (rtm->rtm_type != RTM_GET + && (rtm->rtm_pid == pid || rtm->rtm_pid == old_pid)) + return; + + /* Read destination and netmask and gateway from rtm message + structure. */ + flags = rtm_read_mesg (rtm, &dest, &mask, &gate); + +#ifdef RTF_CLONED /*bsdi, netbsd 1.6*/ + if (flags & RTF_CLONED) + return; +#endif +#ifdef RTF_WASCLONED /*freebsd*/ + if (flags & RTF_WASCLONED) + return; +#endif + + if ((rtm->rtm_type == RTM_ADD) && ! (flags & RTF_UP)) + return; + + /* This is connected route. */ + if (! (flags & RTF_GATEWAY)) + return; + + if (flags & RTF_PROTO1) + SET_FLAG (zebra_flags, ZEBRA_FLAG_SELFROUTE); + + /* This is persistent route. */ + if (flags & RTF_STATIC) + SET_FLAG (zebra_flags, ZEBRA_FLAG_STATIC); + + if (dest.sa.sa_family == AF_INET) + { + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefix = dest.sin.sin_addr; + if (flags & RTF_HOST) + p.prefixlen = IPV4_MAX_PREFIXLEN; + else + p.prefixlen = ip_masklen (mask.sin.sin_addr); + + if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD) + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, + &p, &gate.sin.sin_addr, 0, 0, 0, 0); + else + rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, + &p, &gate.sin.sin_addr, 0, 0); + } +#ifdef HAVE_IPV6 + if (dest.sa.sa_family == AF_INET6) + { + struct prefix_ipv6 p; + unsigned int ifindex = 0; + + p.family = AF_INET6; + p.prefix = dest.sin6.sin6_addr; + if (flags & RTF_HOST) + p.prefixlen = IPV6_MAX_PREFIXLEN; + else + p.prefixlen = ip6_masklen (mask.sin6.sin6_addr); + +#ifdef KAME + if (IN6_IS_ADDR_LINKLOCAL (&gate.sin6.sin6_addr)) + { + ifindex = IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr); + SET_IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr, 0); + } +#endif /* KAME */ + + if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD) + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, + &p, &gate.sin6.sin6_addr, ifindex, 0); + else + rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, + &p, &gate.sin6.sin6_addr, ifindex, 0); + } +#endif /* HAVE_IPV6 */ +} + +/* Interface function for the kernel routing table updates. Support + for RTM_CHANGE will be needed. */ +int +rtm_write (int message, + union sockunion *dest, + union sockunion *mask, + union sockunion *gate, + unsigned int index, + int zebra_flags, + int metric) +{ + int ret; + caddr_t pnt; + struct interface *ifp; + struct sockaddr_in tmp_gate; +#ifdef HAVE_IPV6 + struct sockaddr_in6 tmp_gate6; +#endif /* HAVE_IPV6 */ + + /* Sequencial number of routing message. */ + static int msg_seq = 0; + + /* Struct of rt_msghdr and buffer for storing socket's data. */ + struct + { + struct rt_msghdr rtm; + char buf[512]; + } msg; + + memset (&tmp_gate, 0, sizeof (struct sockaddr_in)); + tmp_gate.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + tmp_gate.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + +#ifdef HAVE_IPV6 + memset (&tmp_gate6, 0, sizeof (struct sockaddr_in6)); + tmp_gate6.sin6_family = AF_INET6; +#ifdef SIN6_LEN + tmp_gate6.sin6_len = sizeof (struct sockaddr_in6); +#endif /* SIN6_LEN */ +#endif /* HAVE_IPV6 */ + + if (routing_sock < 0) + return ZEBRA_ERR_EPERM; + + /* Clear and set rt_msghdr values */ + memset (&msg, 0, sizeof (struct rt_msghdr)); + msg.rtm.rtm_version = RTM_VERSION; + msg.rtm.rtm_type = message; + msg.rtm.rtm_seq = msg_seq++; + msg.rtm.rtm_addrs = RTA_DST; + msg.rtm.rtm_addrs |= RTA_GATEWAY; + msg.rtm.rtm_flags = RTF_UP; + msg.rtm.rtm_index = index; + + if (metric != 0) + { + msg.rtm.rtm_rmx.rmx_hopcount = metric; + msg.rtm.rtm_inits |= RTV_HOPCOUNT; + } + + ifp = if_lookup_by_index (index); + + if (gate && message == RTM_ADD) + msg.rtm.rtm_flags |= RTF_GATEWAY; + + if (! gate && message == RTM_ADD && ifp && + (ifp->flags & IFF_POINTOPOINT) == 0) + msg.rtm.rtm_flags |= RTF_CLONING; + + /* If no protocol specific gateway is specified, use link + address for gateway. */ + if (! gate) + { + if (!ifp) + { + zlog_warn ("no gateway found for interface index %d", index); + return -1; + } + gate = (union sockunion *) & ifp->sdl; + } + + if (mask) + msg.rtm.rtm_addrs |= RTA_NETMASK; + else if (message == RTM_ADD) + msg.rtm.rtm_flags |= RTF_HOST; + + /* Tagging route with flags */ + msg.rtm.rtm_flags |= (RTF_PROTO1); + + /* Additional flags. */ + if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) + msg.rtm.rtm_flags |= RTF_BLACKHOLE; + +#ifdef HAVE_SIN_LEN +#define SOCKADDRSET(X,R) \ + if (msg.rtm.rtm_addrs & (R)) \ + { \ + int len = ROUNDUP ((X)->sa.sa_len); \ + memcpy (pnt, (caddr_t)(X), len); \ + pnt += len; \ + } +#else +#define SOCKADDRSET(X,R) \ + if (msg.rtm.rtm_addrs & (R)) \ + { \ + int len = ROUNDUP (sizeof((X)->sa)); \ + memcpy (pnt, (caddr_t)(X), len); \ + pnt += len; \ + } +#endif /* HAVE_SIN_LEN */ + + pnt = (caddr_t) msg.buf; + + /* Write each socket data into rtm message buffer */ + SOCKADDRSET (dest, RTA_DST); + SOCKADDRSET (gate, RTA_GATEWAY); + SOCKADDRSET (mask, RTA_NETMASK); + + msg.rtm.rtm_msglen = pnt - (caddr_t) &msg; + + ret = write (routing_sock, &msg, msg.rtm.rtm_msglen); + + if (ret != msg.rtm.rtm_msglen) + { + if (errno == EEXIST) + return ZEBRA_ERR_RTEXIST; + if (errno == ENETUNREACH) + return ZEBRA_ERR_RTUNREACH; + + zlog_warn ("write : %s (%d)", strerror (errno), errno); + return -1; + } + return 0; +} + + +#include "thread.h" +#include "zebra/zserv.h" + +extern struct thread_master *master; + +/* For debug purpose. */ +void +rtmsg_debug (struct rt_msghdr *rtm) +{ + char *type = "Unknown"; + struct message *mes; + + for (mes = rtm_type_str; mes->str; mes++) + if (mes->key == rtm->rtm_type) + { + type = mes->str; + break; + } + + zlog_info ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, type); + rtm_flag_dump (rtm->rtm_flags); + zlog_info ("Kernel: message seq %d", rtm->rtm_seq); + zlog_info ("Kernel: pid %d", rtm->rtm_pid); +} + +/* This is pretty gross, better suggestions welcome -- mhandler */ +#ifndef RTAX_MAX +#ifdef RTA_NUMBITS +#define RTAX_MAX RTA_NUMBITS +#else +#define RTAX_MAX 8 +#endif /* RTA_NUMBITS */ +#endif /* RTAX_MAX */ + +/* Kernel routing table and interface updates via routing socket. */ +int +kernel_read (struct thread *thread) +{ + int sock; + int nbytes; + struct rt_msghdr *rtm; + + union + { + /* Routing information. */ + struct + { + struct rt_msghdr rtm; + struct sockaddr addr[RTAX_MAX]; + } r; + + /* Interface information. */ + struct + { + struct if_msghdr ifm; + struct sockaddr addr[RTAX_MAX]; + } im; + + /* Interface address information. */ + struct + { + struct ifa_msghdr ifa; + struct sockaddr addr[RTAX_MAX]; + } ia; + +#ifdef RTM_IFANNOUNCE + /* Interface arrival/departure */ + struct + { + struct if_announcemsghdr ifan; + struct sockaddr addr[RTAX_MAX]; + } ian; +#endif /* RTM_IFANNOUNCE */ + + } buf; + + /* Fetch routing socket. */ + sock = THREAD_FD (thread); + + nbytes= read (sock, &buf, sizeof buf); + + if (nbytes <= 0) + { + if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN) + zlog_warn ("routing socket error: %s", strerror (errno)); + return 0; + } + + thread_add_read (master, kernel_read, NULL, sock); + +#ifdef DEBUG + rtmsg_debug (&buf.r.rtm); +#endif /* DEBUG */ + + rtm = &buf.r.rtm; + + switch (rtm->rtm_type) + { + case RTM_ADD: + case RTM_DELETE: + rtm_read (rtm); + break; + case RTM_IFINFO: + ifm_read (&buf.im.ifm); + break; + case RTM_NEWADDR: + case RTM_DELADDR: + ifam_read (&buf.ia.ifa); + break; +#ifdef RTM_IFANNOUNCE + case RTM_IFANNOUNCE: + ifan_read (&buf.ian.ifan); + break; +#endif /* RTM_IFANNOUNCE */ + default: + break; + } + return 0; +} + +/* Make routing socket. */ +void +routing_socket () +{ + routing_sock = socket (AF_ROUTE, SOCK_RAW, 0); + + if (routing_sock < 0) + { + zlog_warn ("Can't init kernel routing socket"); + return; + } + + if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0) + zlog_warn ("Can't set O_NONBLOCK to routing socket"); + + /* kernel_read needs rewrite. */ + thread_add_read (master, kernel_read, NULL, routing_sock); +} + +/* Exported interface function. This function simply calls + routing_socket (). */ +void +kernel_init () +{ + routing_socket (); +} diff --git a/zebra/main.c b/zebra/main.c new file mode 100644 index 0000000..844cc08 --- /dev/null +++ b/zebra/main.c @@ -0,0 +1,322 @@ +/* + * zebra daemon main routine. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "version.h" +#include "getopt.h" +#include "command.h" +#include "thread.h" +#include "filter.h" +#include "memory.h" +#include "prefix.h" +#include "log.h" + +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/debug.h" +#include "zebra/rib.h" + +/* Master of threads. */ +struct thread_master *master; + +/* process id. */ +pid_t old_pid; +pid_t pid; + +/* Route retain mode flag. */ +int retain_mode = 0; + +/* Don't delete kernel route. */ +int keep_kernel_mode = 0; + +/* Command line options. */ +struct option longopts[] = +{ + { "batch", no_argument, NULL, 'b'}, + { "daemon", no_argument, NULL, 'd'}, + { "keep_kernel", no_argument, NULL, 'k'}, + { "log_mode", no_argument, NULL, 'l'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "help", no_argument, NULL, 'h'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "retain", no_argument, NULL, 'r'}, + { "version", no_argument, NULL, 'v'}, + { 0 } +}; + +/* Default configuration file path. */ +char config_current[] = DEFAULT_CONFIG_FILE; +char config_default[] = SYSCONFDIR DEFAULT_CONFIG_FILE; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_ZEBRA_PID; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\n\ +Daemon which manages kernel routing table management and \ +redistribution between different routing protocols.\n\n\ +-b, --batch Runs in batch mode\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-k, --keep_kernel Don't delete old routes which installed by zebra.\n\ +-l, --log_mode Set verbose log mode flag\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-r, --retain When program terminates, retain added route by zebra.\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + + exit (status); +} + +/* SIGHUP handler. */ +void +sighup (int sig) +{ + zlog_info ("SIGHUP received"); + + /* Reload of config file. */ + ; +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ + /* Decrared in rib.c */ + void rib_close (); + + zlog_info ("Terminating on signal"); + + if (!retain_mode) + rib_close (); +#ifdef HAVE_IRDP + irdp_finish(); +#endif + + exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ + zlog_rotate (NULL); +} + +/* Signale wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigint); + signal_set (SIGPIPE, SIG_IGN); + signal_set (SIGUSR1, sigusr1); +} + +/* Main startup routine. */ +int +main (int argc, char **argv) +{ + char *p; + char *vty_addr = NULL; + int vty_port = 0; + int batch_mode = 0; + int daemon_mode = 0; + char *config_file = NULL; + char *progname; + struct thread thread; + void rib_weed_tables (); + void zebra_vty_init (); + + /* Set umask before anything for security */ + umask (0027); + + /* preserve my name */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + zlog_default = openzlog (progname, ZLOG_STDOUT, ZLOG_ZEBRA, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + while (1) + { + int opt; + + opt = getopt_long (argc, argv, "bdklf:hA:P:rv", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'b': + batch_mode = 1; + case 'd': + daemon_mode = 1; + break; + case 'k': + keep_kernel_mode = 1; + break; + case 'l': + /* log_mode = 1; */ + break; + case 'f': + config_file = optarg; + break; + case 'A': + vty_addr = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'P': + vty_port = atoi (optarg); + break; + case 'r': + retain_mode = 1; + break; + case 'v': + print_version (progname); + exit (0); + break; + case 'h': + usage (progname, 0); + break; + default: + usage (progname, 1); + break; + } + } + + /* Make master thread emulator. */ + master = thread_master_create (); + + /* Vty related initialize. */ + signal_init (); + cmd_init (1); + vty_init (); + memory_init (); + + /* Zebra related initialize. */ + zebra_init (); + rib_init (); + zebra_if_init (); + zebra_debug_init (); + zebra_vty_init (); + access_list_init (); + rtadv_init (); +#ifdef HAVE_IRDP + irdp_init(); +#endif + + /* For debug purpose. */ + /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ + + /* Make kernel routing socket. */ + kernel_init (); + interface_list (); + route_read (); + + /* Sort VTY commands. */ + sort_node (); + +#ifdef HAVE_SNMP + zebra_snmp_init (); +#endif /* HAVE_SNMP */ + + /* Clean up self inserted route. */ + if (! keep_kernel_mode) + rib_sweep_route (); + + /* Configuration file read*/ + vty_read_config (config_file, config_current, config_default); + + /* Clean up rib. */ + rib_weed_tables (); + + /* Exit when zebra is working in batch mode. */ + if (batch_mode) + exit (0); + + /* Needed for BSD routing socket. */ + old_pid = getpid (); + + /* Daemonize. */ + if (daemon_mode) + daemon (0, 0); + + /* Output pid of zebra. */ + pid_output (pid_file); + + /* Needed for BSD routing socket. */ + pid = getpid (); + + /* Make vty server socket. */ + vty_serv_sock (vty_addr, + vty_port ? vty_port : ZEBRA_VTY_PORT, ZEBRA_VTYSH_PATH); + + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Not reached... */ + exit (0); +} diff --git a/zebra/mtu_kvm.c b/zebra/mtu_kvm.c new file mode 100644 index 0000000..3731dab --- /dev/null +++ b/zebra/mtu_kvm.c @@ -0,0 +1,97 @@ +/* MTU get using kvm_read. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include +#include +#include + +#include "if.h" + +/* get interface MTU to use kvm_read */ +void +if_kvm_get_mtu (struct interface *ifp) +{ + kvm_t *kvmd; + struct ifnet ifnet; + unsigned long ifnetaddr; + int len; + + char ifname[IFNAMSIZ]; + char tname[INTERFACE_NAMSIZ + 1]; + char buf[_POSIX2_LINE_MAX]; + + struct nlist nl[] = + { + {"_ifnet"}, + {""} + }; + + ifp->mtu = -1; + + kvmd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, buf); + + if (kvmd == NULL) + return ; + + kvm_nlist(kvmd, nl); + + ifnetaddr = nl[0].n_value; + + if (kvm_read(kvmd, ifnetaddr, (char *)&ifnetaddr, sizeof ifnetaddr) < 0) + { + kvm_close (kvmd); + return ; + } + + while(ifnetaddr != 0) + { + if (kvm_read (kvmd, ifnetaddr, (char *)&ifnet, sizeof ifnet) < 0) + { + kvm_close (kvmd); + return ; + } + + if (kvm_read (kvmd, (u_long)ifnet.if_name, ifname, IFNAMSIZ) < 0) + { + kvm_close (kvmd); + return ; + } + + len = snprintf (tname, INTERFACE_NAMSIZ + 1, + "%s%d", ifname, ifnet.if_unit); + + if (strncmp (tname, ifp->name, len) == 0) + break; + + ifnetaddr = (u_long)ifnet.if_next; + } + + kvm_close (kvmd); + + if (ifnetaddr == 0) + { + return ; + } + + ifp->mtu = ifnet.if_mtu; +} diff --git a/zebra/redistribute.c b/zebra/redistribute.c new file mode 100644 index 0000000..a3d4bad --- /dev/null +++ b/zebra/redistribute.c @@ -0,0 +1,410 @@ +/* Redistribution Handler + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "prefix.h" +#include "table.h" +#include "stream.h" +#include "zclient.h" +#include "linklist.h" +#include "log.h" + +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/debug.h" + +int +zebra_check_addr (struct prefix *p) +{ + if (p->family == AF_INET) + { + u_int32_t addr; + + addr = p->u.prefix4.s_addr; + addr = ntohl (addr); + + if (IPV4_NET127 (addr) || IN_CLASSD (addr)) + return 0; + } +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + { + if (IN6_IS_ADDR_LOOPBACK (&p->u.prefix6)) + return 0; + if (IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) + return 0; + } +#endif /* HAVE_IPV6 */ + return 1; +} + +int +is_default (struct prefix *p) +{ + if (p->family == AF_INET) + if (p->u.prefix4.s_addr == 0 && p->prefixlen == 0) + return 1; +#ifdef HAVE_IPV6 +#if 0 /* IPv6 default separation is now pending until protocol daemon + can handle that. */ + if (p->family == AF_INET6) + if (IN6_IS_ADDR_UNSPECIFIED (&p->u.prefix6) && p->prefixlen == 0) + return 1; +#endif /* 0 */ +#endif /* HAVE_IPV6 */ + return 0; +} + +void +zebra_redistribute_default (struct zserv *client) +{ + struct prefix_ipv4 p; + struct route_table *table; + struct route_node *rn; + struct rib *newrib; +#ifdef HAVE_IPV6 + struct prefix_ipv6 p6; +#endif /* HAVE_IPV6 */ + + + /* Lookup default route. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (table) + { + rn = route_node_lookup (table, (struct prefix *)&p); + if (rn) + { + for (newrib = rn->info; newrib; newrib = newrib->next) + if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) + && newrib->distance != DISTANCE_INFINITY) + zsend_ipv4_add_multipath (client, &rn->p, newrib); + route_unlock_node (rn); + } + } + +#ifdef HAVE_IPV6 + /* Lookup default route. */ + memset (&p6, 0, sizeof (struct prefix_ipv6)); + p6.family = AF_INET6; + + /* Lookup table. */ + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (table) + { + rn = route_node_lookup (table, (struct prefix *)&p6); + if (rn) + { + for (newrib = rn->info; newrib; newrib = newrib->next) + if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) + && newrib->distance != DISTANCE_INFINITY) + zsend_ipv6_add_multipath (client, &rn->p, newrib); + route_unlock_node (rn); + } + } +#endif /* HAVE_IPV6 */ +} + +/* Redistribute routes. */ +void +zebra_redistribute (struct zserv *client, int type) +{ + struct rib *newrib; + struct route_table *table; + struct route_node *rn; + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + for (newrib = rn->info; newrib; newrib = newrib->next) + if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) + && newrib->type == type + && newrib->distance != DISTANCE_INFINITY + && zebra_check_addr (&rn->p)) + zsend_ipv4_add_multipath (client, &rn->p, newrib); + +#ifdef HAVE_IPV6 + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + for (newrib = rn->info; newrib; newrib = newrib->next) + if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) + && newrib->type == type + && newrib->distance != DISTANCE_INFINITY + && zebra_check_addr (&rn->p)) + zsend_ipv6_add_multipath (client, &rn->p, newrib); +#endif /* HAVE_IPV6 */ +} + +extern list client_list; + +void +redistribute_add (struct prefix *p, struct rib *rib) +{ + listnode node; + struct zserv *client; + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + { + if (is_default (p)) + { + if (client->redist_default || client->redist[rib->type]) + { + if (p->family == AF_INET) + zsend_ipv4_add_multipath (client, p, rib); +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + zsend_ipv6_add_multipath (client, p, rib); +#endif /* HAVE_IPV6 */ + } + } + else if (client->redist[rib->type]) + { + if (p->family == AF_INET) + zsend_ipv4_add_multipath (client, p, rib); +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + zsend_ipv6_add_multipath (client, p, rib); +#endif /* HAVE_IPV6 */ + } + } +} + +void +redistribute_delete (struct prefix *p, struct rib *rib) +{ + listnode node; + struct zserv *client; + + /* Add DISTANCE_INFINITY check. */ + if (rib->distance == DISTANCE_INFINITY) + return; + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + { + if (is_default (p)) + { + if (client->redist_default || client->redist[rib->type]) + { + if (p->family == AF_INET) + zsend_ipv4_delete_multipath (client, p, rib); +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + zsend_ipv6_delete_multipath (client, p, rib); +#endif /* HAVE_IPV6 */ + } + } + else if (client->redist[rib->type]) + { + if (p->family == AF_INET) + zsend_ipv4_delete_multipath (client, p, rib); +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + zsend_ipv6_delete_multipath (client, p, rib); +#endif /* HAVE_IPV6 */ + } + } +} + +void +zebra_redistribute_add (int command, struct zserv *client, int length) +{ + int type; + + type = stream_getc (client->ibuf); + + switch (type) + { + case ZEBRA_ROUTE_KERNEL: + case ZEBRA_ROUTE_CONNECT: + case ZEBRA_ROUTE_STATIC: + case ZEBRA_ROUTE_RIP: + case ZEBRA_ROUTE_RIPNG: + case ZEBRA_ROUTE_OSPF: + case ZEBRA_ROUTE_OSPF6: + case ZEBRA_ROUTE_BGP: + if (! client->redist[type]) + { + client->redist[type] = 1; + zebra_redistribute (client, type); + } + break; + default: + break; + } +} + +void +zebra_redistribute_delete (int command, struct zserv *client, int length) +{ + int type; + + type = stream_getc (client->ibuf); + + switch (type) + { + case ZEBRA_ROUTE_KERNEL: + case ZEBRA_ROUTE_CONNECT: + case ZEBRA_ROUTE_STATIC: + case ZEBRA_ROUTE_RIP: + case ZEBRA_ROUTE_RIPNG: + case ZEBRA_ROUTE_OSPF: + case ZEBRA_ROUTE_OSPF6: + case ZEBRA_ROUTE_BGP: + client->redist[type] = 0; + break; + default: + break; + } +} + +void +zebra_redistribute_default_add (int command, struct zserv *client, int length) +{ + client->redist_default = 1; + zebra_redistribute_default (client); +} + +void +zebra_redistribute_default_delete (int command, struct zserv *client, + int length) +{ + client->redist_default = 0;; +} + +/* Interface up information. */ +void +zebra_interface_up_update (struct interface *ifp) +{ + listnode node; + struct zserv *client; + + if (IS_ZEBRA_DEBUG_EVENT) + zlog_info ("MESSAGE: ZEBRA_INTERFACE_UP %s", ifp->name); + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + zsend_interface_up (client, ifp); +} + +/* Interface down information. */ +void +zebra_interface_down_update (struct interface *ifp) +{ + listnode node; + struct zserv *client; + + if (IS_ZEBRA_DEBUG_EVENT) + zlog_info ("MESSAGE: ZEBRA_INTERFACE_DOWN %s", ifp->name); + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + zsend_interface_down (client, ifp); +} + +/* Interface information update. */ +void +zebra_interface_add_update (struct interface *ifp) +{ + listnode node; + struct zserv *client; + + if (IS_ZEBRA_DEBUG_EVENT) + zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADD %s", ifp->name); + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + if (client->ifinfo) + zsend_interface_add (client, ifp); +} + +void +zebra_interface_delete_update (struct interface *ifp) +{ + listnode node; + struct zserv *client; + + if (IS_ZEBRA_DEBUG_EVENT) + zlog_info ("MESSAGE: ZEBRA_INTERFACE_DELETE %s", ifp->name); + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + if (client->ifinfo) + zsend_interface_delete (client, ifp); +} + +/* Interface address addition. */ +void +zebra_interface_address_add_update (struct interface *ifp, + struct connected *ifc) +{ + listnode node; + struct zserv *client; + struct prefix *p; + char buf[BUFSIZ]; + + if (IS_ZEBRA_DEBUG_EVENT) + { + p = ifc->address; + zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s/%d on %s", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen, ifc->ifp->name); + } + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + zsend_interface_address_add (client, ifp, ifc); +} + +/* Interface address deletion. */ +void +zebra_interface_address_delete_update (struct interface *ifp, + struct connected *ifc) +{ + listnode node; + struct zserv *client; + struct prefix *p; + char buf[BUFSIZ]; + + if (IS_ZEBRA_DEBUG_EVENT) + { + p = ifc->address; + zlog_info ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s/%d on %s", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen, ifc->ifp->name); + } + + for (node = listhead (client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) + zsend_interface_address_delete (client, ifp, ifc); +} diff --git a/zebra/redistribute.h b/zebra/redistribute.h new file mode 100644 index 0000000..8b45cf3 --- /dev/null +++ b/zebra/redistribute.h @@ -0,0 +1,49 @@ +/* + * Redistribution Handler + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_REDISTRIBUTE_H +#define _ZEBRA_REDISTRIBUTE_H + +#include "table.h" + +void zebra_redistribute_add (int, struct zserv *, int); +void zebra_redistribute_delete (int, struct zserv *, int); + +void zebra_redistribute_default_add (int, struct zserv *, int); +void zebra_redistribute_default_delete (int, struct zserv *, int); + +void redistribute_add (struct prefix *, struct rib *); +void redistribute_delete (struct prefix *, struct rib *); + +void zebra_interface_up_update (struct interface *); +void zebra_interface_down_update (struct interface *); + +void zebra_interface_add_update (struct interface *); +void zebra_interface_delete_update (struct interface *); + +void zebra_interface_address_add_update (struct interface *, + struct connected *); +void zebra_interface_address_delete_update (struct interface *, + struct connected *c); + +#endif /* _ZEBRA_REDISTRIBUTE_H */ + diff --git a/zebra/rib.h b/zebra/rib.h new file mode 100644 index 0000000..5e9f13b --- /dev/null +++ b/zebra/rib.h @@ -0,0 +1,252 @@ +/* + * Routing Information Base header + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RIB_H +#define _ZEBRA_RIB_H + +#define DISTANCE_INFINITY 255 + +/* Routing information base. */ +struct rib +{ + /* Link list. */ + struct rib *next; + struct rib *prev; + + /* Type fo this route. */ + int type; + + /* Which routing table */ + int table; + + /* Distance. */ + u_char distance; + + /* Flags of this route. This flag's definition is in lib/zebra.h + ZEBRA_FLAG_* */ + u_char flags; + + /* Metric */ + u_int32_t metric; + + /* Uptime. */ + time_t uptime; + + /* Refrence count. */ + unsigned long refcnt; + + /* Nexthop information. */ + u_char nexthop_num; + u_char nexthop_active_num; + u_char nexthop_fib_num; + + struct nexthop *nexthop; +}; + +/* Static route information. */ +struct static_ipv4 +{ + /* For linked list. */ + struct static_ipv4 *prev; + struct static_ipv4 *next; + + /* Administrative distance. */ + u_char distance; + + /* Flag for this static route's type. */ + u_char type; +#define STATIC_IPV4_GATEWAY 1 +#define STATIC_IPV4_IFNAME 2 +#define STATIC_IPV4_BLACKHOLE 3 + + /* Nexthop value. */ + union + { + struct in_addr ipv4; + char *ifname; + } gate; +}; + +#ifdef HAVE_IPV6 +/* Static route information. */ +struct static_ipv6 +{ + /* For linked list. */ + struct static_ipv6 *prev; + struct static_ipv6 *next; + + /* Administrative distance. */ + u_char distance; + + /* Flag for this static route's type. */ + u_char type; +#define STATIC_IPV6_GATEWAY 1 +#define STATIC_IPV6_GATEWAY_IFNAME 2 +#define STATIC_IPV6_IFNAME 3 +#define STATIC_IPV6_BLACKHOLE 4 + + /* Nexthop value. */ + struct in6_addr ipv6; + char *ifname; +}; +#endif /* HAVE_IPV6 */ + +/* Nexthop structure. */ +struct nexthop +{ + struct nexthop *next; + struct nexthop *prev; + + u_char type; +#define NEXTHOP_TYPE_IFINDEX 1 /* Directly connected. */ +#define NEXTHOP_TYPE_IFNAME 2 /* Interface route. */ +#define NEXTHOP_TYPE_IPV4 3 /* IPv4 nexthop. */ +#define NEXTHOP_TYPE_IPV4_IFINDEX 4 /* IPv4 nexthop with ifindex. */ +#define NEXTHOP_TYPE_IPV4_IFNAME 5 /* IPv4 nexthop with ifname. */ +#define NEXTHOP_TYPE_IPV6 6 /* IPv6 nexthop. */ +#define NEXTHOP_TYPE_IPV6_IFINDEX 7 /* IPv6 nexthop with ifindex. */ +#define NEXTHOP_TYPE_IPV6_IFNAME 8 /* IPv6 nexthop with ifname. */ +#define NEXTHOP_TYPE_BLACKHOLE 9 /* Null0 nexthop. */ + + u_char flags; +#define NEXTHOP_FLAG_ACTIVE (1 << 0) /* This nexthop is alive. */ +#define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */ +#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */ + + /* Interface index. */ + unsigned int ifindex; + char *ifname; + + /* Nexthop address or interface name. */ + union + { + struct in_addr ipv4; +#ifdef HAVE_IPV6 + struct in6_addr ipv6; +#endif /* HAVE_IPV6*/ + } gate; + + /* Recursive lookup nexthop. */ + u_char rtype; + unsigned int rifindex; + union + { + struct in_addr ipv4; +#ifdef HAVE_IPV6 + struct in6_addr ipv6; +#endif /* HAVE_IPV6 */ + } rgate; + + struct nexthop *indirect; +}; + +/* Routing table instance. */ +struct vrf +{ + /* Identifier. This is same as routing table vector index. */ + u_int32_t id; + + /* Routing table name. */ + char *name; + + /* Description. */ + char *desc; + + /* FIB identifier. */ + u_char fib_id; + + /* Routing table. */ + struct route_table *table[AFI_MAX][SAFI_MAX]; + + /* Static route configuration. */ + struct route_table *stable[AFI_MAX][SAFI_MAX]; +}; + +struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int); +struct nexthop *nexthop_ifname_add (struct rib *, char *); +struct nexthop *nexthop_blackhole_add (struct rib *); +struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *); +#ifdef HAVE_IPV6 +struct nexthop *nexthop_ipv6_add (struct rib *, struct in6_addr *); +#endif /* HAVE_IPV6 */ + +struct vrf *vrf_lookup (u_int32_t); +struct route_table *vrf_table (afi_t afi, safi_t safi, u_int32_t id); +struct route_table *vrf_static_table (afi_t afi, safi_t safi, u_int32_t id); + +int +rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, + struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id, + u_int32_t, u_char); + +int +rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *); + +int +rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, + struct in_addr *gate, unsigned int ifindex, u_int32_t); + +struct rib * +rib_match_ipv4 (struct in_addr); + +struct rib * +rib_lookup_ipv4 (struct prefix_ipv4 *); + +void rib_update (); +void rib_sweep_route (); +void rib_close (); +void rib_init (); + +int +static_add_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname, + u_char distance, u_int32_t vrf_id); + +int +static_delete_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname, + u_char distance, u_int32_t vrf_id); + +#ifdef HAVE_IPV6 +int +rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, + struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id); + +int +rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, + struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id); + +struct rib *rib_lookup_ipv6 (struct in6_addr *); + +struct rib *rib_match_ipv6 (struct in6_addr *); + +extern struct route_table *rib_table_ipv6; + +int +static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, + char *ifname, u_char distance, u_int32_t vrf_id); + +int +static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, + char *ifname, u_char distance, u_int32_t vrf_id); + +#endif /* HAVE_IPV6 */ + +#endif /*_ZEBRA_RIB_H */ diff --git a/zebra/rt.h b/zebra/rt.h new file mode 100644 index 0000000..faaddab --- /dev/null +++ b/zebra/rt.h @@ -0,0 +1,40 @@ +/* + * kernel routing table update prototype. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RT_H +#define _ZEBRA_RT_H + +int kernel_add_ipv4 (struct prefix *, struct rib *); +int kernel_delete_ipv4 (struct prefix *, struct rib *); +int kernel_add_route (struct prefix_ipv4 *, struct in_addr *, int, int); +int kernel_address_add_ipv4 (struct interface *, struct connected *); +int kernel_address_delete_ipv4 (struct interface *, struct connected *); + +#ifdef HAVE_IPV6 +int kernel_add_ipv6 (struct prefix *, struct rib *); +int kernel_delete_ipv6 (struct prefix *, struct rib *); +int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, + unsigned int index, int flags, int table); + +#endif /* HAVE_IPV6 */ + +#endif /* _ZEBRA_RT_H */ diff --git a/zebra/rt_ioctl.c b/zebra/rt_ioctl.c new file mode 100644 index 0000000..ed70f33 --- /dev/null +++ b/zebra/rt_ioctl.c @@ -0,0 +1,569 @@ +/* + * kernel routing table update by ioctl(). + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "log.h" +#include "if.h" + +#include "zebra/rib.h" +#include "zebra/debug.h" + +/* Initialize of kernel interface. There is no kernel communication + support under ioctl(). So this is dummy stub function. */ +void +kernel_init () +{ + return; +} + +/* Dummy function of routing socket. */ +void +kernel_read (int sock) +{ + return; +} + +#if 0 +/* Initialization prototype of struct sockaddr_in. */ +static struct sockaddr_in sin_proto = +{ +#ifdef HAVE_SIN_LEN + sizeof (struct sockaddr_in), +#endif /* HAVE_SIN_LEN */ + AF_INET, 0, {0}, {0} +}; +#endif /* 0 */ + +/* Solaris has ortentry. */ +#ifdef HAVE_OLD_RTENTRY +#define rtentry ortentry +#endif /* HAVE_OLD_RTENTRY */ + +/* Interface to ioctl route message. */ +int +kernel_add_route (struct prefix_ipv4 *dest, struct in_addr *gate, + int index, int flags) +{ + int ret; + int sock; + struct rtentry rtentry; + struct sockaddr_in sin_dest, sin_mask, sin_gate; + + memset (&rtentry, 0, sizeof (struct rtentry)); + + /* Make destination. */ + memset (&sin_dest, 0, sizeof (struct sockaddr_in)); + sin_dest.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + sin_dest.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + sin_dest.sin_addr = dest->prefix; + + /* Make gateway. */ + if (gate) + { + memset (&sin_gate, 0, sizeof (struct sockaddr_in)); + sin_gate.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + sin_gate.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + sin_gate.sin_addr = *gate; + } + + memset (&sin_mask, 0, sizeof (struct sockaddr_in)); + sin_mask.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + sin_gate.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + masklen2ip (dest->prefixlen, &sin_mask.sin_addr); + + /* Set destination address, mask and gateway.*/ + memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in)); + if (gate) + memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in)); +#ifndef SUNOS_5 + memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in)); +#endif /* SUNOS_5 */ + + /* Routing entry flag set. */ + if (dest->prefixlen == 32) + rtentry.rt_flags |= RTF_HOST; + + if (gate && gate->s_addr != INADDR_ANY) + rtentry.rt_flags |= RTF_GATEWAY; + + rtentry.rt_flags |= RTF_UP; + + /* Additional flags */ + rtentry.rt_flags |= flags; + + + /* For tagging route. */ + /* rtentry.rt_flags |= RTF_DYNAMIC; */ + + /* Open socket for ioctl. */ + sock = socket (AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + { + zlog_warn ("can't make socket\n"); + return -1; + } + + /* Send message by ioctl(). */ + ret = ioctl (sock, SIOCADDRT, &rtentry); + if (ret < 0) + { + switch (errno) + { + case EEXIST: + close (sock); + return ZEBRA_ERR_RTEXIST; + break; + case ENETUNREACH: + close (sock); + return ZEBRA_ERR_RTUNREACH; + break; + case EPERM: + close (sock); + return ZEBRA_ERR_EPERM; + break; + } + + close (sock); + zlog_warn ("write : %s (%d)", strerror (errno), errno); + return 1; + } + close (sock); + + return ret; +} + +/* Interface to ioctl route message. */ +int +kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family) +{ + int ret; + int sock; + struct rtentry rtentry; + struct sockaddr_in sin_dest, sin_mask, sin_gate; + struct nexthop *nexthop; + int nexthop_num = 0; + struct interface *ifp; + + memset (&rtentry, 0, sizeof (struct rtentry)); + + /* Make destination. */ + memset (&sin_dest, 0, sizeof (struct sockaddr_in)); + sin_dest.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + sin_dest.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + sin_dest.sin_addr = p->u.prefix4; + + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) + { + SET_FLAG (rtentry.rt_flags, RTF_REJECT); + + if (cmd == SIOCADDRT) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + goto skip; + } + + memset (&sin_gate, 0, sizeof (struct sockaddr_in)); + + /* Make gateway. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + if ((cmd == SIOCADDRT + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + || (cmd == SIOCDELRT + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) + { + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + if (nexthop->rtype == NEXTHOP_TYPE_IPV4 || + nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) + { + sin_gate.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + sin_gate.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + sin_gate.sin_addr = nexthop->rgate.ipv4; + rtentry.rt_flags |= RTF_GATEWAY; + } + if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IFNAME) + { + ifp = if_lookup_by_index (nexthop->rifindex); + if (ifp) + rtentry.rt_dev = ifp->name; + else + return -1; + } + } + else + { + if (nexthop->type == NEXTHOP_TYPE_IPV4 || + nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + { + sin_gate.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + sin_gate.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + sin_gate.sin_addr = nexthop->gate.ipv4; + rtentry.rt_flags |= RTF_GATEWAY; + } + if (nexthop->type == NEXTHOP_TYPE_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IFNAME) + { + ifp = if_lookup_by_index (nexthop->ifindex); + if (ifp) + rtentry.rt_dev = ifp->name; + else + return -1; + } + } + + if (cmd == SIOCADDRT) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + nexthop_num++; + break; + } + } + + /* If there is no useful nexthop then return. */ + if (nexthop_num == 0) + { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("kernel_ioctl_ipv4(): No useful nexthop."); + return 0; + } + + skip: + + memset (&sin_mask, 0, sizeof (struct sockaddr_in)); + sin_mask.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + sin_mask.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + masklen2ip (p->prefixlen, &sin_mask.sin_addr); + + /* Set destination address, mask and gateway.*/ + memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in)); + + if (rtentry.rt_flags & RTF_GATEWAY) + memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in)); + +#ifndef SUNOS_5 + memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in)); +#endif /* SUNOS_5 */ + + /* Metric. It seems metric minus one value is installed... */ + rtentry.rt_metric = rib->metric; + + /* Routing entry flag set. */ + if (p->prefixlen == 32) + rtentry.rt_flags |= RTF_HOST; + + rtentry.rt_flags |= RTF_UP; + + /* Additional flags */ + /* rtentry.rt_flags |= flags; */ + + /* For tagging route. */ + /* rtentry.rt_flags |= RTF_DYNAMIC; */ + + /* Open socket for ioctl. */ + sock = socket (AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + { + zlog_warn ("can't make socket\n"); + return -1; + } + + /* Send message by ioctl(). */ + ret = ioctl (sock, cmd, &rtentry); + if (ret < 0) + { + switch (errno) + { + case EEXIST: + close (sock); + return ZEBRA_ERR_RTEXIST; + break; + case ENETUNREACH: + close (sock); + return ZEBRA_ERR_RTUNREACH; + break; + case EPERM: + close (sock); + return ZEBRA_ERR_EPERM; + break; + } + + close (sock); + zlog_warn ("write : %s (%d)", strerror (errno), errno); + return ret; + } + close (sock); + + return ret; +} + +int +kernel_add_ipv4 (struct prefix *p, struct rib *rib) +{ + return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET); +} + +int +kernel_delete_ipv4 (struct prefix *p, struct rib *rib) +{ + return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET); +} + +#ifdef HAVE_IPV6 + +/* Below is hack for GNU libc definition and Linux 2.1.X header. */ +#undef RTF_DEFAULT +#undef RTF_ADDRCONF + +#include + +#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 +/* struct in6_rtmsg will be declared in net/route.h. */ +#else +#include +#endif + +int +kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate, + int index, int flags) +{ + int ret; + int sock; + struct in6_rtmsg rtm; + + memset (&rtm, 0, sizeof (struct in6_rtmsg)); + + rtm.rtmsg_flags |= RTF_UP; + rtm.rtmsg_metric = 1; + memcpy (&rtm.rtmsg_dst, &dest->prefix, sizeof (struct in6_addr)); + rtm.rtmsg_dst_len = dest->prefixlen; + + /* We need link local index. But this should be done caller... + if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway)) + { + index = if_index_address (&rtm.rtmsg_gateway); + rtm.rtmsg_ifindex = index; + } + else + rtm.rtmsg_ifindex = 0; + */ + + rtm.rtmsg_flags |= RTF_GATEWAY; + + /* For tagging route. */ + /* rtm.rtmsg_flags |= RTF_DYNAMIC; */ + + memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr)); + + if (index) + rtm.rtmsg_ifindex = index; + else + rtm.rtmsg_ifindex = 0; + + rtm.rtmsg_metric = 1; + + sock = socket (AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + zlog_warn ("can't make socket\n"); + return -1; + } + + /* Send message via ioctl. */ + ret = ioctl (sock, type, &rtm); + if (ret < 0) + { + zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete", + strerror(errno)); + ret = errno; + close (sock); + return ret; + } + close (sock); + + return ret; +} + +int +kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib, + int family) +{ + int ret; + int sock; + struct in6_rtmsg rtm; + struct nexthop *nexthop; + int nexthop_num = 0; + + memset (&rtm, 0, sizeof (struct in6_rtmsg)); + + rtm.rtmsg_flags |= RTF_UP; + rtm.rtmsg_metric = rib->metric; + memcpy (&rtm.rtmsg_dst, &p->u.prefix, sizeof (struct in6_addr)); + rtm.rtmsg_dst_len = p->prefixlen; + + /* We need link local index. But this should be done caller... + if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway)) + { + index = if_index_address (&rtm.rtmsg_gateway); + rtm.rtmsg_ifindex = index; + } + else + rtm.rtmsg_ifindex = 0; + */ + + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) + SET_FLAG (rtm.rtmsg_flags, RTF_REJECT); + + rtm.rtmsg_flags |= RTF_GATEWAY; + + /* For tagging route. */ + /* rtm.rtmsg_flags |= RTF_DYNAMIC; */ + + /* Make gateway. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + if ((cmd == SIOCADDRT + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + || (cmd == SIOCDELRT + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) + { + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + if (nexthop->rtype == NEXTHOP_TYPE_IPV6 + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) + { + memcpy (&rtm.rtmsg_gateway, &nexthop->rgate.ipv6, + sizeof (struct in6_addr)); + } + if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IFNAME + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) + rtm.rtmsg_ifindex = nexthop->rifindex; + else + rtm.rtmsg_ifindex = 0; + + } + else + { + if (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) + { + memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6, + sizeof (struct in6_addr)); + } + if (nexthop->type == NEXTHOP_TYPE_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) + rtm.rtmsg_ifindex = nexthop->ifindex; + else + rtm.rtmsg_ifindex = 0; + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) + { +#ifdef HAVE_IN6ADDR_GLOBAL + rtm.rtmsg_gateway = in6addr_loopback; +#else /*HAVE_IN6ADDR_GLOBAL*/ + inet_pton (AF_INET6, "::1", &rtm.rtmsg_gateway); +#endif /*HAVE_IN6ADDR_GLOBAL*/ + } + } + + if (cmd == SIOCADDRT) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + nexthop_num++; + break; + } + } + + /* If there is no useful nexthop then return. */ + if (nexthop_num == 0) + { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("kernel_ioctl_ipv6_multipath(): No useful nexthop."); + return 0; + } + + sock = socket (AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) + { + zlog_warn ("can't make socket\n"); + return -1; + } + + /* Send message via ioctl. */ + ret = ioctl (sock, cmd, &rtm); + if (ret < 0) + { + zlog_warn ("can't %s ipv6 route: %s\n", + cmd == SIOCADDRT ? "add" : "delete", + strerror(errno)); + ret = errno; + close (sock); + return ret; + } + close (sock); + + return ret; +} + +int +kernel_add_ipv6 (struct prefix *p, struct rib *rib) +{ + return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6); +} + +int +kernel_delete_ipv6 (struct prefix *p, struct rib *rib) +{ + return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6); +} + +/* Delete IPv6 route from the kernel. */ +int +kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, + int index, int flags, int table) +{ + return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags); +} +#endif /* HAVE_IPV6 */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c new file mode 100644 index 0000000..bc26570 --- /dev/null +++ b/zebra/rt_netlink.c @@ -0,0 +1,1495 @@ +/* Kernel routing table updates using netlink over GNU/Linux system. + * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +/* Hack for GNU libc version 2. */ +#ifndef MSG_TRUNC +#define MSG_TRUNC 0x20 +#endif /* MSG_TRUNC */ + +#include "linklist.h" +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "connected.h" +#include "table.h" +#include "rib.h" + +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/interface.h" +#include "zebra/debug.h" + +/* Socket interface to kernel */ +struct nlsock +{ + int sock; + int seq; + struct sockaddr_nl snl; + char *name; +} netlink = { -1, 0, {0}, "netlink-listen" }, /* kernel messages */ + netlink_cmd = { -1, 0, {0}, "netlink-cmd" }, /* command channel */ + netlink_addr = {-1, 0, {0}, "netlink-addr" }; /* address channel */ + +struct message nlmsg_str[] = +{ + {RTM_NEWROUTE, "RTM_NEWROUTE"}, + {RTM_DELROUTE, "RTM_DELROUTE"}, + {RTM_GETROUTE, "RTM_GETROUTE"}, + {RTM_NEWLINK, "RTM_NEWLINK"}, + {RTM_DELLINK, "RTM_DELLINK"}, + {RTM_GETLINK, "RTM_GETLINK"}, + {RTM_NEWADDR, "RTM_NEWADDR"}, + {RTM_DELADDR, "RTM_DELADDR"}, + {RTM_GETADDR, "RTM_GETADDR"}, + {0, NULL} +}; + +extern int rtm_table_default; + +/* Make socket for Linux netlink interface. */ +static int +netlink_socket (struct nlsock *nl, unsigned long groups) +{ + int ret; + struct sockaddr_nl snl; + int sock; + int namelen; + + sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (sock < 0) + { + zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name, + strerror (errno)); + return -1; + } + + ret = fcntl (sock, F_SETFL, O_NONBLOCK); + if (ret < 0) + { + zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name, + strerror (errno)); + close (sock); + return -1; + } + + memset (&snl, 0, sizeof snl); + snl.nl_family = AF_NETLINK; + snl.nl_groups = groups; + + /* Bind the socket to the netlink structure for anything. */ + ret = bind (sock, (struct sockaddr *) &snl, sizeof snl); + if (ret < 0) + { + zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s", + nl->name, snl.nl_groups, strerror (errno)); + close (sock); + return -1; + } + + /* multiple netlink sockets will have different nl_pid */ + namelen = sizeof snl; + ret = getsockname (sock, (struct sockaddr *) &snl, &namelen); + if (ret < 0 || namelen != sizeof snl) + { + zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name, + strerror (errno)); + close (sock); + return -1; + } + + nl->snl = snl; + nl->sock = sock; + return ret; +} + +/* Get type specified information from netlink. */ +static int +netlink_request (int family, int type, struct nlsock *nl) +{ + int ret; + struct sockaddr_nl snl; + + struct + { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + + + /* Check netlink socket. */ + if (nl->sock < 0) + { + zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name); + return -1; + } + + memset (&snl, 0, sizeof snl); + snl.nl_family = AF_NETLINK; + + req.nlh.nlmsg_len = sizeof req; + req.nlh.nlmsg_type = type; + req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = ++nl->seq; + req.g.rtgen_family = family; + + ret = sendto (nl->sock, (void*) &req, sizeof req, 0, + (struct sockaddr*) &snl, sizeof snl); + if (ret < 0) + { + zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name, strerror (errno)); + return -1; + } + return 0; +} + +/* Receive message from netlink interface and pass those information + to the given function. */ +static int +netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), + struct nlsock *nl) +{ + int status; + int ret = 0; + int error; + + while (1) + { + char buf[4096]; + struct iovec iov = { buf, sizeof buf }; + struct sockaddr_nl snl; + struct msghdr msg = { (void*)&snl, sizeof snl, &iov, 1, NULL, 0, 0}; + struct nlmsghdr *h; + + status = recvmsg (nl->sock, &msg, 0); + + if (status < 0) + { + if (errno == EINTR) + continue; + if (errno == EWOULDBLOCK || errno == EAGAIN) + break; + zlog (NULL, LOG_ERR, "%s recvmsg overrun", nl->name); + continue; + } + + if (snl.nl_pid != 0) + { + zlog (NULL, LOG_ERR, "Ignoring non kernel message from pid %u", + snl.nl_pid); + continue; + } + + if (status == 0) + { + zlog (NULL, LOG_ERR, "%s EOF", nl->name); + return -1; + } + + if (msg.msg_namelen != sizeof snl) + { + zlog (NULL, LOG_ERR, "%s sender address length error: length %d", + nl->name, msg.msg_namelen); + return -1; + } + + for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, status); + h = NLMSG_NEXT (h, status)) + { + /* Finish of reading. */ + if (h->nlmsg_type == NLMSG_DONE) + return ret; + + /* Error handling. */ + if (h->nlmsg_type == NLMSG_ERROR) + { + struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h); + + /* If the error field is zero, then this is an ACK */ + if (err->error == 0) + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + zlog_info("%s: %s ACK: type=%s(%u), seq=%u, pid=%d", + __FUNCTION__, nl->name, + lookup (nlmsg_str, err->msg.nlmsg_type), + err->msg.nlmsg_type, err->msg.nlmsg_seq, + err->msg.nlmsg_pid); + } + + /* return if not a multipart message, otherwise continue */ + if(!(h->nlmsg_flags & NLM_F_MULTI)) + { + return 0; + } + continue; + } + + if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) + { + zlog (NULL, LOG_ERR, "%s error: message truncated", + nl->name); + return -1; + } + zlog (NULL, LOG_ERR, "%s error: %s, type=%s(%u), seq=%u, pid=%d", + nl->name, strerror (-err->error), + lookup (nlmsg_str, err->msg.nlmsg_type), + err->msg.nlmsg_type, err->msg.nlmsg_seq, + err->msg.nlmsg_pid); + /* + ret = -1; + continue; + */ + return -1; + } + + /* OK we got netlink message. */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d", + nl->name, + lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type, + h->nlmsg_seq, h->nlmsg_pid); + + /* skip unsolicited messages originating from command socket */ + if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid) + { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("netlink_parse_info: %s packet comes from %s", + nl->name, netlink_cmd.name); + continue; + } + + error = (*filter) (&snl, h); + if (error < 0) + { + zlog (NULL, LOG_ERR, "%s filter function error", nl->name); + ret = error; + } + } + + /* After error care. */ + if (msg.msg_flags & MSG_TRUNC) + { + zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name); + continue; + } + if (status) + { + zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name, + status); + return -1; + } + } + return ret; +} + +/* Utility function for parse rtattr. */ +static void +netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta, int len) +{ + while (RTA_OK(rta, len)) + { + if (rta->rta_type <= max) + tb[rta->rta_type] = rta; + rta = RTA_NEXT(rta,len); + } +} + +/* Called from interface_lookup_netlink(). This function is only used + during bootstrap. */ +int +netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h) +{ + int len; + struct ifinfomsg *ifi; + struct rtattr *tb[IFLA_MAX + 1]; + struct interface *ifp; + char *name; + int i; + + ifi = NLMSG_DATA (h); + + if (h->nlmsg_type != RTM_NEWLINK) + return 0; + + len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); + if (len < 0) + return -1; + + /* Looking up interface name. */ + memset (tb, 0, sizeof tb); + netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len); + if (tb[IFLA_IFNAME] == NULL) + return -1; + name = (char *)RTA_DATA(tb[IFLA_IFNAME]); + + /* Add interface. */ + ifp = if_get_by_name (name); + + ifp->ifindex = ifi->ifi_index; + ifp->flags = ifi->ifi_flags & 0x0000fffff; + ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]); + ifp->metric = 1; + + /* Hardware type and address. */ + ifp->hw_type = ifi->ifi_type; + + if (tb[IFLA_ADDRESS]) + { + int hw_addr_len; + + hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]); + + if (hw_addr_len > INTERFACE_HWADDR_MAX) + zlog_warn ("Hardware address is too large: %d", hw_addr_len); + else + { + ifp->hw_addr_len = hw_addr_len; + memcpy (ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]), hw_addr_len); + + for (i = 0; i < hw_addr_len; i++) + if (ifp->hw_addr[i] != 0) + break; + + if (i == hw_addr_len) + ifp->hw_addr_len = 0; + else + ifp->hw_addr_len = hw_addr_len; + } + } + + if_add_update (ifp); + + return 0; +} + +/* Lookup interface IPv4/IPv6 address. */ +int +netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) +{ + int len; + struct ifaddrmsg *ifa; + struct rtattr *tb [IFA_MAX + 1]; + struct interface *ifp; + void *addr = NULL; + void *broad = NULL; + u_char flags = 0; + char *label = NULL; + + ifa = NLMSG_DATA (h); + + if (ifa->ifa_family != AF_INET +#ifdef HAVE_IPV6 + && ifa->ifa_family != AF_INET6 +#endif /* HAVE_IPV6 */ + ) + return 0; + + if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR) + return 0; + + len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifaddrmsg)); + if (len < 0) + return -1; + + memset (tb, 0, sizeof tb); + netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len); + + ifp = if_lookup_by_index (ifa->ifa_index); + if (ifp == NULL) + { + zlog_err ("netlink_interface_addr can't find interface by index %d", + ifa->ifa_index); + return -1; + } + + if (tb[IFA_ADDRESS] == NULL) + tb[IFA_ADDRESS] = tb[IFA_LOCAL]; + + if (ifp->flags & IFF_POINTOPOINT) + { + if (tb[IFA_LOCAL]) + { + addr = RTA_DATA (tb[IFA_LOCAL]); + if (tb[IFA_ADDRESS]) + broad = RTA_DATA (tb[IFA_ADDRESS]); + else + broad = NULL; + } + else + { + if (tb[IFA_ADDRESS]) + addr = RTA_DATA (tb[IFA_ADDRESS]); + else + addr = NULL; + } + } + else + { + if (tb[IFA_ADDRESS]) + addr = RTA_DATA (tb[IFA_ADDRESS]); + else + addr = NULL; + + if (tb[IFA_BROADCAST]) + broad = RTA_DATA(tb[IFA_BROADCAST]); + else + broad = NULL; + } + + /* Flags. */ + if (ifa->ifa_flags & IFA_F_SECONDARY) + SET_FLAG (flags, ZEBRA_IFA_SECONDARY); + + /* Label */ + if (tb[IFA_LABEL]) + label = (char *) RTA_DATA (tb[IFA_LABEL]); + + if (ifp && label && strcmp (ifp->name, label) == 0) + label = NULL; + + /* Register interface address to the interface. */ + if (ifa->ifa_family == AF_INET) + { + if (h->nlmsg_type == RTM_NEWADDR) + connected_add_ipv4 (ifp, flags, + (struct in_addr *) addr, ifa->ifa_prefixlen, + (struct in_addr *) broad, label); + else + connected_delete_ipv4 (ifp, flags, + (struct in_addr *) addr, ifa->ifa_prefixlen, + (struct in_addr *) broad, label); + } +#ifdef HAVE_IPV6 + if (ifa->ifa_family == AF_INET6) + { + if (h->nlmsg_type == RTM_NEWADDR) + connected_add_ipv6 (ifp, + (struct in6_addr *) addr, ifa->ifa_prefixlen, + (struct in6_addr *) broad); + else + connected_delete_ipv6 (ifp, + (struct in6_addr *) addr, ifa->ifa_prefixlen, + (struct in6_addr *) broad); + } +#endif /* HAVE_IPV6*/ + + return 0; +} + +/* Looking up routing table by netlink interface. */ +int +netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) +{ + int len; + struct rtmsg *rtm; + struct rtattr *tb [RTA_MAX + 1]; + u_char flags = 0; + + char anyaddr[16] = {0}; + + int index; + int table; + void *dest; + void *gate; + + rtm = NLMSG_DATA (h); + + if (h->nlmsg_type != RTM_NEWROUTE) + return 0; + if (rtm->rtm_type != RTN_UNICAST) + return 0; + + table = rtm->rtm_table; +#if 0 /* we weed them out later in rib_weed_tables () */ + if (table != RT_TABLE_MAIN && table != rtm_table_default) + return 0; +#endif + + len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct rtmsg)); + if (len < 0) + return -1; + + memset (tb, 0, sizeof tb); + netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len); + + if (rtm->rtm_flags & RTM_F_CLONED) + return 0; + if (rtm->rtm_protocol == RTPROT_REDIRECT) + return 0; + if (rtm->rtm_protocol == RTPROT_KERNEL) + return 0; + + if (rtm->rtm_src_len != 0) + return 0; + + /* Route which inserted by Zebra. */ + if (rtm->rtm_protocol == RTPROT_ZEBRA) + flags |= ZEBRA_FLAG_SELFROUTE; + + index = 0; + dest = NULL; + gate = NULL; + + if (tb[RTA_OIF]) + index = *(int *) RTA_DATA (tb[RTA_OIF]); + + if (tb[RTA_DST]) + dest = RTA_DATA (tb[RTA_DST]); + else + dest = anyaddr; + + /* Multipath treatment is needed. */ + if (tb[RTA_GATEWAY]) + gate = RTA_DATA (tb[RTA_GATEWAY]); + + if (rtm->rtm_family == AF_INET) + { + struct prefix_ipv4 p; + p.family = AF_INET; + memcpy (&p.prefix, dest, 4); + p.prefixlen = rtm->rtm_dst_len; + + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, 0, 0); + } +#ifdef HAVE_IPV6 + if (rtm->rtm_family == AF_INET6) + { + struct prefix_ipv6 p; + p.family = AF_INET6; + memcpy (&p.prefix, dest, 16); + p.prefixlen = rtm->rtm_dst_len; + + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table); + } +#endif /* HAVE_IPV6 */ + + return 0; +} + +struct message rtproto_str [] = +{ + {RTPROT_REDIRECT, "redirect"}, + {RTPROT_KERNEL, "kernel"}, + {RTPROT_BOOT, "boot"}, + {RTPROT_STATIC, "static"}, + {RTPROT_GATED, "GateD"}, + {RTPROT_RA, "router advertisement"}, + {RTPROT_MRT, "MRT"}, + {RTPROT_ZEBRA, "Zebra"}, +#ifdef RTPROT_BIRD + {RTPROT_BIRD, "BIRD"}, +#endif /* RTPROT_BIRD */ + {0, NULL} +}; + +/* Routing information change from the kernel. */ +int +netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) +{ + int len; + struct rtmsg *rtm; + struct rtattr *tb [RTA_MAX + 1]; + + char anyaddr[16] = {0}; + + int index; + int table; + void *dest; + void *gate; + + rtm = NLMSG_DATA (h); + + if (! (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) + { + /* If this is not route add/delete message print warning. */ + zlog_warn ("Kernel message: %d\n", h->nlmsg_type); + return 0; + } + + /* Connected route. */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("%s %s %s proto %s", + h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", + rtm->rtm_family == AF_INET ? "ipv4" : "ipv6", + rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast", + lookup (rtproto_str, rtm->rtm_protocol)); + + if (rtm->rtm_type != RTN_UNICAST) + { + return 0; + } + + table = rtm->rtm_table; + if (table != RT_TABLE_MAIN && table != rtm_table_default) + { + return 0; + } + + len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct rtmsg)); + if (len < 0) + return -1; + + memset (tb, 0, sizeof tb); + netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len); + + if (rtm->rtm_flags & RTM_F_CLONED) + return 0; + if (rtm->rtm_protocol == RTPROT_REDIRECT) + return 0; + if (rtm->rtm_protocol == RTPROT_KERNEL) + return 0; + + if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE) + return 0; + + if (rtm->rtm_src_len != 0) + { + zlog_warn ("netlink_route_change(): no src len"); + return 0; + } + + index = 0; + dest = NULL; + gate = NULL; + + if (tb[RTA_OIF]) + index = *(int *) RTA_DATA (tb[RTA_OIF]); + + if (tb[RTA_DST]) + dest = RTA_DATA (tb[RTA_DST]); + else + dest = anyaddr; + + if (tb[RTA_GATEWAY]) + gate = RTA_DATA (tb[RTA_GATEWAY]); + + if (rtm->rtm_family == AF_INET) + { + struct prefix_ipv4 p; + p.family = AF_INET; + memcpy (&p.prefix, dest, 4); + p.prefixlen = rtm->rtm_dst_len; + + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (h->nlmsg_type == RTM_NEWROUTE) + zlog_info ("RTM_NEWROUTE %s/%d", + inet_ntoa (p.prefix), p.prefixlen); + else + zlog_info ("RTM_DELROUTE %s/%d", + inet_ntoa (p.prefix), p.prefixlen); + } + + if (h->nlmsg_type == RTM_NEWROUTE) + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0); + else + rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table); + } + +#ifdef HAVE_IPV6 + if (rtm->rtm_family == AF_INET6) + { + struct prefix_ipv6 p; + char buf[BUFSIZ]; + + p.family = AF_INET6; + memcpy (&p.prefix, dest, 16); + p.prefixlen = rtm->rtm_dst_len; + + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (h->nlmsg_type == RTM_NEWROUTE) + zlog_info ("RTM_NEWROUTE %s/%d", + inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), + p.prefixlen); + else + zlog_info ("RTM_DELROUTE %s/%d", + inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), + p.prefixlen); + } + + if (h->nlmsg_type == RTM_NEWROUTE) + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0); + else + rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0); + } +#endif /* HAVE_IPV6 */ + + return 0; +} + +int +netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) +{ + int len; + struct ifinfomsg *ifi; + struct rtattr *tb [IFLA_MAX + 1]; + struct interface *ifp; + char *name; + + ifi = NLMSG_DATA (h); + + if (! (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) + { + /* If this is not link add/delete message so print warning. */ + zlog_warn ("netlink_link_change: wrong kernel message %d\n", + h->nlmsg_type); + return 0; + } + + len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); + if (len < 0) + return -1; + + /* Looking up interface name. */ + memset (tb, 0, sizeof tb); + netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len); + if (tb[IFLA_IFNAME] == NULL) + return -1; + name = (char *)RTA_DATA(tb[IFLA_IFNAME]); + + /* Add interface. */ + if (h->nlmsg_type == RTM_NEWLINK) + { + ifp = if_lookup_by_name (name); + + if (ifp == NULL || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + { + if (ifp == NULL) + ifp = if_get_by_name (name); + + ifp->ifindex = ifi->ifi_index; + ifp->flags = ifi->ifi_flags & 0x0000fffff; + ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]); + ifp->metric = 1; + + /* If new link is added. */ + if_add_update(ifp); + } + else + { + /* Interface status change. */ + ifp->ifindex = ifi->ifi_index; + ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]); + ifp->metric = 1; + + if (if_is_up (ifp)) + { + ifp->flags = ifi->ifi_flags & 0x0000fffff; + if (! if_is_up (ifp)) + if_down (ifp); + } + else + { + ifp->flags = ifi->ifi_flags & 0x0000fffff; + if (if_is_up (ifp)) + if_up (ifp); + } + } + } + else + { + /* RTM_DELLINK. */ + ifp = if_lookup_by_name (name); + + if (ifp == NULL) + { + zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find", + name); + return 0; + } + + if_delete_update (ifp); + } + + return 0; +} + +int +netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h) +{ + switch (h->nlmsg_type) + { + case RTM_NEWROUTE: + return netlink_route_change (snl, h); + break; + case RTM_DELROUTE: + return netlink_route_change (snl, h); + break; + case RTM_NEWLINK: + return netlink_link_change (snl, h); + break; + case RTM_DELLINK: + return netlink_link_change (snl, h); + break; + case RTM_NEWADDR: + return netlink_interface_addr (snl, h); + break; + case RTM_DELADDR: + return netlink_interface_addr (snl, h); + break; + default: + zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type); + break; + } + return 0; +} + +/* Interface lookup by netlink socket. */ +int +interface_lookup_netlink () +{ + int ret; + + /* Get interface information. */ + ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd); + if (ret < 0) + return ret; + ret = netlink_parse_info (netlink_interface, &netlink_cmd); + if (ret < 0) + return ret; + + /* Get IPv4 address of the interfaces. */ + ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd); + if (ret < 0) + return ret; + ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd); + if (ret < 0) + return ret; + +#ifdef HAVE_IPV6 + /* Get IPv6 address of the interfaces. */ + ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd); + if (ret < 0) + return ret; + ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd); + if (ret < 0) + return ret; +#endif /* HAVE_IPV6 */ + + return 0; +} + +/* Routing table read function using netlink interface. Only called + bootstrap time. */ +int +netlink_route_read () +{ + int ret; + + /* Get IPv4 routing table. */ + ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd); + if (ret < 0) + return ret; + ret = netlink_parse_info (netlink_routing_table, &netlink_cmd); + if (ret < 0) + return ret; + +#ifdef HAVE_IPV6 + /* Get IPv6 routing table. */ + ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd); + if (ret < 0) + return ret; + ret = netlink_parse_info (netlink_routing_table, &netlink_cmd); + if (ret < 0) + return ret; +#endif /* HAVE_IPV6 */ + + return 0; +} + +/* Utility function comes from iproute2. + Authors: Alexey Kuznetsov, */ +int +addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen) +{ + int len; + struct rtattr *rta; + + len = RTA_LENGTH(alen); + + if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) + return -1; + + rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len)); + rta->rta_type = type; + rta->rta_len = len; + memcpy (RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; + + return 0; +} + +int +rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen) +{ + int len; + struct rtattr *subrta; + + len = RTA_LENGTH(alen); + + if (RTA_ALIGN(rta->rta_len) + len > maxlen) + return -1; + + subrta = (struct rtattr*) (((char*)rta) + RTA_ALIGN (rta->rta_len)); + subrta->rta_type = type; + subrta->rta_len = len; + memcpy (RTA_DATA(subrta), data, alen); + rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len; + + return 0; +} + +/* Utility function comes from iproute2. + Authors: Alexey Kuznetsov, */ +int +addattr32 (struct nlmsghdr *n, int maxlen, int type, int data) +{ + int len; + struct rtattr *rta; + + len = RTA_LENGTH(4); + + if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) + return -1; + + rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len)); + rta->rta_type = type; + rta->rta_len = len; + memcpy (RTA_DATA(rta), &data, 4); + n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; + + return 0; +} + +static int +netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h) +{ + zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type); + return 0; +} + +/* sendmsg() to netlink socket then recvmsg(). */ +int +netlink_talk (struct nlmsghdr *n, struct nlsock *nl) +{ + int status; + struct sockaddr_nl snl; + struct iovec iov = { (void*) n, n->nlmsg_len }; + struct msghdr msg = {(void*) &snl, sizeof snl, &iov, 1, NULL, 0, 0}; + int flags = 0; + + memset (&snl, 0, sizeof snl); + snl.nl_family = AF_NETLINK; + + n->nlmsg_seq = ++netlink_cmd.seq; + + /* Request an acknowledgement by setting NLM_F_ACK */ + n->nlmsg_flags |= NLM_F_ACK; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name, + lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type, + n->nlmsg_seq); + + /* Send message to netlink interface. */ + status = sendmsg (nl->sock, &msg, 0); + if (status < 0) + { + zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s", + strerror (errno)); + return -1; + } + + /* + * Change socket flags for blocking I/O. + * This ensures we wait for a reply in netlink_parse_info(). + */ + if((flags = fcntl(nl->sock, F_GETFL, 0)) < 0) + { + zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s", + __FUNCTION__, __LINE__, strerror (errno)); + } + flags &= ~O_NONBLOCK; + if(fcntl(nl->sock, F_SETFL, flags) < 0) + { + zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", + __FUNCTION__, __LINE__, strerror (errno)); + } + + /* + * Get reply from netlink socket. + * The reply should either be an acknowlegement or an error. + */ + status = netlink_parse_info (netlink_talk_filter, nl); + + /* Restore socket flags for nonblocking I/O */ + flags |= O_NONBLOCK; + if(fcntl(nl->sock, F_SETFL, flags) < 0) + { + zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", + __FUNCTION__, __LINE__, strerror (errno)); + } + + return status; +} + +/* Routing table change via netlink interface. */ +int +netlink_route (int cmd, int family, void *dest, int length, void *gate, + int index, int zebra_flags, int table) +{ + int ret; + int bytelen; + struct sockaddr_nl snl; + int discard; + + struct + { + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; + } req; + + memset (&req, 0, sizeof req); + + bytelen = (family == AF_INET ? 4 : 16); + + req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); + req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + req.n.nlmsg_type = cmd; + req.r.rtm_family = family; + req.r.rtm_table = table; + req.r.rtm_dst_len = length; + + if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) + discard = 1; + else + discard = 0; + + if (cmd == RTM_NEWROUTE) + { +#if 0 + req.r.rtm_protocol = RTPROT_ZEBRA; +#endif + req.r.rtm_scope = RT_SCOPE_UNIVERSE; + + if (discard) + req.r.rtm_type = RTN_BLACKHOLE; + else + req.r.rtm_type = RTN_UNICAST; + } + + if (dest) + addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen); + + if (! discard) + { + if (gate) + addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen); + if (index > 0) + addattr32 (&req.n, sizeof req, RTA_OIF, index); + } + + /* Destination netlink address. */ + memset (&snl, 0, sizeof snl); + snl.nl_family = AF_NETLINK; + + /* Talk to netlink socket. */ + ret = netlink_talk (&req.n, &netlink); + if (ret < 0) + return -1; + + return 0; +} + +/* Routing table change via netlink interface. */ +int +netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, + int family) +{ + int bytelen; + struct sockaddr_nl snl; + struct nexthop *nexthop = NULL; + int nexthop_num = 0; + struct nlsock *nl; + int discard; + + struct + { + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; + } req; + + memset (&req, 0, sizeof req); + + bytelen = (family == AF_INET ? 4 : 16); + + req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); + req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + req.n.nlmsg_type = cmd; + req.r.rtm_family = family; + req.r.rtm_table = rib->table; + req.r.rtm_dst_len = p->prefixlen; + +#ifdef RTM_F_EQUALIZE + req.r.rtm_flags |= RTM_F_EQUALIZE; +#endif /* RTM_F_EQUALIZE */ + + if (rib->flags & ZEBRA_FLAG_BLACKHOLE) + discard = 1; + else + discard = 0; + + if (cmd == RTM_NEWROUTE) + { + req.r.rtm_protocol = RTPROT_ZEBRA; + req.r.rtm_scope = RT_SCOPE_UNIVERSE; + + if (discard) + req.r.rtm_type = RTN_BLACKHOLE; + else + req.r.rtm_type = RTN_UNICAST; + } + + addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen); + + /* Metric. */ + addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric); + + if (discard) + { + if (cmd == RTM_NEWROUTE) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + goto skip; + } + + /* Multipath case. */ + if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1) + { + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + if ((cmd == RTM_NEWROUTE + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + || (cmd == RTM_DELROUTE + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) + { + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + if (nexthop->rtype == NEXTHOP_TYPE_IPV4 + || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) + addattr_l (&req.n, sizeof req, RTA_GATEWAY, + &nexthop->rgate.ipv4, bytelen); +#ifdef HAVE_IPV6 + if (nexthop->rtype == NEXTHOP_TYPE_IPV6 + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME) + addattr_l (&req.n, sizeof req, RTA_GATEWAY, + &nexthop->rgate.ipv6, bytelen); +#endif /* HAVE_IPV6 */ + if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IFNAME + || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME) + addattr32 (&req.n, sizeof req, RTA_OIF, + nexthop->rifindex); + } + else + { + if (nexthop->type == NEXTHOP_TYPE_IPV4 + || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + addattr_l (&req.n, sizeof req, RTA_GATEWAY, + &nexthop->gate.ipv4, bytelen); +#ifdef HAVE_IPV6 + if (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) + addattr_l (&req.n, sizeof req, RTA_GATEWAY, + &nexthop->gate.ipv6, bytelen); +#endif /* HAVE_IPV6 */ + if (nexthop->type == NEXTHOP_TYPE_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) + addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex); + } + + if (cmd == RTM_NEWROUTE) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + nexthop_num++; + break; + } + } + } + else + { + char buf[1024]; + struct rtattr *rta = (void *) buf; + struct rtnexthop *rtnh; + + rta->rta_type = RTA_MULTIPATH; + rta->rta_len = RTA_LENGTH(0); + rtnh = RTA_DATA(rta); + + nexthop_num = 0; + for (nexthop = rib->nexthop; + nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM); + nexthop = nexthop->next) + { + if ((cmd == RTM_NEWROUTE + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + || (cmd == RTM_DELROUTE + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) + { + nexthop_num++; + + rtnh->rtnh_len = sizeof (*rtnh); + rtnh->rtnh_flags = 0; + rtnh->rtnh_hops = 0; + rta->rta_len += rtnh->rtnh_len; + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + if (nexthop->rtype == NEXTHOP_TYPE_IPV4 + || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) + { + rta_addattr_l (rta, 4096, RTA_GATEWAY, + &nexthop->rgate.ipv4, bytelen); + rtnh->rtnh_len += sizeof (struct rtattr) + 4; + } +#ifdef HAVE_IPV6 + if (nexthop->rtype == NEXTHOP_TYPE_IPV6 + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) + rta_addattr_l (rta, 4096, RTA_GATEWAY, + &nexthop->rgate.ipv6, bytelen); +#endif /* HAVE_IPV6 */ + /* ifindex */ + if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IFNAME + || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME) + rtnh->rtnh_ifindex = nexthop->rifindex; + else + rtnh->rtnh_ifindex = 0; + } + else + { + if (nexthop->type == NEXTHOP_TYPE_IPV4 + || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + { + rta_addattr_l (rta, 4096, RTA_GATEWAY, + &nexthop->gate.ipv4, bytelen); + rtnh->rtnh_len += sizeof (struct rtattr) + 4; + } +#ifdef HAVE_IPV6 + if (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) + rta_addattr_l (rta, 4096, RTA_GATEWAY, + &nexthop->gate.ipv6, bytelen); +#endif /* HAVE_IPV6 */ + /* ifindex */ + if (nexthop->type == NEXTHOP_TYPE_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) + rtnh->rtnh_ifindex = nexthop->ifindex; + else + rtnh->rtnh_ifindex = 0; + } + rtnh = RTNH_NEXT(rtnh); + + if (cmd == RTM_NEWROUTE) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + } + } + + if (rta->rta_len > RTA_LENGTH (0)) + addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA(rta), + RTA_PAYLOAD(rta)); + } + + /* If there is no useful nexthop then return. */ + if (nexthop_num == 0) + { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("netlink_route_multipath(): No useful nexthop."); + return 0; + } + + skip: + + /* Destination netlink address. */ + memset (&snl, 0, sizeof snl); + snl.nl_family = AF_NETLINK; + + if (family == AF_INET) + nl = &netlink_cmd; + else + nl = &netlink; + + /* Talk to netlink socket. */ + return netlink_talk (&req.n, nl); +} + +int +kernel_add_ipv4 (struct prefix *p, struct rib *rib) +{ + return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET); +} + +int +kernel_delete_ipv4 (struct prefix *p, struct rib *rib) +{ + return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET); +} + +#ifdef HAVE_IPV6 +int +kernel_add_ipv6 (struct prefix *p, struct rib *rib) +{ + return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6); +} + +int +kernel_delete_ipv6 (struct prefix *p, struct rib *rib) +{ + return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6); +} + +/* Delete IPv6 route from the kernel. */ +int +kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, + int index, int flags, int table) +{ + return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix, dest->prefixlen, + gate, index, flags, table); +} +#endif /* HAVE_IPV6 */ + +/* Interface address modification. */ +int +netlink_address (int cmd, int family, struct interface *ifp, + struct connected *ifc) +{ + int bytelen; + struct prefix *p; + + struct + { + struct nlmsghdr n; + struct ifaddrmsg ifa; + char buf[1024]; + } req; + + p = ifc->address; + memset (&req, 0, sizeof req); + + bytelen = (family == AF_INET ? 4 : 16); + + req.n.nlmsg_len = NLMSG_LENGTH (sizeof(struct ifaddrmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = cmd; + req.ifa.ifa_family = family; + + req.ifa.ifa_index = ifp->ifindex; + req.ifa.ifa_prefixlen = p->prefixlen; + + addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen); + + if (family == AF_INET && cmd == RTM_NEWADDR) + { + if (if_is_broadcast (ifp) && ifc->destination) + { + p = ifc->destination; + addattr_l(&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix, bytelen); + } + } + + if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY)) + SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY); + + if (ifc->label) + addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label, + strlen (ifc->label) + 1); + + return netlink_talk (&req.n, &netlink_cmd); +} + +int +kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc) +{ + return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc); +} + +int +kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc) +{ + return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc); +} + +#include "thread.h" + +extern struct thread_master *master; + +/* Kernel route reflection. */ +int +kernel_read (struct thread *thread) +{ + int ret; + int sock; + + sock = THREAD_FD (thread); + ret = netlink_parse_info (netlink_information_fetch, &netlink); + thread_add_read (master, kernel_read, NULL, netlink.sock); + + return 0; +} + +/* Exported interface function. This function simply calls + netlink_socket (). */ +void +kernel_init () +{ + unsigned long groups; + + groups = RTMGRP_LINK|RTMGRP_IPV4_ROUTE|RTMGRP_IPV4_IFADDR; +#ifdef HAVE_IPV6 + groups |= RTMGRP_IPV6_ROUTE|RTMGRP_IPV6_IFADDR; +#endif /* HAVE_IPV6 */ + netlink_socket (&netlink, groups); + netlink_socket (&netlink_cmd, 0); + + /* Register kernel socket. */ + if (netlink.sock > 0) + thread_add_read (master, kernel_read, NULL, netlink.sock); +} diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c new file mode 100644 index 0000000..d6a74c9 --- /dev/null +++ b/zebra/rt_socket.c @@ -0,0 +1,449 @@ +/* + * Kernel routing table updates by routing socket. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "prefix.h" +#include "sockunion.h" +#include "log.h" +#include "str.h" + +#include "zebra/debug.h" +#include "zebra/rib.h" + +int +rtm_write (int message, + union sockunion *dest, + union sockunion *mask, + union sockunion *gate, + unsigned int index, + int zebra_flags, + int metric); + +/* Adjust netmask socket length. Return value is a adjusted sin_len + value. */ +int +sin_masklen (struct in_addr mask) +{ + char *p, *lim; + int len; + struct sockaddr_in sin; + + if (mask.s_addr == 0) + return sizeof (long); + + sin.sin_addr = mask; + len = sizeof (struct sockaddr_in); + + lim = (char *) &sin.sin_addr; + p = lim + sizeof (sin.sin_addr); + + while (*--p == 0 && p >= lim) + len--; + return len; +} + +/* Interface between zebra message and rtm message. */ +int +kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) +{ + struct sockaddr_in *mask = NULL; + struct sockaddr_in sin_dest, sin_mask, sin_gate; + struct nexthop *nexthop; + int nexthop_num = 0; + unsigned int ifindex = 0; + int gate = 0; + int error; + + memset (&sin_dest, 0, sizeof (struct sockaddr_in)); + sin_dest.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + sin_dest.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + sin_dest.sin_addr = p->u.prefix4; + + memset (&sin_mask, 0, sizeof (struct sockaddr_in)); + + memset (&sin_gate, 0, sizeof (struct sockaddr_in)); + sin_gate.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + sin_gate.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + + /* Make gateway. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + gate = 0; + + if ((cmd == RTM_ADD + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + || (cmd == RTM_DELETE +#if 0 + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) +#endif + )) + { + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + if (nexthop->rtype == NEXTHOP_TYPE_IPV4 || + nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) + { + sin_gate.sin_addr = nexthop->rgate.ipv4; + gate = 1; + } + if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IFNAME + || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) + ifindex = nexthop->rifindex; + } + else + { + if (nexthop->type == NEXTHOP_TYPE_IPV4 || + nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + { + sin_gate.sin_addr = nexthop->gate.ipv4; + gate = 1; + } + if (nexthop->type == NEXTHOP_TYPE_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + ifindex = nexthop->ifindex; + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) + { + struct in_addr loopback; + + loopback.s_addr = htonl (INADDR_LOOPBACK); + sin_gate.sin_addr = loopback; + gate = 1; + } + } + + if (cmd == RTM_ADD) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + if (gate && p->prefixlen == 32) + mask = NULL; + else + { + masklen2ip (p->prefixlen, &sin_mask.sin_addr); + sin_mask.sin_family = AF_UNSPEC; +#ifdef HAVE_SIN_LEN + sin_mask.sin_len = sin_masklen (sin_mask.sin_addr); +#endif /* HAVE_SIN_LEN */ + mask = &sin_mask; + } + } + + error = rtm_write (cmd, + (union sockunion *)&sin_dest, + (union sockunion *)mask, + gate ? (union sockunion *)&sin_gate : NULL, + ifindex, + rib->flags, + rib->metric); + +#if 0 + if (error) + { + zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.", + nexthop_num, error); + } +#endif + + nexthop_num++; + } + + /* If there is no useful nexthop then return. */ + if (nexthop_num == 0) + { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("kernel_rtm_ipv4(): No useful nexthop."); + return 0; + } + + return 0; /*XXX*/ +} + +int +kernel_add_ipv4 (struct prefix *p, struct rib *rib) +{ + return kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET); +} + +int +kernel_delete_ipv4 (struct prefix *p, struct rib *rib) +{ + return kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET); +} + +#ifdef HAVE_IPV6 + +/* Calculate sin6_len value for netmask socket value. */ +int +sin6_masklen (struct in6_addr mask) +{ + struct sockaddr_in6 sin6; + char *p, *lim; + int len; + +#if defined (INRIA) + if (IN_ANYADDR6 (mask)) + return sizeof (long); +#else /* ! INRIA */ + if (IN6_IS_ADDR_UNSPECIFIED (&mask)) + return sizeof (long); +#endif /* ! INRIA */ + + sin6.sin6_addr = mask; + len = sizeof (struct sockaddr_in6); + + lim = (char *) & sin6.sin6_addr; + p = lim + sizeof (sin6.sin6_addr); + + while (*--p == 0 && p >= lim) + len--; + + return len; +} + +/* Interface between zebra message and rtm message. */ +int +kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest, + struct in6_addr *gate, int index, int flags) +{ + struct sockaddr_in6 *mask; + struct sockaddr_in6 sin_dest, sin_mask, sin_gate; + + memset (&sin_dest, 0, sizeof (struct sockaddr_in6)); + sin_dest.sin6_family = AF_INET6; +#ifdef SIN6_LEN + sin_dest.sin6_len = sizeof (struct sockaddr_in6); +#endif /* SIN6_LEN */ + + memset (&sin_mask, 0, sizeof (struct sockaddr_in6)); + + memset (&sin_gate, 0, sizeof (struct sockaddr_in6)); + sin_gate.sin6_family = AF_INET6; +#ifdef SIN6_LEN + sin_gate.sin6_len = sizeof (struct sockaddr_in6); +#endif /* SIN6_LEN */ + + sin_dest.sin6_addr = dest->prefix; + + if (gate) + memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr)); + + /* Under kame set interface index to link local address. */ +#ifdef KAME + +#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ + do { \ + (a).s6_addr[2] = ((i) >> 8) & 0xff; \ + (a).s6_addr[3] = (i) & 0xff; \ + } while (0) + + if (gate && IN6_IS_ADDR_LINKLOCAL(gate)) + SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index); +#endif /* KAME */ + + if (gate && dest->prefixlen == 128) + mask = NULL; + else + { + masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr); + sin_mask.sin6_family = AF_UNSPEC; +#ifdef SIN6_LEN + sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr); +#endif /* SIN6_LEN */ + mask = &sin_mask; + } + + return rtm_write (message, + (union sockunion *) &sin_dest, + (union sockunion *) mask, + gate ? (union sockunion *)&sin_gate : NULL, + index, + flags, + 0); +} + +/* Interface between zebra message and rtm message. */ +int +kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, + int family) +{ + struct sockaddr_in6 *mask; + struct sockaddr_in6 sin_dest, sin_mask, sin_gate; + struct nexthop *nexthop; + int nexthop_num = 0; + unsigned int ifindex = 0; + int gate = 0; + int error; + + memset (&sin_dest, 0, sizeof (struct sockaddr_in6)); + sin_dest.sin6_family = AF_INET6; +#ifdef SIN6_LEN + sin_dest.sin6_len = sizeof (struct sockaddr_in6); +#endif /* SIN6_LEN */ + sin_dest.sin6_addr = p->u.prefix6; + + memset (&sin_mask, 0, sizeof (struct sockaddr_in6)); + + memset (&sin_gate, 0, sizeof (struct sockaddr_in6)); + sin_gate.sin6_family = AF_INET6; +#ifdef HAVE_SIN_LEN + sin_gate.sin6_len = sizeof (struct sockaddr_in6); +#endif /* HAVE_SIN_LEN */ + + /* Make gateway. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + gate = 0; + + if ((cmd == RTM_ADD + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + || (cmd == RTM_DELETE +#if 0 + && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) +#endif + )) + { + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + if (nexthop->rtype == NEXTHOP_TYPE_IPV6 + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) + { + sin_gate.sin6_addr = nexthop->rgate.ipv6; + gate = 1; + } + if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX + || nexthop->rtype == NEXTHOP_TYPE_IFNAME + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) + ifindex = nexthop->rifindex; + } + else + { + if (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) + { + sin_gate.sin6_addr = nexthop->gate.ipv6; + gate = 1; + } + if (nexthop->type == NEXTHOP_TYPE_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) + ifindex = nexthop->ifindex; + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) + { +#ifdef HAVE_IN6ADDR_GLOBAL + sin_gate.sin6_addr = in6addr_loopback; +#else /*HAVE_IN6ADDR_GLOBAL*/ + inet_pton (AF_INET6, "::1", &sin_gate.sin6_addr); +#endif /*HAVE_IN6ADDR_GLOBAL*/ + gate = 1; + } + } + + if (cmd == RTM_ADD) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + } + + /* Under kame set interface index to link local address. */ +#ifdef KAME + +#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ + do { \ + (a).s6_addr[2] = ((i) >> 8) & 0xff; \ + (a).s6_addr[3] = (i) & 0xff; \ + } while (0) + + if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr)) + SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex); +#endif /* KAME */ + + if (gate && p->prefixlen == 128) + mask = NULL; + else + { + masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr); + sin_mask.sin6_family = AF_UNSPEC; +#ifdef SIN6_LEN + sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr); +#endif /* SIN6_LEN */ + mask = &sin_mask; + } + + error = rtm_write (cmd, + (union sockunion *) &sin_dest, + (union sockunion *) mask, + gate ? (union sockunion *)&sin_gate : NULL, + ifindex, + rib->flags, + rib->metric); + +#if 0 + if (error) + { + zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.", + nexthop_num, error); + } +#endif + + nexthop_num++; + } + + /* If there is no useful nexthop then return. */ + if (nexthop_num == 0) + { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("kernel_rtm_ipv6_multipath(): No useful nexthop."); + return 0; + } + + return 0; /*XXX*/ +} + +int +kernel_add_ipv6 (struct prefix *p, struct rib *rib) +{ + return kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6); +} + +int +kernel_delete_ipv6 (struct prefix *p, struct rib *rib) +{ + return kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6); +} + +/* Delete IPv6 route from the kernel. */ +int +kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, + int index, int flags, int table) +{ + return kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags); +} +#endif /* HAVE_IPV6 */ diff --git a/zebra/rtadv.c b/zebra/rtadv.c new file mode 100644 index 0000000..752f498 --- /dev/null +++ b/zebra/rtadv.c @@ -0,0 +1,1112 @@ +/* Router advertisement + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "sockopt.h" +#include "thread.h" +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "linklist.h" +#include "command.h" + +#include "zebra/interface.h" +#include "zebra/rtadv.h" +#include "zebra/debug.h" + +#if defined (HAVE_IPV6) && defined (RTADV) + +/* If RFC2133 definition is used. */ +#ifndef IPV6_JOIN_GROUP +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#endif +#ifndef IPV6_LEAVE_GROUP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP +#endif + +#define ALLNODE "ff02::1" +#define ALLROUTER "ff02::2" + +enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, RTADV_READ}; + +void rtadv_event (enum rtadv_event, int); + +int if_join_all_router (int, struct interface *); +int if_leave_all_router (int, struct interface *); + +/* Structure which hold status of router advertisement. */ +struct rtadv +{ + int sock; + + int adv_if_count; + + struct thread *ra_read; + struct thread *ra_timer; +}; + +struct rtadv *rtadv = NULL; + +struct rtadv * +rtadv_new () +{ + struct rtadv *new; + new = XMALLOC (MTYPE_TMP, sizeof (struct rtadv)); + memset (new, 0, sizeof (struct rtadv)); + return new; +} + +void +rtadv_free (struct rtadv *rtadv) +{ + XFREE (MTYPE_TMP, rtadv); +} + +int +rtadv_recv_packet (int sock, u_char *buf, int buflen, + struct sockaddr_in6 *from, unsigned int *ifindex, + int *hoplimit) +{ + int ret; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsgptr; + struct in6_addr dst; + + char adata[1024]; + + /* Fill in message and iovec. */ + msg.msg_name = (void *) from; + msg.msg_namelen = sizeof (struct sockaddr_in6); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = (void *) adata; + msg.msg_controllen = sizeof adata; + iov.iov_base = buf; + iov.iov_len = buflen; + + /* If recvmsg fail return minus value. */ + ret = recvmsg (sock, &msg, 0); + if (ret < 0) + return ret; + + for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; + cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) + { + /* I want interface index which this packet comes from. */ + if (cmsgptr->cmsg_level == IPPROTO_IPV6 && + cmsgptr->cmsg_type == IPV6_PKTINFO) + { + struct in6_pktinfo *ptr; + + ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr); + *ifindex = ptr->ipi6_ifindex; + memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr)); + } + + /* Incoming packet's hop limit. */ + if (cmsgptr->cmsg_level == IPPROTO_IPV6 && + cmsgptr->cmsg_type == IPV6_HOPLIMIT) + *hoplimit = *((int *) CMSG_DATA (cmsgptr)); + } + return ret; +} + +#define RTADV_MSG_SIZE 4096 + +/* Send router advertisement packet. */ +void +rtadv_send_packet (int sock, struct interface *ifp) +{ + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsgptr; + struct in6_pktinfo *pkt; + struct sockaddr_in6 addr; +#ifdef HAVE_SOCKADDR_DL + struct sockaddr_dl *sdl; +#endif /* HAVE_SOCKADDR_DL */ + char adata [sizeof (struct cmsghdr) + sizeof (struct in6_pktinfo)]; + unsigned char buf[RTADV_MSG_SIZE]; + struct nd_router_advert *rtadv; + int ret; + int len = 0; + struct zebra_if *zif; + u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; + listnode node; + + /* Logging of packet. */ + if (IS_ZEBRA_DEBUG_PACKET) + zlog_info ("Router advertisement send to %s", ifp->name); + + /* Fill in sockaddr_in6. */ + memset (&addr, 0, sizeof (struct sockaddr_in6)); + addr.sin6_family = AF_INET6; +#ifdef SIN6_LEN + addr.sin6_len = sizeof (struct sockaddr_in6); +#endif /* SIN6_LEN */ + addr.sin6_port = htons (IPPROTO_ICMPV6); + memcpy (&addr.sin6_addr, all_nodes_addr, sizeof (struct in6_addr)); + + /* Fetch interface information. */ + zif = ifp->info; + + /* Make router advertisement message. */ + rtadv = (struct nd_router_advert *) buf; + + rtadv->nd_ra_type = ND_ROUTER_ADVERT; + rtadv->nd_ra_code = 0; + rtadv->nd_ra_cksum = 0; + + rtadv->nd_ra_curhoplimit = 64; + rtadv->nd_ra_flags_reserved = 0; + if (zif->rtadv.AdvManagedFlag) + rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED; + if (zif->rtadv.AdvOtherConfigFlag) + rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER; + rtadv->nd_ra_router_lifetime = htons (zif->rtadv.AdvDefaultLifetime); + rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime); + rtadv->nd_ra_retransmit = htonl (0); + + len = sizeof (struct nd_router_advert); + + /* Fill in prefix. */ + for (node = listhead (zif->rtadv.AdvPrefixList); node; node = nextnode (node)) + { + struct nd_opt_prefix_info *pinfo; + struct rtadv_prefix *rprefix; + + rprefix = getdata (node); + + pinfo = (struct nd_opt_prefix_info *) (buf + len); + + pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; + pinfo->nd_opt_pi_len = 4; + pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen; + + pinfo->nd_opt_pi_flags_reserved = 0; + if (rprefix->AdvOnLinkFlag) + pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK; + if (rprefix->AdvAutonomousFlag) + pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO; + + pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime); + pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime); + pinfo->nd_opt_pi_reserved2 = 0; + + memcpy (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.u.prefix6, + sizeof (struct in6_addr)); + +#ifdef DEBUG + { + u_char buf[INET6_ADDRSTRLEN]; + + zlog_info ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix, buf, INET6_ADDRSTRLEN)); + + } +#endif /* DEBUG */ + + len += sizeof (struct nd_opt_prefix_info); + } + + /* Hardware address. */ +#ifdef HAVE_SOCKADDR_DL + sdl = &ifp->sdl; + if (sdl != NULL && sdl->sdl_alen != 0) + { + buf[len++] = ND_OPT_SOURCE_LINKADDR; + buf[len++] = (sdl->sdl_alen + 2) >> 3; + + memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen); + len += sdl->sdl_alen; + } +#else + if (ifp->hw_addr_len != 0) + { + buf[len++] = ND_OPT_SOURCE_LINKADDR; + buf[len++] = (ifp->hw_addr_len + 2) >> 3; + + memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len); + len += ifp->hw_addr_len; + } +#endif /* HAVE_SOCKADDR_DL */ + + msg.msg_name = (void *) &addr; + msg.msg_namelen = sizeof (struct sockaddr_in6); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = (void *) adata; + msg.msg_controllen = sizeof adata; + iov.iov_base = buf; + iov.iov_len = len; + + cmsgptr = (struct cmsghdr *)adata; + cmsgptr->cmsg_len = sizeof adata; + cmsgptr->cmsg_level = IPPROTO_IPV6; + cmsgptr->cmsg_type = IPV6_PKTINFO; + pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr); + memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr)); + pkt->ipi6_ifindex = ifp->ifindex; + + ret = sendmsg (sock, &msg, 0); + if (ret <0) + perror ("sendmsg"); +} + +int +rtadv_timer (struct thread *thread) +{ + listnode node; + struct interface *ifp; + struct zebra_if *zif; + + rtadv->ra_timer = NULL; + rtadv_event (RTADV_TIMER, 1); + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + + if (if_is_loopback (ifp)) + continue; + + zif = ifp->info; + + if (zif->rtadv.AdvSendAdvertisements) + if (--zif->rtadv.AdvIntervalTimer <= 0) + { + zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; + rtadv_send_packet (rtadv->sock, ifp); + } + } + return 0; +} + +void +rtadv_process_solicit (struct interface *ifp) +{ + zlog_info ("Router solicitation received on %s", ifp->name); + + rtadv_send_packet (rtadv->sock, ifp); +} + +void +rtadv_process_advert () +{ + zlog_info ("Router advertisement received"); +} + +void +rtadv_process_packet (u_char *buf, int len, unsigned int ifindex, int hoplimit) +{ + struct icmp6_hdr *icmph; + struct interface *ifp; + struct zebra_if *zif; + + /* Interface search. */ + ifp = if_lookup_by_index (ifindex); + if (ifp == NULL) + { + zlog_warn ("Unknown interface index: %d", ifindex); + return; + } + + if (if_is_loopback (ifp)) + return; + + /* Check interface configuration. */ + zif = ifp->info; + if (! zif->rtadv.AdvSendAdvertisements) + return; + + /* ICMP message length check. */ + if (len < sizeof (struct icmp6_hdr)) + { + zlog_warn ("Invalid ICMPV6 packet length: %d", len); + return; + } + + icmph = (struct icmp6_hdr *) buf; + + /* ICMP message type check. */ + if (icmph->icmp6_type != ND_ROUTER_SOLICIT && + icmph->icmp6_type != ND_ROUTER_ADVERT) + { + zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type); + return; + } + + /* Hoplimit check. */ + if (hoplimit >= 0 && hoplimit != 255) + { + zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet", + hoplimit); + return; + } + + /* Check ICMP message type. */ + if (icmph->icmp6_type == ND_ROUTER_SOLICIT) + rtadv_process_solicit (ifp); + else if (icmph->icmp6_type == ND_ROUTER_ADVERT) + rtadv_process_advert (); + + return; +} + +int +rtadv_read (struct thread *thread) +{ + int sock; + int len; + u_char buf[RTADV_MSG_SIZE]; + struct sockaddr_in6 from; + unsigned int ifindex; + int hoplimit = -1; + + sock = THREAD_FD (thread); + rtadv->ra_read = NULL; + + /* Register myself. */ + rtadv_event (RTADV_READ, sock); + + len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit); + + if (len < 0) + { + zlog_warn ("router solicitation recv failed: %s.", strerror (errno)); + return len; + } + + rtadv_process_packet (buf, len, ifindex, hoplimit); + + return 0; +} + +int +rtadv_make_socket (void) +{ + int sock; + int ret; + struct icmp6_filter filter; + + sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + + /* When we can't make ICMPV6 socket simply back. Router + advertisement feature will not be supported. */ + if (sock < 0) + return -1; + + ret = setsockopt_ipv6_pktinfo (sock, 1); + if (ret < 0) + return ret; + ret = setsockopt_ipv6_checksum (sock, 2); + if (ret < 0) + return ret; + ret = setsockopt_ipv6_multicast_loop (sock, 0); + if (ret < 0) + return ret; + ret = setsockopt_ipv6_unicast_hops (sock, 255); + if (ret < 0) + return ret; + ret = setsockopt_ipv6_multicast_hops (sock, 255); + if (ret < 0) + return ret; + ret = setsockopt_ipv6_hoplimit (sock, 1); + if (ret < 0) + return ret; + + ICMP6_FILTER_SETBLOCKALL(&filter); + ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter); + ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter); + + ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, + sizeof (struct icmp6_filter)); + if (ret < 0) + { + zlog_info ("ICMP6_FILTER set fail: %s", strerror (errno)); + return ret; + } + + return sock; +} + +struct rtadv_prefix * +rtadv_prefix_new () +{ + struct rtadv_prefix *new; + + new = XMALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix)); + memset (new, 0, sizeof (struct rtadv_prefix)); + + return new; +} + +void +rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix) +{ + XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix); +} + +struct rtadv_prefix * +rtadv_prefix_lookup (list rplist, struct prefix *p) +{ + listnode node; + struct rtadv_prefix *rprefix; + + for (node = listhead (rplist); node; node = nextnode (node)) + { + rprefix = getdata (node); + if (prefix_same (&rprefix->prefix, p)) + return rprefix; + } + return NULL; +} + +struct rtadv_prefix * +rtadv_prefix_get (list rplist, struct prefix *p) +{ + struct rtadv_prefix *rprefix; + + rprefix = rtadv_prefix_lookup (rplist, p); + if (rprefix) + return rprefix; + + rprefix = rtadv_prefix_new (); + memcpy (&rprefix->prefix, p, sizeof (struct prefix)); + listnode_add (rplist, rprefix); + + return rprefix; +} + +void +rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp) +{ + struct rtadv_prefix *rprefix; + + rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix); + + /* Set parameters. */ + rprefix->AdvValidLifetime = rp->AdvValidLifetime; + rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime; + rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag; + rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag; +} + +int +rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp) +{ + struct rtadv_prefix *rprefix; + + rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix); + if (rprefix != NULL) + { + listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix); + rtadv_prefix_free (rprefix); + return 1; + } + else + return 0; +} + +DEFUN (ipv6_nd_suppress_ra, + ipv6_nd_suppress_ra_cmd, + "ipv6 nd suppress-ra", + IP_STR + "Neighbor discovery\n" + "Suppress Router Advertisement\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = vty->index; + zif = ifp->info; + + if (if_is_loopback (ifp)) + { + vty_out (vty, "Invalid interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (zif->rtadv.AdvSendAdvertisements) + { + zif->rtadv.AdvSendAdvertisements = 0; + zif->rtadv.AdvIntervalTimer = 0; + rtadv->adv_if_count--; + + if_leave_all_router (rtadv->sock, ifp); + + if (rtadv->adv_if_count == 0) + rtadv_event (RTADV_STOP, 0); + } + + return CMD_SUCCESS; +} + +ALIAS (ipv6_nd_suppress_ra, + no_ipv6_nd_send_ra_cmd, + "no ipv6 nd send-ra", + NO_STR + IP_STR + "Neighbor discovery\n" + "Send Router Advertisement\n"); + +DEFUN (no_ipv6_nd_suppress_ra, + no_ipv6_nd_suppress_ra_cmd, + "no ipv6 nd suppress-ra", + NO_STR + IP_STR + "Neighbor discovery\n" + "Suppress Router Advertisement\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = vty->index; + zif = ifp->info; + + if (if_is_loopback (ifp)) + { + vty_out (vty, "Invalid interface%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (! zif->rtadv.AdvSendAdvertisements) + { + zif->rtadv.AdvSendAdvertisements = 1; + zif->rtadv.AdvIntervalTimer = 0; + rtadv->adv_if_count++; + + if_join_all_router (rtadv->sock, ifp); + + if (rtadv->adv_if_count == 1) + rtadv_event (RTADV_START, rtadv->sock); + } + + return CMD_SUCCESS; +} + +ALIAS (no_ipv6_nd_suppress_ra, + ipv6_nd_send_ra_cmd, + "ipv6 nd send-ra", + IP_STR + "Neighbor discovery\n" + "Send Router Advertisement\n"); + +DEFUN (ipv6_nd_ra_interval, + ipv6_nd_ra_interval_cmd, + "ipv6 nd ra-interval SECONDS", + IP_STR + "Neighbor discovery\n" + "Router Advertisement interval\n" + "Router Advertisement interval in seconds\n") +{ + int interval; + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + interval = atoi (argv[0]); + + if (interval < 0) + { + vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE); + return CMD_WARNING; + } + + zif->rtadv.MaxRtrAdvInterval = interval; + zif->rtadv.MinRtrAdvInterval = 0.33 * interval; + zif->rtadv.AdvIntervalTimer = 0; + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_nd_ra_interval, + no_ipv6_nd_ra_interval_cmd, + "no ipv6 nd ra-interval", + NO_STR + IP_STR + "Neighbor discovery\n" + "Router Advertisement interval\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL; + zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL; + zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; + + return CMD_SUCCESS; +} + +DEFUN (ipv6_nd_ra_lifetime, + ipv6_nd_ra_lifetime_cmd, + "ipv6 nd ra-lifetime SECONDS", + IP_STR + "Neighbor discovery\n" + "Router lifetime\n" + "Router lifetime in seconds\n") +{ + int lifetime; + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + lifetime = atoi (argv[0]); + + if (lifetime < 0 || lifetime > 0xffff) + { + vty_out (vty, "Invalid Router Lifetime%s", VTY_NEWLINE); + return CMD_WARNING; + } + + zif->rtadv.AdvDefaultLifetime = lifetime; + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_nd_ra_lifetime, + no_ipv6_nd_ra_lifetime_cmd, + "no ipv6 nd ra-lifetime", + NO_STR + IP_STR + "Neighbor discovery\n" + "Router lifetime\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME; + + return CMD_SUCCESS; +} + +DEFUN (ipv6_nd_reachable_time, + ipv6_nd_reachable_time_cmd, + "ipv6 nd reachable-time MILLISECONDS", + IP_STR + "Neighbor discovery\n" + "Reachable time\n" + "Reachable time in milliseconds\n") +{ + u_int32_t rtime; + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + rtime = (u_int32_t) atol (argv[0]); + + if (rtime > RTADV_MAX_REACHABLE_TIME) + { + vty_out (vty, "Invalid Reachable time%s", VTY_NEWLINE); + return CMD_WARNING; + } + + zif->rtadv.AdvReachableTime = rtime; + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_nd_reachable_time, + no_ipv6_nd_reachable_time_cmd, + "no ipv6 nd reachable-time", + NO_STR + IP_STR + "Neighbor discovery\n" + "Reachable time\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.AdvReachableTime = 0; + + return CMD_SUCCESS; +} + +DEFUN (ipv6_nd_managed_config_flag, + ipv6_nd_managed_config_flag_cmd, + "ipv6 nd managed-config-flag", + IP_STR + "Neighbor discovery\n" + "Managed address configuration flag\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.AdvManagedFlag = 1; + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_nd_managed_config_flag, + no_ipv6_nd_managed_config_flag_cmd, + "no ipv6 nd managed-config-flag", + NO_STR + IP_STR + "Neighbor discovery\n" + "Managed address configuration flag\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.AdvManagedFlag = 0; + + return CMD_SUCCESS; +} + +DEFUN (ipv6_nd_other_config_flag, + ipv6_nd_other_config_flag_cmd, + "ipv6 nd other-config-flag", + IP_STR + "Neighbor discovery\n" + "Other statefull configuration flag\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.AdvOtherConfigFlag = 1; + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_nd_other_config_flag, + no_ipv6_nd_other_config_flag_cmd, + "no ipv6 nd other-config-flag", + NO_STR + IP_STR + "Neighbor discovery\n" + "Other statefull configuration flag\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.AdvOtherConfigFlag = 0; + + return CMD_SUCCESS; +} + +DEFUN (ipv6_nd_prefix_advertisement, + ipv6_nd_prefix_advertisement_cmd, + "ipv6 nd prefix-advertisement IPV6PREFIX VALID PREFERRED [onlink] [autoconfig]", + IP_STR + "Neighbor discovery\n" + "Prefix information\n" + "IPv6 prefix\n" + "Valid lifetime in seconds\n" + "Preferred lifetime in seconds\n" + "On link flag\n" + "Autonomous address-configuration flag\n") +{ + int i; + int ret; + struct interface *ifp; + struct zebra_if *zebra_if; + struct rtadv_prefix rp; + + ifp = (struct interface *) vty->index; + zebra_if = ifp->info; + + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix); + if (!ret) + { + vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 1) + { + rp.AdvValidLifetime = RTADV_VALID_LIFETIME; + rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME; + rp.AdvOnLinkFlag = 1; + rp.AdvAutonomousFlag = 1; + } + else + { + rp.AdvValidLifetime = (u_int32_t) atol (argv[1]); + rp.AdvPreferredLifetime = (u_int32_t) atol (argv[2]); + if (rp.AdvPreferredLifetime > rp.AdvValidLifetime) + { + vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rp.AdvOnLinkFlag = 0; + rp.AdvAutonomousFlag = 0; + for (i = 3; i < argc; i++) + { + if (! strcmp (argv[i], "onlink")) + rp.AdvOnLinkFlag = 1; + else if (! strcmp (argv[i], "autoconfig")) + rp.AdvAutonomousFlag = 1; + } + } + + rtadv_prefix_set (zebra_if, &rp); + + return CMD_SUCCESS; +} + +ALIAS (ipv6_nd_prefix_advertisement, + ipv6_nd_prefix_advertisement_no_val_cmd, + "ipv6 nd prefix-advertisement IPV6PREFIX", + IP_STR + "Neighbor discovery\n" + "Prefix information\n" + "IPv6 prefix\n"); + +DEFUN (no_ipv6_nd_prefix_advertisement, + no_ipv6_nd_prefix_advertisement_cmd, + "no ipv6 nd prefix-advertisement IPV6PREFIX", + NO_STR + IP_STR + "Neighbor discovery\n" + "Prefix information\n" + "IPv6 prefix\n") +{ + int ret; + struct interface *ifp; + struct zebra_if *zebra_if; + struct rtadv_prefix rp; + + ifp = (struct interface *) vty->index; + zebra_if = ifp->info; + + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix); + if (!ret) + { + vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = rtadv_prefix_reset (zebra_if, &rp); + if (!ret) + { + vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* Write configuration about router advertisement. */ +void +rtadv_config_write (struct vty *vty, struct interface *ifp) +{ + struct zebra_if *zif; + listnode node; + struct rtadv_prefix *rprefix; + u_char buf[INET6_ADDRSTRLEN]; + + if (! rtadv) + return; + + zif = ifp->info; + + if (! if_is_loopback (ifp)) + { + if (zif->rtadv.AdvSendAdvertisements) + vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE); + else + vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE); + } + + if (zif->rtadv.MaxRtrAdvInterval != RTADV_MAX_RTR_ADV_INTERVAL) + vty_out (vty, " ipv6 nd ra-interval %d%s", zif->rtadv.MaxRtrAdvInterval, + VTY_NEWLINE); + + if (zif->rtadv.AdvDefaultLifetime != RTADV_ADV_DEFAULT_LIFETIME) + vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime, + VTY_NEWLINE); + + if (zif->rtadv.AdvReachableTime) + vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime, + VTY_NEWLINE); + + if (zif->rtadv.AdvManagedFlag) + vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE); + + if (zif->rtadv.AdvOtherConfigFlag) + vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE); + + for (node = listhead(zif->rtadv.AdvPrefixList); node; node = nextnode (node)) + { + rprefix = getdata (node); + vty_out (vty, " ipv6 nd prefix-advertisement %s/%d %d %d", + inet_ntop (AF_INET6, &rprefix->prefix.u.prefix6, + buf, INET6_ADDRSTRLEN), + rprefix->prefix.prefixlen, + rprefix->AdvValidLifetime, + rprefix->AdvPreferredLifetime); + if (rprefix->AdvOnLinkFlag) + vty_out (vty, " onlink"); + if (rprefix->AdvAutonomousFlag) + vty_out (vty, " autoconfig"); + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +extern struct thread_master *master; + +void +rtadv_event (enum rtadv_event event, int val) +{ + switch (event) + { + case RTADV_START: + if (! rtadv->ra_read) + rtadv->ra_read = thread_add_read (master, rtadv_read, NULL, val); + if (! rtadv->ra_timer) + rtadv->ra_timer = thread_add_event (master, rtadv_timer, NULL, 0); + break; + case RTADV_STOP: + if (rtadv->ra_timer) + { + thread_cancel (rtadv->ra_timer); + rtadv->ra_timer = NULL; + } + if (rtadv->ra_read) + { + thread_cancel (rtadv->ra_read); + rtadv->ra_read = NULL; + } + break; + case RTADV_TIMER: + if (! rtadv->ra_timer) + rtadv->ra_timer = thread_add_timer (master, rtadv_timer, NULL, val); + break; + case RTADV_READ: + if (! rtadv->ra_read) + rtadv->ra_read = thread_add_read (master, rtadv_read, NULL, val); + break; + default: + break; + } + return; +} + +void +rtadv_init () +{ + int sock; + + sock = rtadv_make_socket (); + if (sock < 0) + return; + + rtadv = rtadv_new (); + rtadv->sock = sock; + + install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_send_ra_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_send_ra_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_no_val_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_advertisement_cmd); +} + +int +if_join_all_router (int sock, struct interface *ifp) +{ + int ret; + + struct ipv6_mreq mreq; + + memset (&mreq, 0, sizeof (struct ipv6_mreq)); + inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr); + mreq.ipv6mr_interface = ifp->ifindex; + + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + (char *) &mreq, sizeof mreq); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno)); + + zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name); + + return 0; +} + +int +if_leave_all_router (int sock, struct interface *ifp) +{ + int ret; + + struct ipv6_mreq mreq; + + memset (&mreq, 0, sizeof (struct ipv6_mreq)); + inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr); + mreq.ipv6mr_interface = ifp->ifindex; + + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + (char *) &mreq, sizeof mreq); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", strerror (errno)); + + zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name); + + return 0; +} + +#else +void +rtadv_init () +{ + /* Empty.*/; +} +#endif /* RTADV && HAVE_IPV6 */ diff --git a/zebra/rtadv.h b/zebra/rtadv.h new file mode 100644 index 0000000..859b2d7 --- /dev/null +++ b/zebra/rtadv.h @@ -0,0 +1,49 @@ +/* Router advertisement + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RTADV_H +#define _ZEBRA_RTADV_H + +/* Router advertisement prefix. */ +struct rtadv_prefix +{ + /* Prefix to be advertised. */ + struct prefix prefix; + + /* The value to be placed in the Valid Lifetime in the Prefix */ + u_int32_t AdvValidLifetime; +#define RTADV_VALID_LIFETIME 2592000 + + /* The value to be placed in the on-link flag */ + int AdvOnLinkFlag; + + /* The value to be placed in the Preferred Lifetime in the Prefix + Information option, in seconds.*/ + u_int32_t AdvPreferredLifetime; +#define RTADV_PREFERRED_LIFETIME 604800 + + /* The value to be placed in the Autonomous Flag. */ + int AdvAutonomousFlag; +}; + +void rtadv_config_write (struct vty *, struct interface *); + +#endif /* _ZEBRA_RTADV_H */ diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c new file mode 100644 index 0000000..435eed8 --- /dev/null +++ b/zebra/rtread_getmsg.c @@ -0,0 +1,229 @@ +/* + * Kernel routing table readup by getmsg(2) + * Copyright (C) 1999 Michael Handler + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "log.h" +#include "if.h" + +#include "zebra/rib.h" + +#include +#include + +/* Solaris defines these in both and , sigh */ +#ifdef SUNOS_5 +#include +#ifndef T_CURRENT +#define T_CURRENT MI_T_CURRENT +#endif /* T_CURRENT */ +#ifndef IRE_CACHE +#define IRE_CACHE 0x0020 /* Cached Route entry */ +#endif /* IRE_CACHE */ +#ifndef IRE_HOST_REDIRECT +#define IRE_HOST_REDIRECT 0x0200 /* Host route entry from redirects */ +#endif /* IRE_HOST_REDIRECT */ +#ifndef IRE_CACHETABLE +#define IRE_CACHETABLE (IRE_CACHE | IRE_BROADCAST | IRE_LOCAL | \ + IRE_LOOPBACK) +#endif /* IRE_CACHETABLE */ +#undef IPOPT_EOL +#undef IPOPT_NOP +#undef IPOPT_LSRR +#undef IPOPT_RR +#undef IPOPT_SSRR +#endif /* SUNOS_5 */ + +#include +#include +#include + +/* device to read IP routing table from */ +#ifndef _PATH_GETMSG_ROUTE +#define _PATH_GETMSG_ROUTE "/dev/ip" +#endif /* _PATH_GETMSG_ROUTE */ + +#define RT_BUFSIZ 8192 + +void handle_route_entry (mib2_ipRouteEntry_t *routeEntry) +{ + struct prefix_ipv4 prefix; + struct in_addr tmpaddr, gateway; + u_char zebra_flags = 0; + + if (routeEntry->ipRouteInfo.re_ire_type & IRE_CACHETABLE) + return; + + if (routeEntry->ipRouteInfo.re_ire_type & IRE_HOST_REDIRECT) + zebra_flags |= ZEBRA_FLAG_SELFROUTE; + + prefix.family = AF_INET; + + tmpaddr.s_addr = routeEntry->ipRouteDest; + prefix.prefix = tmpaddr; + + tmpaddr.s_addr = routeEntry->ipRouteMask; + prefix.prefixlen = ip_masklen (tmpaddr); + + gateway.s_addr = routeEntry->ipRouteNextHop; + + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix, + &gateway, 0, 0, 0, 0); +} + +void route_read () +{ + char storage[RT_BUFSIZ]; + + struct T_optmgmt_req *TLIreq = (struct T_optmgmt_req *) storage; + struct T_optmgmt_ack *TLIack = (struct T_optmgmt_ack *) storage; + struct T_error_ack *TLIerr = (struct T_error_ack *) storage; + + struct opthdr *MIB2hdr; + + mib2_ipRouteEntry_t *routeEntry, *lastRouteEntry; + + struct strbuf msgdata; + int flags, dev, retval, process; + + if ((dev = open (_PATH_GETMSG_ROUTE, O_RDWR)) == -1) { + zlog_warn ("can't open %s: %s", _PATH_GETMSG_ROUTE, + strerror (errno)); + return; + } + + TLIreq->PRIM_type = T_OPTMGMT_REQ; + TLIreq->OPT_offset = sizeof (struct T_optmgmt_req); + TLIreq->OPT_length = sizeof (struct opthdr); + TLIreq->MGMT_flags = T_CURRENT; + + MIB2hdr = (struct opthdr *) &TLIreq[1]; + + MIB2hdr->level = MIB2_IP; + MIB2hdr->name = 0; + MIB2hdr->len = 0; + + msgdata.buf = storage; + msgdata.len = sizeof (struct T_optmgmt_req) + sizeof (struct opthdr); + + flags = 0; + + if (putmsg (dev, &msgdata, NULL, flags) == -1) { + zlog_warn ("putmsg failed: %s", strerror (errno)); + goto exit; + } + + MIB2hdr = (struct opthdr *) &TLIack[1]; + msgdata.maxlen = sizeof (storage); + + while (1) { + flags = 0; + retval = getmsg (dev, &msgdata, NULL, &flags); + + if (retval == -1) { + zlog_warn ("getmsg(ctl) failed: %s", strerror (errno)); + goto exit; + } + + /* This is normal loop termination */ + if (retval == 0 && + msgdata.len >= sizeof (struct T_optmgmt_ack) && + TLIack->PRIM_type == T_OPTMGMT_ACK && + TLIack->MGMT_flags == T_SUCCESS && + MIB2hdr->len == 0) + break; + + if (msgdata.len >= sizeof (struct T_error_ack) && + TLIerr->PRIM_type == T_ERROR_ACK) { + zlog_warn ("getmsg(ctl) returned T_ERROR_ACK: %s", + strerror ((TLIerr->TLI_error == TSYSERR) + ? TLIerr->UNIX_error : EPROTO)); + break; + } + + /* should dump more debugging info to the log statement, + like what GateD does in this instance, but not + critical yet. */ + if (retval != MOREDATA || + msgdata.len < sizeof (struct T_optmgmt_ack) || + TLIack->PRIM_type != T_OPTMGMT_ACK || + TLIack->MGMT_flags != T_SUCCESS) { + errno = ENOMSG; + zlog_warn ("getmsg(ctl) returned bizarreness"); + break; + } + + /* MIB2_IP_21 is the the pseudo-MIB2 ipRouteTable + entry, see . "This isn't the MIB data + you're looking for." */ + process = (MIB2hdr->level == MIB2_IP && + MIB2hdr->name == MIB2_IP_21) ? 1 : 0; + + /* getmsg writes the data buffer out completely, not + to the closest smaller multiple. Unless reassembling + data structures across buffer boundaries is your idea + of a good time, set maxlen to the closest smaller + multiple of the size of the datastructure you're + retrieving. */ + msgdata.maxlen = sizeof (storage) - (sizeof (storage) + % sizeof (mib2_ipRouteEntry_t)); + + msgdata.len = 0; + flags = 0; + + do { + retval = getmsg (dev, NULL, &msgdata, &flags); + + if (retval == -1) { + zlog_warn ("getmsg(data) failed: %s", + strerror (errno)); + goto exit; + } + + if (!(retval == 0 || retval == MOREDATA)) { + zlog_warn ("getmsg(data) returned %d", retval); + goto exit; + } + + if (process) { + if (msgdata.len % + sizeof (mib2_ipRouteEntry_t) != 0) { + zlog_warn ("getmsg(data) returned " +"msgdata.len = %d (%% sizeof (mib2_ipRouteEntry_t) != 0)", msgdata.len); + goto exit; + } + + routeEntry = (mib2_ipRouteEntry_t *) + msgdata.buf; + lastRouteEntry = (mib2_ipRouteEntry_t *) + (msgdata.buf + msgdata.len); + do { + handle_route_entry (routeEntry); + } while (++routeEntry < lastRouteEntry); + } + } while (retval == MOREDATA); + } + +exit: + close (dev); +} diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c new file mode 100644 index 0000000..0b255a5 --- /dev/null +++ b/zebra/rtread_netlink.c @@ -0,0 +1,31 @@ +/* + * Kernel routing table readup by netlink + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +/* Extern from rt_netlink.c */ +void netlink_route_read (); + +void route_read () +{ + netlink_route_read (); +} diff --git a/zebra/rtread_proc.c b/zebra/rtread_proc.c new file mode 100644 index 0000000..320152e --- /dev/null +++ b/zebra/rtread_proc.c @@ -0,0 +1,169 @@ +/* + * Kernel routing readup by /proc filesystem + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "log.h" +#include "if.h" +#include "rib.h" + +/* Proc file system to read IPv4 routing table. */ +#ifndef _PATH_PROCNET_ROUTE +#define _PATH_PROCNET_ROUTE "/proc/net/route" +#endif /* _PATH_PROCNET_ROUTE */ + +/* Proc file system to read IPv6 routing table. */ +#ifndef _PATH_PROCNET_ROUTE6 +#define _PATH_PROCNET_ROUTE6 "/proc/net/ipv6_route" +#endif /* _PATH_PROCNET_ROUTE6 */ + +/* To read interface's name */ +#define INTERFACE_NAMSIZ 20 + +/* Reading buffer for one routing entry. */ +#define RT_BUFSIZ 1024 + +/* Kernel routing table read up by /proc filesystem. */ +int +proc_route_read () +{ + FILE *fp; + char buf[RT_BUFSIZ]; + char iface[INTERFACE_NAMSIZ], dest[9], gate[9], mask[9]; + int flags, refcnt, use, metric, mtu, window, rtt; + + /* Open /proc filesystem */ + fp = fopen (_PATH_PROCNET_ROUTE, "r"); + if (fp == NULL) + { + zlog_warn ("Can't open %s : %s\n", _PATH_PROCNET_ROUTE, strerror (errno)); + return -1; + } + + /* Drop first label line. */ + fgets (buf, RT_BUFSIZ, fp); + + while (fgets (buf, RT_BUFSIZ, fp) != NULL) + { + int n; + struct prefix_ipv4 p; + struct in_addr tmpmask; + struct in_addr gateway; + u_char zebra_flags = 0; + + n = sscanf (buf, "%s %s %s %x %d %d %d %s %d %d %d", + iface, dest, gate, &flags, &refcnt, &use, &metric, + mask, &mtu, &window, &rtt); + if (n != 11) + { + zlog_warn ("can't read all of routing information\n"); + continue; + } + if (! (flags & RTF_UP)) + continue; + if (! (flags & RTF_GATEWAY)) + continue; + + if (flags & RTF_DYNAMIC) + zebra_flags |= ZEBRA_FLAG_SELFROUTE; + + p.family = AF_INET; + sscanf (dest, "%lX", (unsigned long *)&p.prefix); + sscanf (mask, "%lX", (unsigned long *)&tmpmask); + p.prefixlen = ip_masklen (tmpmask); + sscanf (gate, "%lX", (unsigned long *)&gateway); + + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0, 0, 0); + } + + return 0; +} + +#ifdef HAVE_IPV6 +int +proc_ipv6_route_read () +{ + FILE *fp; + char buf [RT_BUFSIZ]; + + /* Open /proc filesystem */ + fp = fopen (_PATH_PROCNET_ROUTE6, "r"); + if (fp == NULL) + { + zlog_warn ("Can't open %s : %s", _PATH_PROCNET_ROUTE6, + strerror (errno)); + return -1; + } + + /* There is no title line, so we don't drop first line. */ + while (fgets (buf, RT_BUFSIZ, fp) != NULL) + { + int n; + char dest[33], src[33], gate[33]; + char iface[INTERFACE_NAMSIZ]; + int dest_plen, src_plen; + int metric, use, refcnt, flags; + struct prefix_ipv6 p; + struct in6_addr gateway; + u_char zebra_flags = 0; + + /* Linux 2.1.x write this information at net/ipv6/route.c + rt6_info_node () */ + n = sscanf (buf, "%32s %02x %32s %02x %32s %08x %08x %08x %08x %s", + dest, &dest_plen, src, &src_plen, gate, + &metric, &use, &refcnt, &flags, iface); + + if (n != 10) + { + /* zlog_warn ("can't read all of routing information %d\n%s\n", n, buf); */ + continue; + } + + if (! (flags & RTF_UP)) + continue; + if (! (flags & RTF_GATEWAY)) + continue; + + if (flags & RTF_DYNAMIC) + zebra_flags |= ZEBRA_FLAG_SELFROUTE; + + p.family = AF_INET6; + str2in6_addr (dest, &p.prefix); + str2in6_addr (gate, &gateway); + p.prefixlen = dest_plen; + + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0); + } + + return 0; +} +#endif /* HAVE_IPV6 */ + +void +route_read () +{ + proc_route_read (); +#ifdef HAVE_IPV6 + proc_ipv6_route_read (); +#endif /* HAVE_IPV6 */ +} diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c new file mode 100644 index 0000000..970c0aa --- /dev/null +++ b/zebra/rtread_sysctl.c @@ -0,0 +1,75 @@ +/* + * Kernel routing table read by sysctl function. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "memory.h" +#include "log.h" + +/* Kernel routing table read up by sysctl function. */ +int +route_read () +{ + caddr_t buf, end, ref; + size_t bufsiz; + struct rt_msghdr *rtm; + void rtm_read (struct rt_msghdr *); + +#define MIBSIZ 6 + int mib[MIBSIZ] = + { + CTL_NET, + PF_ROUTE, + 0, + 0, + NET_RT_DUMP, + 0 + }; + + /* Get buffer size. */ + if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) + { + zlog_warn ("sysctl fail: %s", strerror (errno)); + return -1; + } + + /* Allocate buffer. */ + ref = buf = XMALLOC (MTYPE_TMP, bufsiz); + + /* Read routing table information by calling sysctl(). */ + if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) + { + zlog_warn ("sysctl() fail by %s", strerror (errno)); + return -1; + } + + for (end = buf + bufsiz; buf < end; buf += rtm->rtm_msglen) + { + rtm = (struct rt_msghdr *) buf; + rtm_read (rtm); + } + + /* Free buffer. */ + XFREE (MTYPE_TMP, ref); + + return 0; +} diff --git a/zebra/zebra.conf.sample b/zebra/zebra.conf.sample new file mode 100644 index 0000000..799623a --- /dev/null +++ b/zebra/zebra.conf.sample @@ -0,0 +1,25 @@ +! -*- zebra -*- +! +! zebra sample configuration file +! +! $Id: zebra.conf.sample,v 1.14 1999/02/19 17:26:38 developer Exp $ +! +hostname Router +password zebra +enable password zebra +! +! Interface's description. +! +!interface lo +! description test of desc. +! +!interface sit0 +! multicast + +! +! Static default route sample. +! +!ip route 0.0.0.0/0 203.181.89.241 +! + +!log file zebra.log diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c new file mode 100644 index 0000000..bd4ea32 --- /dev/null +++ b/zebra/zebra_rib.c @@ -0,0 +1,2208 @@ +/* Routing Information Base. + * Copyright (C) 1997, 98, 99, 2001 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "str.h" +#include "command.h" +#include "if.h" +#include "log.h" +#include "sockunion.h" + +#include "zebra/rib.h" +#include "zebra/rt.h" +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/debug.h" + +/* Default rtm_table for all clients */ +extern int rtm_table_default; + +/* Each route type's string and default distance value. */ +struct +{ + int key; + int distance; +} route_info[] = +{ + {ZEBRA_ROUTE_SYSTEM, 0}, + {ZEBRA_ROUTE_KERNEL, 0}, + {ZEBRA_ROUTE_CONNECT, 0}, + {ZEBRA_ROUTE_STATIC, 1}, + {ZEBRA_ROUTE_RIP, 120}, + {ZEBRA_ROUTE_RIPNG, 120}, + {ZEBRA_ROUTE_OSPF, 110}, + {ZEBRA_ROUTE_OSPF6, 110}, + {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */} +}; + +/* Vector for routing table. */ +vector vrf_vector; + +/* Allocate new VRF. */ +struct vrf * +vrf_alloc (char *name) +{ + struct vrf *vrf; + + vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf)); + + /* Put name. */ + if (name) + vrf->name = XSTRDUP (MTYPE_VRF_NAME, name); + + /* Allocate routing table and static table. */ + vrf->table[AFI_IP][SAFI_UNICAST] = route_table_init (); + vrf->table[AFI_IP6][SAFI_UNICAST] = route_table_init (); + vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); + vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); + + return vrf; +} + +/* Free VRF. */ +void +vrf_free (struct vrf *vrf) +{ + if (vrf->name) + XFREE (MTYPE_VRF_NAME, vrf->name); + XFREE (MTYPE_VRF, vrf); +} + +/* Lookup VRF by identifier. */ +struct vrf * +vrf_lookup (u_int32_t id) +{ + return vector_lookup (vrf_vector, id); +} + +/* Lookup VRF by name. */ +struct vrf * +vrf_lookup_by_name (char *name) +{ + int i; + struct vrf *vrf; + + for (i = 0; i < vector_max (vrf_vector); i++) + if ((vrf = vector_slot (vrf_vector, i)) != NULL) + if (vrf->name && name && strcmp (vrf->name, name) == 0) + return vrf; + return NULL; +} + +/* Initialize VRF. */ +void +vrf_init () +{ + struct vrf *default_table; + + /* Allocate VRF vector. */ + vrf_vector = vector_init (1); + + /* Allocate default main table. */ + default_table = vrf_alloc ("Default-IP-Routing-Table"); + + /* Default table index must be 0. */ + vector_set_index (vrf_vector, 0, default_table); +} + +/* Lookup route table. */ +struct route_table * +vrf_table (afi_t afi, safi_t safi, u_int32_t id) +{ + struct vrf *vrf; + + vrf = vrf_lookup (id); + if (! vrf) + return NULL; + + return vrf->table[afi][safi]; +} + +/* Lookup static route table. */ +struct route_table * +vrf_static_table (afi_t afi, safi_t safi, u_int32_t id) +{ + struct vrf *vrf; + + vrf = vrf_lookup (id); + if (! vrf) + return NULL; + + return vrf->stable[afi][safi]; +} + +/* Add nexthop to the end of the list. */ +void +nexthop_add (struct rib *rib, struct nexthop *nexthop) +{ + struct nexthop *last; + + for (last = rib->nexthop; last && last->next; last = last->next) + ; + if (last) + last->next = nexthop; + else + rib->nexthop = nexthop; + nexthop->prev = last; + + rib->nexthop_num++; +} + +/* Delete specified nexthop from the list. */ +void +nexthop_delete (struct rib *rib, struct nexthop *nexthop) +{ + if (nexthop->next) + nexthop->next->prev = nexthop->prev; + if (nexthop->prev) + nexthop->prev->next = nexthop->next; + else + rib->nexthop = nexthop->next; + rib->nexthop_num--; +} + +/* Free nexthop. */ +void +nexthop_free (struct nexthop *nexthop) +{ + if (nexthop->type == NEXTHOP_TYPE_IFNAME && nexthop->ifname) + free (nexthop->ifname); + XFREE (MTYPE_NEXTHOP, nexthop); +} + +struct nexthop * +nexthop_ifindex_add (struct rib *rib, unsigned int ifindex) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IFINDEX; + nexthop->ifindex = ifindex; + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ifname_add (struct rib *rib, char *ifname) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IFNAME; + nexthop->ifname = strdup (ifname); + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV4; + nexthop->gate.ipv4 = *ipv4; + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, + unsigned int ifindex) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + nexthop->gate.ipv4 = *ipv4; + nexthop->ifindex = ifindex; + + nexthop_add (rib, nexthop); + + return nexthop; +} + +#ifdef HAVE_IPV6 +struct nexthop * +nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV6; + nexthop->gate.ipv6 = *ipv6; + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6, + char *ifname) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME; + nexthop->gate.ipv6 = *ipv6; + nexthop->ifname = XSTRDUP (0, ifname); + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, + unsigned int ifindex) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + nexthop->gate.ipv6 = *ipv6; + nexthop->ifindex = ifindex; + + nexthop_add (rib, nexthop); + + return nexthop; +} +#endif /* HAVE_IPV6 */ + + +struct nexthop * +nexthop_blackhole_add (struct rib *rib) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_BLACKHOLE; + SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE); + + nexthop_add (rib, nexthop); + + return nexthop; +} + +/* If force flag is not set, do not modify falgs at all for uninstall + the route from FIB. */ +int +nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, + struct route_node *top) +{ + struct prefix_ipv4 p; + struct route_table *table; + struct route_node *rn; + struct rib *match; + struct nexthop *newhop; + + if (nexthop->type == NEXTHOP_TYPE_IPV4) + nexthop->ifindex = 0; + + if (set) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + + /* Make lookup prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = nexthop->gate.ipv4; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return 0; + + rn = route_node_match (table, (struct prefix *) &p); + while (rn) + { + route_unlock_node (rn); + + /* If lookup self prefix return immidiately. */ + if (rn == top) + return 0; + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + { + /* Directly point connected route. */ + newhop = match->nexthop; + if (newhop && nexthop->type == NEXTHOP_TYPE_IPV4) + nexthop->ifindex = newhop->ifindex; + + return 1; + } + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) + { + for (newhop = match->nexthop; newhop; newhop = newhop->next) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) + && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + if (set) + { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + nexthop->rtype = newhop->type; + if (newhop->type == NEXTHOP_TYPE_IPV4 || + newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + nexthop->rgate.ipv4 = newhop->gate.ipv4; + if (newhop->type == NEXTHOP_TYPE_IFINDEX + || newhop->type == NEXTHOP_TYPE_IFNAME + || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + nexthop->rifindex = newhop->ifindex; + } + return 1; + } + return 0; + } + else + { + return 0; + } + } + } + return 0; +} + +#ifdef HAVE_IPV6 +/* If force flag is not set, do not modify falgs at all for uninstall + the route from FIB. */ +int +nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, + struct route_node *top) +{ + struct prefix_ipv6 p; + struct route_table *table; + struct route_node *rn; + struct rib *match; + struct nexthop *newhop; + + if (nexthop->type == NEXTHOP_TYPE_IPV6) + nexthop->ifindex = 0; + + if (set) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + + /* Make lookup prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_PREFIXLEN; + p.prefix = nexthop->gate.ipv6; + + /* Lookup table. */ + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return 0; + + rn = route_node_match (table, (struct prefix *) &p); + while (rn) + { + route_unlock_node (rn); + + /* If lookup self prefix return immidiately. */ + if (rn == top) + return 0; + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + { + /* Directly point connected route. */ + newhop = match->nexthop; + + if (newhop && nexthop->type == NEXTHOP_TYPE_IPV6) + nexthop->ifindex = newhop->ifindex; + + return 1; + } + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) + { + for (newhop = match->nexthop; newhop; newhop = newhop->next) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) + && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + if (set) + { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + nexthop->rtype = newhop->type; + if (newhop->type == NEXTHOP_TYPE_IPV6 + || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) + nexthop->rgate.ipv6 = newhop->gate.ipv6; + if (newhop->type == NEXTHOP_TYPE_IFINDEX + || newhop->type == NEXTHOP_TYPE_IFNAME + || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) + nexthop->rifindex = newhop->ifindex; + } + return 1; + } + return 0; + } + else + { + return 0; + } + } + } + return 0; +} +#endif /* HAVE_IPV6 */ + +struct rib * +rib_match_ipv4 (struct in_addr addr) +{ + struct prefix_ipv4 p; + struct route_table *table; + struct route_node *rn; + struct rib *match; + struct nexthop *newhop; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return 0; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = addr; + + rn = route_node_match (table, (struct prefix *) &p); + + while (rn) + { + route_unlock_node (rn); + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + /* Directly point connected route. */ + return match; + else + { + for (newhop = match->nexthop; newhop; newhop = newhop->next) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) + return match; + return NULL; + } + } + } + return NULL; +} + +struct rib * +rib_lookup_ipv4 (struct prefix_ipv4 *p) +{ + struct route_table *table; + struct route_node *rn; + struct rib *match; + struct nexthop *nexthop; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return 0; + + rn = route_node_lookup (table, (struct prefix *) p); + + /* No route for this prefix. */ + if (! rn) + return NULL; + + /* Unlock node. */ + route_unlock_node (rn); + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + if (! match || match->type == ZEBRA_ROUTE_BGP) + return NULL; + + if (match->type == ZEBRA_ROUTE_CONNECT) + return match; + + for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + return match; + + return NULL; +} + +#ifdef HAVE_IPV6 +struct rib * +rib_match_ipv6 (struct in6_addr *addr) +{ + struct prefix_ipv6 p; + struct route_table *table; + struct route_node *rn; + struct rib *match; + struct nexthop *newhop; + + /* Lookup table. */ + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return 0; + + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_PREFIXLEN; + IPV6_ADDR_COPY (&p.prefix, addr); + + rn = route_node_match (table, (struct prefix *) &p); + + while (rn) + { + route_unlock_node (rn); + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + /* Directly point connected route. */ + return match; + else + { + for (newhop = match->nexthop; newhop; newhop = newhop->next) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) + return match; + return NULL; + } + } + } + return NULL; +} +#endif /* HAVE_IPV6 */ + +int +nexthop_active_check (struct route_node *rn, struct rib *rib, + struct nexthop *nexthop, int set) +{ + struct interface *ifp; + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IFINDEX: + ifp = if_lookup_by_index (nexthop->ifindex); + if (ifp && if_is_up (ifp)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + break; + case NEXTHOP_TYPE_IFNAME: + case NEXTHOP_TYPE_IPV6_IFNAME: + ifp = if_lookup_by_name (nexthop->ifname); + if (ifp && if_is_up (ifp)) + { + if (set) + nexthop->ifindex = ifp->ifindex; + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + else + { + if (set) + nexthop->ifindex = 0; + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (nexthop_active_ipv4 (rib, nexthop, set, rn)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + break; +#ifdef HAVE_IPV6 + case NEXTHOP_TYPE_IPV6: + if (nexthop_active_ipv6 (rib, nexthop, set, rn)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6)) + { + ifp = if_lookup_by_index (nexthop->ifindex); + if (ifp && if_is_up (ifp)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + else + { + if (nexthop_active_ipv6 (rib, nexthop, set, rn)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + break; +#endif /* HAVE_IPV6 */ + case NEXTHOP_TYPE_BLACKHOLE: + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + break; + default: + break; + } + return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); +} + +int +nexthop_active_update (struct route_node *rn, struct rib *rib, int set) +{ + struct nexthop *nexthop; + int active; + + rib->nexthop_active_num = 0; + UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + rib->nexthop_active_num += nexthop_active_check (rn, rib, nexthop, set); + if (active != CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + } + return rib->nexthop_active_num; +} + +#define RIB_SYSTEM_ROUTE(R) \ + ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) + +void +newrib_free (struct rib *rib) +{ + struct nexthop *nexthop; + struct nexthop *next; + + for (nexthop = rib->nexthop; nexthop; nexthop = next) + { + next = nexthop->next; + nexthop_free (nexthop); + } + XFREE (MTYPE_RIB, rib); +} + +void +rib_install_kernel (struct route_node *rn, struct rib *rib) +{ + int ret = 0; + struct nexthop *nexthop; + + switch (PREFIX_FAMILY (&rn->p)) + { + case AF_INET: + ret = kernel_add_ipv4 (&rn->p, rib); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + ret = kernel_add_ipv6 (&rn->p, rib); + break; +#endif /* HAVE_IPV6 */ + } + + if (ret < 0) + { + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + } +} + +/* Uninstall the route from kernel. */ +int +rib_uninstall_kernel (struct route_node *rn, struct rib *rib) +{ + int ret = 0; + struct nexthop *nexthop; + + switch (PREFIX_FAMILY (&rn->p)) + { + case AF_INET: + ret = kernel_delete_ipv4 (&rn->p, rib); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + ret = kernel_delete_ipv6 (&rn->p, rib); + break; +#endif /* HAVE_IPV6 */ + } + + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + return ret; +} + +/* Uninstall the route from kernel. */ +void +rib_uninstall (struct route_node *rn, struct rib *rib) +{ + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + { + redistribute_delete (&rn->p, rib); + if (! RIB_SYSTEM_ROUTE (rib)) + rib_uninstall_kernel (rn, rib); + UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED); + } +} + +/* Core function for processing routing information base. */ +void +rib_process (struct route_node *rn, struct rib *del) +{ + struct rib *rib; + struct rib *next; + struct rib *fib = NULL; + struct rib *select = NULL; + + for (rib = rn->info; rib; rib = next) + { + next = rib->next; + + /* Currently installed rib. */ + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + fib = rib; + + /* Skip unreachable nexthop. */ + if (! nexthop_active_update (rn, rib, 0)) + continue; + + /* Infinit distance. */ + if (rib->distance == DISTANCE_INFINITY) + continue; + + /* Newly selected rib. */ + if (! select || rib->distance < select->distance + || rib->type == ZEBRA_ROUTE_CONNECT) + select = rib; + } + + /* Deleted route check. */ + if (del && CHECK_FLAG (del->flags, ZEBRA_FLAG_SELECTED)) + fib = del; + + /* Same route is selected. */ + if (select && select == fib) + { + if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) + { + redistribute_delete (&rn->p, select); + if (! RIB_SYSTEM_ROUTE (select)) + rib_uninstall_kernel (rn, select); + + /* Set real nexthop. */ + nexthop_active_update (rn, select, 1); + + if (! RIB_SYSTEM_ROUTE (select)) + rib_install_kernel (rn, select); + redistribute_add (&rn->p, select); + } + return; + } + + /* Uninstall old rib from forwarding table. */ + if (fib) + { + redistribute_delete (&rn->p, fib); + if (! RIB_SYSTEM_ROUTE (fib)) + rib_uninstall_kernel (rn, fib); + UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + + /* Set real nexthop. */ + nexthop_active_update (rn, fib, 1); + } + + /* Install new rib into forwarding table. */ + if (select) + { + /* Set real nexthop. */ + nexthop_active_update (rn, select, 1); + + if (! RIB_SYSTEM_ROUTE (select)) + rib_install_kernel (rn, select); + SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); + redistribute_add (&rn->p, select); + } +} + +/* Add RIB to head of the route node. */ +void +rib_addnode (struct route_node *rn, struct rib *rib) +{ + struct rib *head; + + head = rn->info; + if (head) + head->prev = rib; + rib->next = head; + rn->info = rib; +} + +void +rib_delnode (struct route_node *rn, struct rib *rib) +{ + if (rib->next) + rib->next->prev = rib->prev; + if (rib->prev) + rib->prev->next = rib->next; + else + rn->info = rib->next; +} + +int +rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, + struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id, + u_int32_t metric, u_char distance) +{ + struct rib *rib; + struct rib *same = NULL; + struct route_table *table; + struct route_node *rn; + struct nexthop *nexthop; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return 0; + + /* Make it sure prefixlen is applied to the prefix. */ + apply_mask_ipv4 (p); + + /* Set default distance by route type. */ + if (distance == 0) + { + distance = route_info[type].distance; + + /* iBGP distance is 200. */ + if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) + distance = 200; + } + + /* Lookup route node.*/ + rn = route_node_get (table, (struct prefix *) p); + + /* If same type of route are installed, treat it as a implicit + withdraw. */ + for (rib = rn->info; rib; rib = rib->next) + { + if (rib->type == ZEBRA_ROUTE_CONNECT) + { + nexthop = rib->nexthop; + + /* Duplicate connected route comes in. */ + if (rib->type == type + && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX + && nexthop->ifindex == ifindex) + { + rib->refcnt++; + return 0 ; + } + } + else if (rib->type == type) + { + same = rib; + rib_delnode (rn, same); + route_unlock_node (rn); + break; + } + } + + /* Allocate new rib structure. */ + rib = XMALLOC (MTYPE_RIB, sizeof (struct rib)); + memset (rib, 0, sizeof (struct rib)); + rib->type = type; + rib->distance = distance; + rib->flags = flags; + rib->metric = metric; + rib->nexthop_num = 0; + rib->uptime = time (NULL); + + /* Nexthop settings. */ + if (gate) + { + if (ifindex) + nexthop_ipv4_ifindex_add (rib, gate, ifindex); + else + nexthop_ipv4_add (rib, gate); + } + else + nexthop_ifindex_add (rib, ifindex); + + /* If this route is kernel route, set FIB flag to the route. */ + if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + /* Link new rib to node.*/ + rib_addnode (rn, rib); + + /* Process this route node. */ + rib_process (rn, same); + + /* Free implicit route.*/ + if (same) + newrib_free (same); + + return 0; +} + +int +rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib) +{ + struct route_table *table; + struct route_node *rn; + struct rib *same; + struct nexthop *nexthop; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return 0; + + /* Make it sure prefixlen is applied to the prefix. */ + apply_mask_ipv4 (p); + + /* Set default distance by route type. */ + if (rib->distance == 0) + { + rib->distance = route_info[rib->type].distance; + + /* iBGP distance is 200. */ + if (rib->type == ZEBRA_ROUTE_BGP + && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP)) + rib->distance = 200; + } + + /* Lookup route node.*/ + rn = route_node_get (table, (struct prefix *) p); + + /* If same type of route are installed, treat it as a implicit + withdraw. */ + for (same = rn->info; same; same = same->next) + { + if (same->type == rib->type && same->table == rib->table + && same->type != ZEBRA_ROUTE_CONNECT) + { + rib_delnode (rn, same); + route_unlock_node (rn); + break; + } + } + + /* If this route is kernel route, set FIB flag to the route. */ + if (rib->type == ZEBRA_ROUTE_KERNEL || rib->type == ZEBRA_ROUTE_CONNECT) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + /* Link new rib to node.*/ + rib_addnode (rn, rib); + + /* Process this route node. */ + rib_process (rn, same); + + /* Free implicit route.*/ + if (same) + newrib_free (same); + + return 0; +} + +int +rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, + struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct rib *fib = NULL; + struct rib *same = NULL; + struct nexthop *nexthop; + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return 0; + + /* Apply mask. */ + apply_mask_ipv4 (p); + + /* Lookup route node. */ + rn = route_node_lookup (table, (struct prefix *) p); + if (! rn) + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_info ("route %s/%d via %s ifindex %d doesn't exist in rib", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntop (AF_INET, gate, buf2, BUFSIZ), + ifindex); + else + zlog_info ("route %s/%d ifindex %d doesn't exist in rib", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex); + } + return ZEBRA_ERR_RTNOEXIST; + } + + /* Lookup same type route. */ + for (rib = rn->info; rib; rib = rib->next) + { + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + fib = rib; + + if (rib->type == ZEBRA_ROUTE_CONNECT) + { + nexthop = rib->nexthop; + + if (rib->type == type + && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX + && nexthop->ifindex == ifindex) + { + if (rib->refcnt) + { + rib->refcnt--; + route_unlock_node (rn); + route_unlock_node (rn); + return 0; + } + same = rib; + break; + } + } + else + { + if (rib->type == type) + { + same = rib; + break; + } + } + } + + /* If same type of route can't be found and this message is from + kernel. */ + if (! same) + { + if (fib && type == ZEBRA_ROUTE_KERNEL) + { + /* Unset flags. */ + for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + } + else + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_info ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntop (AF_INET, gate, buf2, BUFSIZ), + ifindex, + type); + else + zlog_info ("route %s/%d ifindex %d type %d doesn't exist in rib", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex, + type); + } + route_unlock_node (rn); + return ZEBRA_ERR_RTNOEXIST; + } + } + + if (same) + rib_delnode (rn, same); + + /* Process changes. */ + rib_process (rn, same); + + if (same) + { + newrib_free (same); + route_unlock_node (rn); + } + + route_unlock_node (rn); + + return 0; +} + +/* Install static route into rib. */ +void +static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) +{ + struct rib *rib; + struct route_node *rn; + struct route_table *table; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return; + + /* Lookup existing route */ + rn = route_node_get (table, p); + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + + if (rib) + { + /* Same distance static route is there. Update it with new + nexthop. */ + rib_uninstall (rn, rib); + route_unlock_node (rn); + + switch (si->type) + { + case STATIC_IPV4_GATEWAY: + nexthop_ipv4_add (rib, &si->gate.ipv4); + break; + case STATIC_IPV4_IFNAME: + nexthop_ifname_add (rib, si->gate.ifname); + break; + case STATIC_IPV4_BLACKHOLE: + nexthop_blackhole_add (rib); + break; + } + rib_process (rn, NULL); + } + else + { + /* This is new static route. */ + rib = XMALLOC (MTYPE_RIB, sizeof (struct rib)); + memset (rib, 0, sizeof (struct rib)); + + rib->type = ZEBRA_ROUTE_STATIC; + rib->distance = si->distance; + rib->metric = 0; + rib->nexthop_num = 0; + + switch (si->type) + { + case STATIC_IPV4_GATEWAY: + nexthop_ipv4_add (rib, &si->gate.ipv4); + break; + case STATIC_IPV4_IFNAME: + nexthop_ifname_add (rib, si->gate.ifname); + break; + case STATIC_IPV4_BLACKHOLE: + nexthop_blackhole_add (rib); + break; + } + + /* Link this rib to the tree. */ + rib_addnode (rn, rib); + + /* Process this prefix. */ + rib_process (rn, NULL); + } +} + +int +static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_ipv4 *si) +{ + if (nexthop->type == NEXTHOP_TYPE_IPV4 + && si->type == STATIC_IPV4_GATEWAY + && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->gate.ipv4)) + return 1; + if (nexthop->type == NEXTHOP_TYPE_IFNAME + && si->type == STATIC_IPV4_IFNAME + && strcmp (nexthop->ifname, si->gate.ifname) == 0) + return 1; + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE + && si->type == STATIC_IPV4_BLACKHOLE) + return 1; + return 0;; +} + +/* Uninstall static route from RIB. */ +void +static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) +{ + struct route_node *rn; + struct rib *rib; + struct nexthop *nexthop; + struct route_table *table; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return; + + /* Lookup existing route with type and distance. */ + rn = route_node_lookup (table, p); + if (! rn) + return; + + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + + if (! rib) + { + route_unlock_node (rn); + return; + } + + /* Lookup nexthop. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (static_ipv4_nexthop_same (nexthop, si)) + break; + + /* Can't find nexthop. */ + if (! nexthop) + { + route_unlock_node (rn); + return; + } + + /* Check nexthop. */ + if (rib->nexthop_num == 1) + { + rib_delnode (rn, rib); + rib_process (rn, rib); + newrib_free (rib); + route_unlock_node (rn); + } + else + { + rib_uninstall (rn, rib); + nexthop_delete (rib, nexthop); + nexthop_free (nexthop); + rib_process (rn, rib); + } + + /* Unlock node. */ + route_unlock_node (rn); +} + +/* Add static route into static route configuration. */ +int +static_add_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname, + u_char distance, u_int32_t vrf_id) +{ + u_char type = 0; + struct route_node *rn; + struct static_ipv4 *si; + struct static_ipv4 *pp; + struct static_ipv4 *cp; + struct static_ipv4 *update = NULL; + struct route_table *stable; + + /* Lookup table. */ + stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id); + if (! stable) + return -1; + + /* Lookup static route prefix. */ + rn = route_node_get (stable, p); + + /* Make flags. */ + if (gate) + type = STATIC_IPV4_GATEWAY; + else if (ifname) + type = STATIC_IPV4_IFNAME; + else + type = STATIC_IPV4_BLACKHOLE; + + /* Do nothing if there is a same static route. */ + for (si = rn->info; si; si = si->next) + { + if (type == si->type + && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4)) + && (! ifname || strcmp (ifname, si->gate.ifname) == 0)) + { + if (distance == si->distance) + { + route_unlock_node (rn); + return 0; + } + else + update = si; + } + } + + /* Distance chaged. */ + if (update) + static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id); + + /* Make new static route structure. */ + si = XMALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4)); + memset (si, 0, sizeof (struct static_ipv4)); + + si->type = type; + si->distance = distance; + + if (gate) + si->gate.ipv4 = *gate; + if (ifname) + si->gate.ifname = XSTRDUP (0, ifname); + + /* Add new static route information to the tree with sort by + distance value and gateway address. */ + for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) + { + if (si->distance < cp->distance) + break; + if (si->distance > cp->distance) + continue; + if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY) + { + if (ntohl (si->gate.ipv4.s_addr) < ntohl (cp->gate.ipv4.s_addr)) + break; + if (ntohl (si->gate.ipv4.s_addr) > ntohl (cp->gate.ipv4.s_addr)) + continue; + } + } + + /* Make linked list. */ + if (pp) + pp->next = si; + else + rn->info = si; + if (cp) + cp->prev = si; + si->prev = pp; + si->next = cp; + + /* Install into rib. */ + static_install_ipv4 (p, si); + + return 1; +} + +/* Delete static route from static route configuration. */ +int +static_delete_ipv4 (struct prefix *p, struct in_addr *gate, char *ifname, + u_char distance, u_int32_t vrf_id) +{ + u_char type = 0; + struct route_node *rn; + struct static_ipv4 *si; + struct route_table *stable; + + /* Lookup table. */ + stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id); + if (! stable) + return -1; + + /* Lookup static route prefix. */ + rn = route_node_lookup (stable, p); + if (! rn) + return 0; + + /* Make flags. */ + if (gate) + type = STATIC_IPV4_GATEWAY; + else if (ifname) + type = STATIC_IPV4_IFNAME; + else + type = STATIC_IPV4_BLACKHOLE; + + /* Find same static route is the tree */ + for (si = rn->info; si; si = si->next) + if (type == si->type + && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4)) + && (! ifname || strcmp (ifname, si->gate.ifname) == 0)) + break; + + /* Can't find static route. */ + if (! si) + { + route_unlock_node (rn); + return 0; + } + + /* Install into rib. */ + static_uninstall_ipv4 (p, si); + + /* Unlink static route from linked list. */ + if (si->prev) + si->prev->next = si->next; + else + rn->info = si->next; + if (si->next) + si->next->prev = si->prev; + + /* Free static route configuration. */ + XFREE (MTYPE_STATIC_IPV4, si); + + return 1; +} + + +#ifdef HAVE_IPV6 +int +rib_bogus_ipv6 (int type, struct prefix_ipv6 *p, + struct in6_addr *gate, unsigned int ifindex, int table) +{ + if (type == ZEBRA_ROUTE_CONNECT && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)) + return 1; + if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix) + && p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate)) + { + kernel_delete_ipv6_old (p, gate, ifindex, 0, table); + return 1; + } + return 0; +} + +int +rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, + struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id) +{ + struct rib *rib; + struct rib *same = NULL; + struct route_table *table; + struct route_node *rn; + struct nexthop *nexthop; + + int distance; + u_int32_t metric = 0; + + /* Lookup table. */ + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return 0; + + /* Make sure mask is applied. */ + apply_mask_ipv6 (p); + + /* Set default distance by route type. */ + distance = route_info[type].distance; + + if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) + distance = 200; + + /* Filter bogus route. */ + if (rib_bogus_ipv6 (type, p, gate, ifindex, 0)) + return 0; + + /* Lookup route node.*/ + rn = route_node_get (table, (struct prefix *) p); + + /* If same type of route are installed, treat it as a implicit + withdraw. */ + for (rib = rn->info; rib; rib = rib->next) + { + if (rib->type == ZEBRA_ROUTE_CONNECT) + { + nexthop = rib->nexthop; + + if (rib->type == type + && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX + && nexthop->ifindex == ifindex) + { + rib->refcnt++; + return 0; + } + } + else if (rib->type == type) + { + same = rib; + rib_delnode (rn, same); + route_unlock_node (rn); + break; + } + } + + /* Allocate new rib structure. */ + rib = XMALLOC (MTYPE_RIB, sizeof (struct rib)); + memset (rib, 0, sizeof (struct rib)); + rib->type = type; + rib->distance = distance; + rib->flags = flags; + rib->metric = metric; + rib->nexthop_num = 0; + rib->uptime = time (NULL); + + /* Nexthop settings. */ + if (gate) + { + if (ifindex) + nexthop_ipv6_ifindex_add (rib, gate, ifindex); + else + nexthop_ipv6_add (rib, gate); + } + else + nexthop_ifindex_add (rib, ifindex); + + /* If this route is kernel route, set FIB flag to the route. */ + if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + /* Link new rib to node.*/ + rib_addnode (rn, rib); + + /* Process this route node. */ + rib_process (rn, same); + + /* Free implicit route.*/ + if (same) + newrib_free (same); + + return 0; +} + +int +rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, + struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct rib *fib = NULL; + struct rib *same = NULL; + struct nexthop *nexthop; + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; + + /* Apply mask. */ + apply_mask_ipv6 (p); + + /* Lookup table. */ + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return 0; + + /* Lookup route node. */ + rn = route_node_lookup (table, (struct prefix *) p); + if (! rn) + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_info ("route %s/%d via %s ifindex %d doesn't exist in rib", + inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntop (AF_INET6, gate, buf2, BUFSIZ), + ifindex); + else + zlog_info ("route %s/%d ifindex %d doesn't exist in rib", + inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex); + } + return ZEBRA_ERR_RTNOEXIST; + } + + /* Lookup same type route. */ + for (rib = rn->info; rib; rib = rib->next) + { + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + fib = rib; + + if (rib->type == ZEBRA_ROUTE_CONNECT) + { + nexthop = rib->nexthop; + + if (rib->type == type + && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX + && nexthop->ifindex == ifindex) + { + if (rib->refcnt) + { + rib->refcnt--; + route_unlock_node (rn); + route_unlock_node (rn); + return 0; + } + same = rib; + break; + } + } + else + { + if (rib->type == type) + { + same = rib; + break; + } + } + } + + /* If same type of route can't be found and this message is from + kernel. */ + if (! same) + { + if (fib && type == ZEBRA_ROUTE_KERNEL) + { + /* Unset flags. */ + for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + } + else + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_info ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", + inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntop (AF_INET6, gate, buf2, BUFSIZ), + ifindex, + type); + else + zlog_info ("route %s/%d ifindex %d type %d doesn't exist in rib", + inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex, + type); + } + route_unlock_node (rn); + return ZEBRA_ERR_RTNOEXIST; + } + } + + if (same) + rib_delnode (rn, same); + + /* Process changes. */ + rib_process (rn, same); + + if (same) + { + newrib_free (same); + route_unlock_node (rn); + } + + route_unlock_node (rn); + + return 0; +} + +/* Install static route into rib. */ +void +static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) +{ + struct rib *rib; + struct route_table *table; + struct route_node *rn; + + /* Lookup table. */ + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return; + + /* Lookup existing route */ + rn = route_node_get (table, p); + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + + if (rib) + { + /* Same distance static route is there. Update it with new + nexthop. */ + rib_uninstall (rn, rib); + route_unlock_node (rn); + + switch (si->type) + { + case STATIC_IPV6_GATEWAY: + nexthop_ipv6_add (rib, &si->ipv6); + break; + case STATIC_IPV6_IFNAME: + nexthop_ifname_add (rib, si->ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); + break; + case STATIC_IPV6_BLACKHOLE: + nexthop_blackhole_add (rib); + break; + } + rib_process (rn, NULL); + } + else + { + /* This is new static route. */ + rib = XMALLOC (MTYPE_RIB, sizeof (struct rib)); + memset (rib, 0, sizeof (struct rib)); + + rib->type = ZEBRA_ROUTE_STATIC; + rib->distance = si->distance; + rib->metric = 0; + rib->nexthop_num = 0; + + switch (si->type) + { + case STATIC_IPV6_GATEWAY: + nexthop_ipv6_add (rib, &si->ipv6); + break; + case STATIC_IPV6_IFNAME: + nexthop_ifname_add (rib, si->ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); + break; + case STATIC_IPV6_BLACKHOLE: + nexthop_blackhole_add (rib); + break; + } + + /* Link this rib to the tree. */ + rib_addnode (rn, rib); + + /* Process this prefix. */ + rib_process (rn, NULL); + } +} + +int +static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_ipv6 *si) +{ + if (nexthop->type == NEXTHOP_TYPE_IPV6 + && si->type == STATIC_IPV6_GATEWAY + && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6)) + return 1; + if (nexthop->type == NEXTHOP_TYPE_IFNAME + && si->type == STATIC_IPV6_IFNAME + && strcmp (nexthop->ifname, si->ifname) == 0) + return 1; + if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + && si->type == STATIC_IPV6_GATEWAY_IFNAME + && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6) + && strcmp (nexthop->ifname, si->ifname) == 0) + return 1; + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE + && si->type == STATIC_IPV6_BLACKHOLE) + return 1; + return 0;; +} + +void +static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct nexthop *nexthop; + + /* Lookup table. */ + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return; + + /* Lookup existing route with type and distance. */ + rn = route_node_lookup (table, (struct prefix *) p); + if (! rn) + return; + + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + if (! rib) + { + route_unlock_node (rn); + return; + } + + /* Lookup nexthop. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (static_ipv6_nexthop_same (nexthop, si)) + break; + + /* Can't find nexthop. */ + if (! nexthop) + { + route_unlock_node (rn); + return; + } + + /* Check nexthop. */ + if (rib->nexthop_num == 1) + { + rib_delnode (rn, rib); + rib_process (rn, rib); + newrib_free (rib); + route_unlock_node (rn); + } + else + { + rib_uninstall (rn, rib); + nexthop_delete (rib, nexthop); + nexthop_free (nexthop); + rib_process (rn, rib); + } + + /* Unlock node. */ + route_unlock_node (rn); +} + +/* Add static route into static route configuration. */ +int +static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, + char *ifname, u_char distance, u_int32_t vrf_id) +{ + struct route_node *rn; + struct static_ipv6 *si; + struct static_ipv6 *pp; + struct static_ipv6 *cp; + struct route_table *stable; + + /* Lookup table. */ + stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id); + if (! stable) + return -1; + + /* Lookup static route prefix. */ + rn = route_node_get (stable, p); + + /* Do nothing if there is a same static route. */ + for (si = rn->info; si; si = si->next) + { + if (distance == si->distance + && type == si->type + && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6)) + && (! ifname || strcmp (ifname, si->ifname) == 0)) + { + route_unlock_node (rn); + return 0; + } + } + + /* Make new static route structure. */ + si = XMALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6)); + memset (si, 0, sizeof (struct static_ipv6)); + + si->type = type; + si->distance = distance; + + switch (type) + { + case STATIC_IPV6_GATEWAY: + si->ipv6 = *gate; + break; + case STATIC_IPV6_IFNAME: + si->ifname = XSTRDUP (0, ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + si->ipv6 = *gate; + si->ifname = XSTRDUP (0, ifname); + break; + } + + /* Add new static route information to the tree with sort by + distance value and gateway address. */ + for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) + { + if (si->distance < cp->distance) + break; + if (si->distance > cp->distance) + continue; + } + + /* Make linked list. */ + if (pp) + pp->next = si; + else + rn->info = si; + if (cp) + cp->prev = si; + si->prev = pp; + si->next = cp; + + /* Install into rib. */ + static_install_ipv6 (p, si); + + return 1; +} + +/* Delete static route from static route configuration. */ +int +static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, + char *ifname, u_char distance, u_int32_t vrf_id) +{ + struct route_node *rn; + struct static_ipv6 *si; + struct route_table *stable; + + /* Lookup table. */ + stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id); + if (! stable) + return -1; + + /* Lookup static route prefix. */ + rn = route_node_lookup (stable, p); + if (! rn) + return 0; + + /* Find same static route is the tree */ + for (si = rn->info; si; si = si->next) + if (distance == si->distance + && type == si->type + && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6)) + && (! ifname || strcmp (ifname, si->ifname) == 0)) + break; + + /* Can't find static route. */ + if (! si) + { + route_unlock_node (rn); + return 0; + } + + /* Install into rib. */ + static_uninstall_ipv6 (p, si); + + /* Unlink static route from linked list. */ + if (si->prev) + si->prev->next = si->next; + else + rn->info = si->next; + if (si->next) + si->next->prev = si->prev; + + /* Free static route configuration. */ + XFREE (MTYPE_STATIC_IPV6, si); + + return 1; +} +#endif /* HAVE_IPV6 */ + +/* RIB update function. */ +void +rib_update () +{ + struct route_node *rn; + struct route_table *table; + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + rib_process (rn, NULL); + + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + rib_process (rn, NULL); +} + +/* Interface goes up. */ +void +rib_if_up (struct interface *ifp) +{ + rib_update (); +} + +/* Interface goes down. */ +void +rib_if_down (struct interface *ifp) +{ + rib_update (); +} + +/* Remove all routes which comes from non main table. */ +void +rib_weed_table (struct route_table *table) +{ + struct route_node *rn; + struct rib *rib; + struct rib *next; + + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = next) + { + next = rib->next; + + if (rib->table != rtm_table_default && + rib->table != RT_TABLE_MAIN) + { + rib_delnode (rn, rib); + newrib_free (rib); + route_unlock_node (rn); + } + } +} + +/* Delete all routes from non main table. */ +void +rib_weed_tables () +{ + rib_weed_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); + rib_weed_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); +} + +/* Delete self installed routes after zebra is relaunched. */ +void +rib_sweep_table (struct route_table *table) +{ + struct route_node *rn; + struct rib *rib; + struct rib *next; + int ret = 0; + + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = next) + { + next = rib->next; + + if (rib->type == ZEBRA_ROUTE_KERNEL && + CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE)) + { + ret = rib_uninstall_kernel (rn, rib); + if (! ret) + { + rib_delnode (rn, rib); + newrib_free (rib); + route_unlock_node (rn); + } + } + } +} + +/* Sweep all RIB tables. */ +void +rib_sweep_route () +{ + rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); + rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); +} + +/* Close RIB and clean up kernel routes. */ +void +rib_close_table (struct route_table *table) +{ + struct route_node *rn; + struct rib *rib; + + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (! RIB_SYSTEM_ROUTE (rib) + && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + rib_uninstall_kernel (rn, rib); +} + +/* Close all RIB tables. */ +void +rib_close () +{ + rib_close_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); + rib_close_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); +} + +/* Routing information base initialize. */ +void +rib_init () +{ + /* VRF initialization. */ + vrf_init (); +} diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c new file mode 100644 index 0000000..b7f1287 --- /dev/null +++ b/zebra/zebra_snmp.c @@ -0,0 +1,570 @@ +/* FIB SNMP. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#ifdef HAVE_SNMP + +#ifdef HAVE_NETSNMP +#include +#endif /* HAVE_NETSNMP */ + +#include +#include +#include + +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "command.h" +#include "smux.h" +#include "table.h" + +#include "zebra/rib.h" + +#define IPFWMIB 1,3,6,1,2,1,4,24 +#define ZEBRAOID 1,3,6,1,4,1,3317,1,2,1 + +/* ipForwardTable */ +#define IPFORWARDDEST 1 +#define IPFORWARDMASK 2 +#define IPFORWARDPOLICY 3 +#define IPFORWARDNEXTHOP 4 +#define IPFORWARDIFINDEX 5 +#define IPFORWARDTYPE 6 +#define IPFORWARDPROTO 7 +#define IPFORWARDAGE 8 +#define IPFORWARDINFO 9 +#define IPFORWARDNEXTHOPAS 10 +#define IPFORWARDMETRIC1 11 +#define IPFORWARDMETRIC2 12 +#define IPFORWARDMETRIC3 13 +#define IPFORWARDMETRIC4 14 +#define IPFORWARDMETRIC5 15 + +/* ipCidrRouteTable */ +#define IPCIDRROUTEDEST 1 +#define IPCIDRROUTEMASK 2 +#define IPCIDRROUTETOS 3 +#define IPCIDRROUTENEXTHOP 4 +#define IPCIDRROUTEIFINDEX 5 +#define IPCIDRROUTETYPE 6 +#define IPCIDRROUTEPROTO 7 +#define IPCIDRROUTEAGE 8 +#define IPCIDRROUTEINFO 9 +#define IPCIDRROUTENEXTHOPAS 10 +#define IPCIDRROUTEMETRIC1 11 +#define IPCIDRROUTEMETRIC2 12 +#define IPCIDRROUTEMETRIC3 13 +#define IPCIDRROUTEMETRIC4 14 +#define IPCIDRROUTEMETRIC5 15 +#define IPCIDRROUTESTATUS 16 + +#define INTEGER32 ASN_INTEGER +#define GAUGE32 ASN_GAUGE +#define ENUMERATION ASN_INTEGER +#define ROWSTATUS ASN_INTEGER +#define IPADDRESS ASN_IPADDRESS +#define OBJECTIDENTIFIER ASN_OBJECT_ID + +oid ipfw_oid [] = { IPFWMIB }; +oid zebra_oid [] = { ZEBRAOID }; + +/* Hook functions. */ +u_char * ipFwNumber (); +u_char * ipFwTable (); +u_char * ipCidrNumber (); +u_char * ipCidrTable (); + +struct variable zebra_variables[] = + { + {0, GAUGE32, RONLY, ipFwNumber, 1, {1}}, + {IPFORWARDDEST, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 1}}, + {IPFORWARDMASK, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 2}}, + {IPFORWARDPOLICY, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 3}}, + {IPFORWARDNEXTHOP, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 4}}, + {IPFORWARDIFINDEX, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 5}}, + {IPFORWARDTYPE, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 6}}, + {IPFORWARDPROTO, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 7}}, + {IPFORWARDAGE, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 8}}, + {IPFORWARDINFO, OBJECTIDENTIFIER, RONLY, ipFwTable, 3, {2, 1, 9}}, + {IPFORWARDNEXTHOPAS, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 10}}, + {IPFORWARDMETRIC1, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 11}}, + {IPFORWARDMETRIC2, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 12}}, + {IPFORWARDMETRIC3, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 13}}, + {IPFORWARDMETRIC4, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 14}}, + {IPFORWARDMETRIC5, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 15}}, + {0, GAUGE32, RONLY, ipCidrNumber, 1, {3}}, + {IPCIDRROUTEDEST, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 1}}, + {IPCIDRROUTEMASK, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 2}}, + {IPCIDRROUTETOS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 3}}, + {IPCIDRROUTENEXTHOP, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 4}}, + {IPCIDRROUTEIFINDEX, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 5}}, + {IPCIDRROUTETYPE, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 6}}, + {IPCIDRROUTEPROTO, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 7}}, + {IPCIDRROUTEAGE, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 8}}, + {IPCIDRROUTEINFO, OBJECTIDENTIFIER, RONLY, ipCidrTable, 3, {4, 1, 9}}, + {IPCIDRROUTENEXTHOPAS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 10}}, + {IPCIDRROUTEMETRIC1, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 11}}, + {IPCIDRROUTEMETRIC2, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 12}}, + {IPCIDRROUTEMETRIC3, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 13}}, + {IPCIDRROUTEMETRIC4, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 14}}, + {IPCIDRROUTEMETRIC5, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 15}}, + {IPCIDRROUTESTATUS, ROWSTATUS, RONLY, ipCidrTable, 3, {4, 1, 16}} + }; + + +u_char * +ipFwNumber (struct variable *v, oid objid[], size_t *objid_len, + int exact, size_t *val_len, WriteMethod **write_method) +{ + static int result; + struct route_table *table; + struct route_node *rn; + struct rib *rib; + + if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) + return NULL; + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return NULL; + + /* Return number of routing entries. */ + result = 0; + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + result++; + + return (u_char *)&result; +} + +u_char * +ipCidrNumber (struct variable *v, oid objid[], size_t *objid_len, + int exact, size_t *val_len, WriteMethod **write_method) +{ + static int result; + struct route_table *table; + struct route_node *rn; + struct rib *rib; + + if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) + return NULL; + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return 0; + + /* Return number of routing entries. */ + result = 0; + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + result++; + + return (u_char *)&result; +} + +int +in_addr_cmp(u_char *p1, u_char *p2) +{ + int i; + + for (i=0; i<4; i++) + { + if (*p1 < *p2) + return -1; + if (*p1 > *p2) + return 1; + p1++; p2++; + } + return 0; +} + +int +in_addr_add(u_char *p, int num) +{ + int i, ip0; + + ip0 = *p; + p += 4; + for (i = 3; 0 <= i; i--) { + p--; + if (*p + num > 255) { + *p += num; + num = 1; + } else { + *p += num; + return 1; + } + } + if (ip0 > *p) { + /* ip + num > 0xffffffff */ + return 0; + } + + return 1; +} + +int proto_trans(int type) +{ + switch (type) + { + case ZEBRA_ROUTE_SYSTEM: + return 1; /* other */ + case ZEBRA_ROUTE_KERNEL: + return 1; /* other */ + case ZEBRA_ROUTE_CONNECT: + return 2; /* local interface */ + case ZEBRA_ROUTE_STATIC: + return 3; /* static route */ + case ZEBRA_ROUTE_RIP: + return 8; /* rip */ + case ZEBRA_ROUTE_RIPNG: + return 1; /* shouldn't happen */ + case ZEBRA_ROUTE_OSPF: + return 13; /* ospf */ + case ZEBRA_ROUTE_OSPF6: + return 1; /* shouldn't happen */ + case ZEBRA_ROUTE_BGP: + return 14; /* bgp */ + default: + return 1; /* other */ + } +} + +void +check_replace(struct route_node *np2, struct rib *rib2, + struct route_node **np, struct rib **rib) +{ + int proto, proto2; + + if (!*np) + { + *np = np2; + *rib = rib2; + return; + } + + if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) < 0) + return; + if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) > 0) + { + *np = np2; + *rib = rib2; + return; + } + + proto = proto_trans((*rib)->type); + proto2 = proto_trans(rib2->type); + + if (proto2 > proto) + return; + if (proto2 < proto) + { + *np = np2; + *rib = rib2; + return; + } + + if (in_addr_cmp((u_char *)&(*rib)->nexthop->gate.ipv4, + (u_char *)&rib2->nexthop->gate.ipv4) <= 0) + return; + + *np = np2; + *rib = rib2; + return; +} + +void +get_fwtable_route_node(struct variable *v, oid objid[], size_t *objid_len, + int exact, struct route_node **np, struct rib **rib) +{ + struct in_addr dest; + struct route_table *table; + struct route_node *np2; + struct rib *rib2; + int proto; + int policy; + struct in_addr nexthop; + u_char *pnt; + int i; + + /* Init index variables */ + + pnt = (u_char *) &dest; + for (i = 0; i < 4; i++) + *pnt++ = 0; + + pnt = (u_char *) &nexthop; + for (i = 0; i < 4; i++) + *pnt++ = 0; + + proto = 0; + policy = 0; + + /* Init return variables */ + + *np = NULL; + *rib = NULL; + + /* Short circuit exact matches of wrong length */ + + if (exact && (*objid_len != v->namelen + 10)) + return; + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return; + + /* Get INDEX information out of OID. + * ipForwardDest, ipForwardProto, ipForwardPolicy, ipForwardNextHop + */ + + if (*objid_len > v->namelen) + oid2in_addr (objid + v->namelen, MIN(4, *objid_len - v->namelen), &dest); + + if (*objid_len > v->namelen + 4) + proto = objid[v->namelen + 4]; + + if (*objid_len > v->namelen + 5) + policy = objid[v->namelen + 5]; + + if (*objid_len > v->namelen + 6) + oid2in_addr (objid + v->namelen + 6, MIN(4, *objid_len - v->namelen - 6), + &nexthop); + + /* Apply GETNEXT on not exact search */ + + if (!exact && (*objid_len >= v->namelen + 10)) + { + if (! in_addr_add((u_char *) &nexthop, 1)) + return; + } + + /* For exact: search matching entry in rib table. */ + + if (exact) + { + if (policy) /* Not supported (yet?) */ + return; + for (*np = route_top (table); *np; *np = route_next (*np)) + { + if (!in_addr_cmp(&(*np)->p.u.prefix, (u_char *)&dest)) + { + for (*rib = (*np)->info; *rib; *rib = (*rib)->next) + { + if (!in_addr_cmp((u_char *)&(*rib)->nexthop->gate.ipv4, + (u_char *)&nexthop)) + if (proto == proto_trans((*rib)->type)) + return; + } + } + } + return; + } + + /* Search next best entry */ + + for (np2 = route_top (table); np2; np2 = route_next (np2)) + { + + /* Check destination first */ + if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) > 0) + for (rib2 = np2->info; rib2; rib2 = rib2->next) + check_replace(np2, rib2, np, rib); + + if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) == 0) + { /* have to look at each rib individually */ + for (rib2 = np2->info; rib2; rib2 = rib2->next) + { + int proto2, policy2; + + proto2 = proto_trans(rib2->type); + policy2 = 0; + + if ((policy < policy2) + || ((policy == policy2) && (proto < proto2)) + || ((policy == policy2) && (proto == proto2) + && (in_addr_cmp((u_char *)&rib2->nexthop->gate.ipv4, + (u_char *) &nexthop) >= 0) + )) + check_replace(np2, rib2, np, rib); + } + } + } + + if (!*rib) + return; + + policy = 0; + proto = proto_trans((*rib)->type); + + *objid_len = v->namelen + 10; + pnt = (u_char *) &(*np)->p.u.prefix; + for (i = 0; i < 4; i++) + objid[v->namelen + i] = *pnt++; + + objid[v->namelen + 4] = proto; + objid[v->namelen + 5] = policy; + + { + struct nexthop *nexthop; + + nexthop = (*rib)->nexthop; + if (nexthop) + { + pnt = (u_char *) &nexthop->gate.ipv4; + for (i = 0; i < 4; i++) + objid[i + v->namelen + 6] = *pnt++; + } + } + + return; +} + +u_char * +ipFwTable (struct variable *v, oid objid[], size_t *objid_len, + int exact, size_t *val_len, WriteMethod **write_method) +{ + struct route_node *np; + struct rib *rib; + static int result; + static int resarr[2]; + static struct in_addr netmask; + struct nexthop *nexthop; + + get_fwtable_route_node(v, objid, objid_len, exact, &np, &rib); + if (!np) + return NULL; + + nexthop = rib->nexthop; + if (! nexthop) + return NULL; + + switch (v->magic) + { + case IPFORWARDDEST: + *val_len = 4; + return &np->p.u.prefix; + break; + case IPFORWARDMASK: + masklen2ip(np->p.prefixlen, &netmask); + *val_len = 4; + return (u_char *)&netmask; + break; + case IPFORWARDPOLICY: + result = 0; + *val_len = sizeof(int); + return (u_char *)&result; + break; + case IPFORWARDNEXTHOP: + *val_len = 4; + return (u_char *)&nexthop->gate.ipv4; + break; + case IPFORWARDIFINDEX: + *val_len = sizeof(int); + return (u_char *)&nexthop->ifindex; + break; + case IPFORWARDTYPE: + if (nexthop->type == NEXTHOP_TYPE_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IFNAME) + result = 3; + else + result = 4; + *val_len = sizeof(int); + return (u_char *)&result; + break; + case IPFORWARDPROTO: + result = proto_trans(rib->type); + *val_len = sizeof(int); + return (u_char *)&result; + break; + case IPFORWARDAGE: + result = 0; + *val_len = sizeof(int); + return (u_char *)&result; + break; + case IPFORWARDINFO: + resarr[0] = 0; + resarr[1] = 0; + *val_len = 2 * sizeof(int); + return (u_char *)resarr; + break; + case IPFORWARDNEXTHOPAS: + result = -1; + *val_len = sizeof(int); + return (u_char *)&result; + break; + case IPFORWARDMETRIC1: + result = 0; + *val_len = sizeof(int); + return (u_char *)&result; + break; + case IPFORWARDMETRIC2: + result = 0; + *val_len = sizeof(int); + return (u_char *)&result; + break; + case IPFORWARDMETRIC3: + result = 0; + *val_len = sizeof(int); + return (u_char *)&result; + break; + case IPFORWARDMETRIC4: + result = 0; + *val_len = sizeof(int); + return (u_char *)&result; + break; + case IPFORWARDMETRIC5: + result = 0; + *val_len = sizeof(int); + return (u_char *)&result; + break; + default: + return NULL; + break; + } + return NULL; +} + +u_char * +ipCidrTable (struct variable *v, oid objid[], size_t *objid_len, + int exact, size_t *val_len, WriteMethod **write_method) +{ + switch (v->magic) + { + case IPCIDRROUTEDEST: + break; + default: + return NULL; + break; + } + return NULL; +} + +void +zebra_snmp_init () +{ + smux_init (zebra_oid, sizeof (zebra_oid) / sizeof (oid)); + REGISTER_MIB("mibII/ipforward", zebra_variables, variable, ipfw_oid); + smux_start (); +} +#endif /* HAVE_SNMP */ diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c new file mode 100644 index 0000000..6bc509f --- /dev/null +++ b/zebra/zebra_vty.c @@ -0,0 +1,1573 @@ +/* Zebra VTY functions + * Copyright (C) 2002 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "prefix.h" +#include "command.h" +#include "table.h" +#include "rib.h" + +/* Return route type string for VTY output. */ +const char * +route_type_str (u_char type) +{ + switch (type) + { + case ZEBRA_ROUTE_SYSTEM: + return "system"; + case ZEBRA_ROUTE_KERNEL: + return "kernel"; + case ZEBRA_ROUTE_CONNECT: + return "connected"; + case ZEBRA_ROUTE_STATIC: + return "static"; + case ZEBRA_ROUTE_RIP: + return "rip"; + case ZEBRA_ROUTE_RIPNG: + return "rip"; + case ZEBRA_ROUTE_OSPF: + return "ospf"; + case ZEBRA_ROUTE_OSPF6: + return "ospf"; + case ZEBRA_ROUTE_BGP: + return "bgp"; + default: + return "unknown"; + } +}; + +/* Return route type string for VTY output. */ +const char +route_type_char (u_char type) +{ + switch (type) + { + case ZEBRA_ROUTE_SYSTEM: + return 'S'; + case ZEBRA_ROUTE_KERNEL: + return 'K'; + case ZEBRA_ROUTE_CONNECT: + return 'C'; + case ZEBRA_ROUTE_STATIC: + return 'S'; + case ZEBRA_ROUTE_RIP: + return 'R'; + case ZEBRA_ROUTE_RIPNG: + return 'R'; + case ZEBRA_ROUTE_OSPF: + return 'O'; + case ZEBRA_ROUTE_OSPF6: + return 'O'; + case ZEBRA_ROUTE_BGP: + return 'B'; + default: + return '?'; + } +}; + +/* General fucntion for static route. */ +int +zebra_static_ipv4 (struct vty *vty, int add_cmd, + char *dest_str, char *mask_str, char *gate_str, + char *distance_str) +{ + int ret; + u_char distance; + struct prefix p; + struct in_addr gate; + struct in_addr mask; + char *ifname; + + ret = str2prefix (dest_str, &p); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Cisco like mask notation. */ + if (mask_str) + { + ret = inet_aton (mask_str, &mask); + if (ret == 0) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + p.prefixlen = ip_masklen (mask); + } + + /* Apply mask for given prefix. */ + apply_mask (&p); + + /* Administrative distance. */ + if (distance_str) + distance = atoi (distance_str); + else + distance = ZEBRA_STATIC_DISTANCE_DEFAULT; + + /* Null0 static route. */ + if (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0) + { + if (add_cmd) + static_add_ipv4 (&p, NULL, NULL, distance, 0); + else + static_delete_ipv4 (&p, NULL, NULL, distance, 0); + return CMD_SUCCESS; + } + + /* When gateway is A.B.C.D format, gate is treated as nexthop + address other case gate is treated as interface name. */ + ret = inet_aton (gate_str, &gate); + if (ret) + ifname = NULL; + else + ifname = gate_str; + + if (add_cmd) + static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0); + else + static_delete_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0); + + return CMD_SUCCESS; +} + +/* Static route configuration. */ +DEFUN (ip_route, + ip_route_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n") +{ + return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL); +} + +/* Mask as A.B.C.D format. */ +DEFUN (ip_route_mask, + ip_route_mask_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n") +{ + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL); +} + +/* Distance option value. */ +DEFUN (ip_route_distance, + ip_route_distance_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2]); +} + +DEFUN (ip_route_mask_distance, + ip_route_mask_distance_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3]); +} + +DEFUN (no_ip_route, + no_ip_route_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL); +} + +DEFUN (no_ip_route_mask, + no_ip_route_mask_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (no_ip_route_distance, + no_ip_route_distance_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2]); +} + +DEFUN (no_ip_route_mask_distance, + no_ip_route_mask_distance_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Null interface\n" + "Distance value for this route\n") +{ + return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3]); +} + +/* New RIB. Detailed information for IPv4 route. */ +void +vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) +{ + struct rib *rib; + struct nexthop *nexthop; + + for (rib = rn->info; rib; rib = rib->next) + { + vty_out (vty, "Routing entry for %s/%d%s", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + VTY_NEWLINE); + vty_out (vty, " Known via \"%s\"", route_type_str (rib->type)); + vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric); + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + vty_out (vty, ", best"); + if (rib->refcnt) + vty_out (vty, ", refcnt %ld", rib->refcnt); + vty_out (vty, "%s", VTY_NEWLINE); + +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + if (rib->type == ZEBRA_ROUTE_RIP + || rib->type == ZEBRA_ROUTE_OSPF + || rib->type == ZEBRA_ROUTE_BGP) + { + time_t uptime; + struct tm *tm; + + uptime = time (NULL); + uptime -= rib->uptime; + tm = gmtime (&uptime); + + vty_out (vty, " Last update "); + + if (uptime < ONE_DAY_SECOND) + vty_out (vty, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (uptime < ONE_WEEK_SECOND) + vty_out (vty, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + vty_out (vty, "%02dw%dd%02dh", + tm->tm_yday/7, + tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + vty_out (vty, " ago%s", VTY_NEWLINE); + } + + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + vty_out (vty, " %c", + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' '); + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " %s", inet_ntoa (nexthop->gate.ipv4)); + if (nexthop->ifindex) + vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " directly connected, %s", + ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " directly connected, %s", nexthop->ifname); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out (vty, " directly connected, via Null0"); + break; + default: + break; + } + if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + vty_out (vty, " inactive"); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + vty_out (vty, " (recursive"); + + switch (nexthop->rtype) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4)); + break; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s)", + ifindex2ifname (nexthop->rifindex)); + break; + default: + break; + } + } + vty_out (vty, "%s", VTY_NEWLINE); + } + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +void +vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) +{ + struct nexthop *nexthop; + int len = 0; + char buf[BUFSIZ]; + + /* Nexthop information. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + if (nexthop == rib->nexthop) + { + /* Prefix information. */ + len = vty_out (vty, "%c%c%c %s/%d", + route_type_char (rib->type), + CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) + ? '>' : ' ', + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) + ? '*' : ' ', + inet_ntop (AF_INET, &rn->p.u.prefix, buf, BUFSIZ), + rn->p.prefixlen); + + /* Distance and metric display. */ + if (rib->type != ZEBRA_ROUTE_CONNECT + && rib->type != ZEBRA_ROUTE_KERNEL) + len += vty_out (vty, " [%d/%d]", rib->distance, + rib->metric); + } + else + vty_out (vty, " %c%*c", + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) + ? '*' : ' ', + len - 3, ' '); + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4)); + if (nexthop->ifindex) + vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " is directly connected, %s", + ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s", nexthop->ifname); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out (vty, " is directly connected, Null0"); + default: + break; + } + if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + vty_out (vty, " inactive"); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + vty_out (vty, " (recursive"); + + switch (nexthop->rtype) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4)); + break; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s)", + ifindex2ifname (nexthop->rifindex)); + break; + default: + break; + } + } + + if (rib->type == ZEBRA_ROUTE_RIP + || rib->type == ZEBRA_ROUTE_OSPF + || rib->type == ZEBRA_ROUTE_BGP) + { + time_t uptime; + struct tm *tm; + + uptime = time (NULL); + uptime -= rib->uptime; + tm = gmtime (&uptime); + +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + + if (uptime < ONE_DAY_SECOND) + vty_out (vty, ", %02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (uptime < ONE_WEEK_SECOND) + vty_out (vty, ", %dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + vty_out (vty, ", %02dw%dd%02dh", + tm->tm_yday/7, + tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + } + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +#define SHOW_ROUTE_V4_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,%s B - BGP, > - selected route, * - FIB route%s%s" + +DEFUN (show_ip_route, + show_ip_route_cmd, + "show ip route", + SHOW_STR + IP_STR + "IP routing table\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + int first = 1; + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + /* Show all IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE, + VTY_NEWLINE); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_prefix_longer, + show_ip_route_prefix_longer_cmd, + "show ip route A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + "IP routing table\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Show route matching the specified Network/Mask pair only\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct prefix p; + int ret; + int first = 1; + + ret = str2prefix (argv[0], &p); + if (! ret) + { + vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + /* Show matched type IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (prefix_match (&p, &rn->p)) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, + VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_supernets, + show_ip_route_supernets_cmd, + "show ip route supernets-only", + SHOW_STR + IP_STR + "IP routing table\n" + "Show supernet entries only\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + u_int32_t addr; + int first = 1; + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + /* Show matched type IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + { + addr = ntohl (rn->p.u.prefix4.s_addr); + + if ((IN_CLASSC (addr) && rn->p.prefixlen < 24) + || (IN_CLASSB (addr) && rn->p.prefixlen < 16) + || (IN_CLASSA (addr) && rn->p.prefixlen < 8)) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, + VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_protocol, + show_ip_route_protocol_cmd, + "show ip route (bgp|connected|kernel|ospf|rip|static)", + SHOW_STR + IP_STR + "IP routing table\n" + "Border Gateway Protocol (BGP)\n" + "Connected\n" + "Kernel\n" + "Open Shortest Path First (OSPF)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n") +{ + int type; + struct route_table *table; + struct route_node *rn; + struct rib *rib; + int first = 1; + + if (strncmp (argv[0], "b", 1) == 0) + type = ZEBRA_ROUTE_BGP; + else if (strncmp (argv[0], "c", 1) == 0) + type = ZEBRA_ROUTE_CONNECT; + else if (strncmp (argv[0], "k", 1) ==0) + type = ZEBRA_ROUTE_KERNEL; + else if (strncmp (argv[0], "o", 1) == 0) + type = ZEBRA_ROUTE_OSPF; + else if (strncmp (argv[0], "r", 1) == 0) + type = ZEBRA_ROUTE_RIP; + else if (strncmp (argv[0], "s", 1) == 0) + type = ZEBRA_ROUTE_STATIC; + else + { + vty_out (vty, "Unknown route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + /* Show matched type IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == type) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER, + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_addr, + show_ip_route_addr_cmd, + "show ip route A.B.C.D", + SHOW_STR + IP_STR + "IP routing table\n" + "Network in the IP routing table to display\n") +{ + int ret; + struct prefix_ipv4 p; + struct route_table *table; + struct route_node *rn; + + ret = str2prefix_ipv4 (argv[0], &p); + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + rn = route_node_match (table, (struct prefix *) &p); + if (! rn) + { + vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + return CMD_WARNING; + } + + vty_show_ip_route_detail (vty, rn); + + route_unlock_node (rn); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_prefix, + show_ip_route_prefix_cmd, + "show ip route A.B.C.D/M", + SHOW_STR + IP_STR + "IP routing table\n" + "IP prefix /, e.g., 35.0.0.0/8\n") +{ + int ret; + struct prefix_ipv4 p; + struct route_table *table; + struct route_node *rn; + + ret = str2prefix_ipv4 (argv[0], &p); + if (ret <= 0) + { + vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + rn = route_node_match (table, (struct prefix *) &p); + if (! rn || rn->p.prefixlen != p.prefixlen) + { + vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + return CMD_WARNING; + } + + vty_show_ip_route_detail (vty, rn); + + route_unlock_node (rn); + + return CMD_SUCCESS; +} + +void +zebra_show_ip_route (struct vty *vty, struct vrf *vrf) +{ + vty_out (vty, "IP routing table name is %s(%d)%s", + vrf->name ? vrf->name : "", vrf->id, VTY_NEWLINE); + + vty_out (vty, "Route Source Networks%s", VTY_NEWLINE); + vty_out (vty, "connected %d%s", 0, VTY_NEWLINE); + vty_out (vty, "static %d%s", 0, VTY_NEWLINE); + vty_out (vty, "rip %d%s", 0, VTY_NEWLINE); + + vty_out (vty, "bgp %d%s", 0, VTY_NEWLINE); + vty_out (vty, " External: %d Internal: %d Local: %d%s", + 0, 0, 0, VTY_NEWLINE); + + vty_out (vty, "ospf %d%s", 0, VTY_NEWLINE); + vty_out (vty, + " Intra-area: %d Inter-area: %d External-1: %d External-2: %d%s", + 0, 0, 0, 0, VTY_NEWLINE); + vty_out (vty, " NSSA External-1: %d NSSA External-2: %d%s", + 0, 0, VTY_NEWLINE); + + vty_out (vty, "internal %d%s", 0, VTY_NEWLINE); + vty_out (vty, "Total %d%s", 0, VTY_NEWLINE); +} + +/* Show route summary. */ +DEFUN (show_ip_route_summary, + show_ip_route_summary_cmd, + "show ip route summary", + SHOW_STR + IP_STR + "IP routing table\n" + "Summary of all routes\n") +{ + struct vrf *vrf; + + /* Default table id is zero. */ + vrf = vrf_lookup (0); + if (! vrf) + { + vty_out (vty, "%% No Default-IP-Routing-Table%s", VTY_NEWLINE); + return CMD_WARNING; + } + + zebra_show_ip_route (vty, vrf); + + return CMD_SUCCESS; +} + +/* Write IPv4 static route configuration. */ +int +static_config_ipv4 (struct vty *vty) +{ + struct route_node *rn; + struct static_ipv4 *si; + struct route_table *stable; + int write; + + write = 0; + + /* Lookup table. */ + stable = vrf_static_table (AFI_IP, SAFI_UNICAST, 0); + if (! stable) + return -1; + + for (rn = route_top (stable); rn; rn = route_next (rn)) + for (si = rn->info; si; si = si->next) + { + vty_out (vty, "ip route %s/%d", inet_ntoa (rn->p.u.prefix4), + rn->p.prefixlen); + + switch (si->type) + { + case STATIC_IPV4_GATEWAY: + vty_out (vty, " %s", inet_ntoa (si->gate.ipv4)); + break; + case STATIC_IPV4_IFNAME: + vty_out (vty, " %s", si->gate.ifname); + break; + case STATIC_IPV4_BLACKHOLE: + vty_out (vty, " Null0"); + break; + } + + if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) + vty_out (vty, " %d", si->distance); + vty_out (vty, "%s", VTY_NEWLINE); + + write = 1; + } + return write; +} + +#ifdef HAVE_IPV6 +/* General fucntion for IPv6 static route. */ +int +static_ipv6_func (struct vty *vty, int add_cmd, char *dest_str, + char *gate_str, char *ifname, char *distance_str) +{ + int ret; + u_char distance; + struct prefix p; + struct in6_addr *gate = NULL; + struct in6_addr gate_addr; + u_char type = 0; + int table = 0; + + ret = str2prefix (dest_str, &p); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Apply mask for given prefix. */ + apply_mask (&p); + + /* Administrative distance. */ + if (distance_str) + distance = atoi (distance_str); + else + distance = ZEBRA_STATIC_DISTANCE_DEFAULT; + + /* Null0 static route. */ + if (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0) + { + type = STATIC_IPV6_BLACKHOLE; + if (add_cmd) + static_add_ipv6 (&p, type, NULL, NULL, distance, 0); + else + static_delete_ipv6 (&p, type, NULL, NULL, distance, 0); + return CMD_SUCCESS; + } + + /* When gateway is valid IPv6 addrees, then gate is treated as + nexthop address other case gate is treated as interface name. */ + ret = inet_pton (AF_INET6, gate_str, &gate_addr); + + if (ifname) + { + /* When ifname is specified. It must be come with gateway + address. */ + if (ret != 1) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + type = STATIC_IPV6_GATEWAY_IFNAME; + gate = &gate_addr; + } + else + { + if (ret == 1) + { + type = STATIC_IPV6_GATEWAY; + gate = &gate_addr; + } + else + { + type = STATIC_IPV6_IFNAME; + ifname = gate_str; + } + } + + if (add_cmd) + static_add_ipv6 (&p, type, gate, ifname, distance, table); + else + static_delete_ipv6 (&p, type, gate, ifname, distance, table); + + return CMD_SUCCESS; +} + +DEFUN (ipv6_route, + ipv6_route_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE|null0)", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL); +} + +DEFUN (ipv6_route_ifname, + ipv6_route_ifname_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (ipv6_route_pref, + ipv6_route_pref_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE|null0) <1-255>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2]); +} + +DEFUN (ipv6_route_ifname_pref, + ipv6_route_ifname_pref_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3]); +} + +DEFUN (no_ipv6_route, + no_ipv6_route_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE|null0)", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL); +} + +DEFUN (no_ipv6_route_ifname, + no_ipv6_route_ifname_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (no_ipv6_route_pref, + no_ipv6_route_pref_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE|null0) <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2]); +} + +DEFUN (no_ipv6_route_ifname_pref, + no_ipv6_route_ifname_pref_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3]); +} + +/* New RIB. Detailed information for IPv6 route. */ +void +vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn) +{ + struct rib *rib; + struct nexthop *nexthop; + char buf[BUFSIZ]; + + for (rib = rn->info; rib; rib = rib->next) + { + vty_out (vty, "Routing entry for %s/%d%s", + inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), + rn->p.prefixlen, + VTY_NEWLINE); + vty_out (vty, " Known via \"%s\"", route_type_str (rib->type)); + vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric); + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + vty_out (vty, ", best"); + if (rib->refcnt) + vty_out (vty, ", refcnt %ld", rib->refcnt); + vty_out (vty, "%s", VTY_NEWLINE); + +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + if (rib->type == ZEBRA_ROUTE_RIPNG + || rib->type == ZEBRA_ROUTE_OSPF6 + || rib->type == ZEBRA_ROUTE_BGP) + { + time_t uptime; + struct tm *tm; + + uptime = time (NULL); + uptime -= rib->uptime; + tm = gmtime (&uptime); + + vty_out (vty, " Last update "); + + if (uptime < ONE_DAY_SECOND) + vty_out (vty, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (uptime < ONE_WEEK_SECOND) + vty_out (vty, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + vty_out (vty, "%02dw%dd%02dh", + tm->tm_yday/7, + tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + vty_out (vty, " ago%s", VTY_NEWLINE); + } + + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + vty_out (vty, " %c", + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' '); + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFNAME: + vty_out (vty, " %s", + inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); + if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) + vty_out (vty, ", %s", nexthop->ifname); + else if (nexthop->ifindex) + vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " directly connected, %s", + ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " directly connected, %s", + nexthop->ifname); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out (vty, " directly connected, via Null0"); + break; + default: + break; + } + if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + vty_out (vty, " inactive"); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + vty_out (vty, " (recursive"); + + switch (nexthop->rtype) + { + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFNAME: + vty_out (vty, " via %s)", + inet_ntop (AF_INET6, &nexthop->rgate.ipv6, + buf, BUFSIZ)); + if (nexthop->rifindex) + vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex)); + break; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s)", + ifindex2ifname (nexthop->rifindex)); + break; + default: + break; + } + } + vty_out (vty, "%s", VTY_NEWLINE); + } + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +void +vty_show_ipv6_route (struct vty *vty, struct route_node *rn, + struct rib *rib) +{ + struct nexthop *nexthop; + int len = 0; + char buf[BUFSIZ]; + + /* Nexthop information. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + if (nexthop == rib->nexthop) + { + /* Prefix information. */ + len = vty_out (vty, "%c%c%c %s/%d", + route_type_char (rib->type), + CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) + ? '>' : ' ', + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) + ? '*' : ' ', + inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), + rn->p.prefixlen); + + /* Distance and metric display. */ + if (rib->type != ZEBRA_ROUTE_CONNECT + && rib->type != ZEBRA_ROUTE_KERNEL) + len += vty_out (vty, " [%d/%d]", rib->distance, + rib->metric); + } + else + vty_out (vty, " %c%*c", + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) + ? '*' : ' ', + len - 3, ' '); + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFNAME: + vty_out (vty, " via %s", + inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); + if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) + vty_out (vty, ", %s", nexthop->ifname); + else if (nexthop->ifindex) + vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " is directly connected, %s", + ifindex2ifname (nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s", + nexthop->ifname); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out (vty, " is directly connected, Null0"); + default: + break; + } + if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + vty_out (vty, " inactive"); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + vty_out (vty, " (recursive"); + + switch (nexthop->rtype) + { + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFNAME: + vty_out (vty, " via %s)", + inet_ntop (AF_INET6, &nexthop->rgate.ipv6, + buf, BUFSIZ)); + if (nexthop->rifindex) + vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex)); + break; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s)", + ifindex2ifname (nexthop->rifindex)); + break; + default: + break; + } + } + + if (rib->type == ZEBRA_ROUTE_RIPNG + || rib->type == ZEBRA_ROUTE_OSPF6 + || rib->type == ZEBRA_ROUTE_BGP) + { + time_t uptime; + struct tm *tm; + + uptime = time (NULL); + uptime -= rib->uptime; + tm = gmtime (&uptime); + +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + + if (uptime < ONE_DAY_SECOND) + vty_out (vty, ", %02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (uptime < ONE_WEEK_SECOND) + vty_out (vty, ", %dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, tm->tm_min); + else + vty_out (vty, ", %02dw%dd%02dh", + tm->tm_yday/7, + tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + } + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +#define SHOW_ROUTE_V6_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIPng, O - OSPFv3,%s B - BGP, * - FIB route.%s%s" + +DEFUN (show_ipv6_route, + show_ipv6_route_cmd, + "show ipv6 route", + SHOW_STR + IP_STR + "IPv6 routing table\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + int first = 1; + + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + /* Show all IPv6 route. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ipv6_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_route_prefix_longer, + show_ipv6_route_prefix_longer_cmd, + "show ipv6 route X:X::X:X/M longer-prefixes", + SHOW_STR + IP_STR + "IPv6 routing table\n" + "IPv6 prefix\n" + "Show route matching the specified Network/Mask pair only\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + struct prefix p; + int ret; + int first = 1; + + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + ret = str2prefix (argv[0], &p); + if (! ret) + { + vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Show matched type IPv6 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (prefix_match (&p, &rn->p)) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ipv6_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_route_protocol, + show_ipv6_route_protocol_cmd, + "show ipv6 route (bgp|connected|kernel|ospf6|ripng|static)", + SHOW_STR + IP_STR + "IP routing table\n" + "Border Gateway Protocol (BGP)\n" + "Connected\n" + "Kernel\n" + "Open Shortest Path First (OSPFv3)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n") +{ + int type; + struct route_table *table; + struct route_node *rn; + struct rib *rib; + int first = 1; + + if (strncmp (argv[0], "b", 1) == 0) + type = ZEBRA_ROUTE_BGP; + else if (strncmp (argv[0], "c", 1) == 0) + type = ZEBRA_ROUTE_CONNECT; + else if (strncmp (argv[0], "k", 1) ==0) + type = ZEBRA_ROUTE_KERNEL; + else if (strncmp (argv[0], "o", 1) == 0) + type = ZEBRA_ROUTE_OSPF6; + else if (strncmp (argv[0], "r", 1) == 0) + type = ZEBRA_ROUTE_RIPNG; + else if (strncmp (argv[0], "s", 1) == 0) + type = ZEBRA_ROUTE_STATIC; + else + { + vty_out (vty, "Unknown route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + /* Show matched type IPv6 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == type) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ipv6_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_route_addr, + show_ipv6_route_addr_cmd, + "show ipv6 route X:X::X:X", + SHOW_STR + IP_STR + "IPv6 routing table\n" + "IPv6 Address\n") +{ + int ret; + struct prefix_ipv6 p; + struct route_table *table; + struct route_node *rn; + + ret = str2prefix_ipv6 (argv[0], &p); + if (ret <= 0) + { + vty_out (vty, "Malformed IPv6 address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + rn = route_node_match (table, (struct prefix *) &p); + if (! rn) + { + vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + return CMD_WARNING; + } + + vty_show_ipv6_route_detail (vty, rn); + + route_unlock_node (rn); + + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_route_prefix, + show_ipv6_route_prefix_cmd, + "show ipv6 route X:X::X:X/M", + SHOW_STR + IP_STR + "IPv6 routing table\n" + "IPv6 prefix\n") +{ + int ret; + struct prefix_ipv6 p; + struct route_table *table; + struct route_node *rn; + + ret = str2prefix_ipv6 (argv[0], &p); + if (ret <= 0) + { + vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + rn = route_node_match (table, (struct prefix *) &p); + if (! rn || rn->p.prefixlen != p.prefixlen) + { + vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); + return CMD_WARNING; + } + + vty_show_ipv6_route_detail (vty, rn); + + route_unlock_node (rn); + + return CMD_SUCCESS; +} + + +/* Write IPv6 static route configuration. */ +int +static_config_ipv6 (struct vty *vty) +{ + struct route_node *rn; + struct static_ipv6 *si; + int write; + char buf[BUFSIZ]; + struct route_table *stable; + + write = 0; + + /* Lookup table. */ + stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, 0); + if (! stable) + return -1; + + for (rn = route_top (stable); rn; rn = route_next (rn)) + for (si = rn->info; si; si = si->next) + { + vty_out (vty, "ipv6 route %s/%d", + inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), + rn->p.prefixlen); + + switch (si->type) + { + case STATIC_IPV6_GATEWAY: + vty_out (vty, " %s", inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ)); + break; + case STATIC_IPV6_IFNAME: + vty_out (vty, " %s", si->ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + vty_out (vty, " %s %s", + inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ), si->ifname); + break; + case STATIC_IPV6_BLACKHOLE: + vty_out (vty, " Null0"); + break; + } + + if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) + vty_out (vty, " %d", si->distance); + vty_out (vty, "%s", VTY_NEWLINE); + + write = 1; + } + return write; +} +#endif /* HAVE_IPV6 */ + +/* Static ip route configuration write function. */ +int +zebra_ip_config (struct vty *vty) +{ + int write = 0; + + write += static_config_ipv4 (vty); +#ifdef HAVE_IPV6 + write += static_config_ipv6 (vty); +#endif /* HAVE_IPV6 */ + + return write; +} + +/* IP node for static routes. */ +struct cmd_node ip_node = { IP_NODE, "", 1 }; + +/* Route VTY. */ +void +zebra_vty_route_init () +{ + install_node (&ip_node, zebra_ip_config); + + install_element (CONFIG_NODE, &ip_route_cmd); + install_element (CONFIG_NODE, &ip_route_mask_cmd); + install_element (CONFIG_NODE, &no_ip_route_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_cmd); + install_element (CONFIG_NODE, &ip_route_distance_cmd); + install_element (CONFIG_NODE, &ip_route_mask_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_distance_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_distance_cmd); + + install_element (VIEW_NODE, &show_ip_route_cmd); + install_element (VIEW_NODE, &show_ip_route_addr_cmd); + install_element (VIEW_NODE, &show_ip_route_prefix_cmd); + install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_route_protocol_cmd); + install_element (VIEW_NODE, &show_ip_route_supernets_cmd); + install_element (ENABLE_NODE, &show_ip_route_cmd); + install_element (ENABLE_NODE, &show_ip_route_addr_cmd); + install_element (ENABLE_NODE, &show_ip_route_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_route_protocol_cmd); + install_element (ENABLE_NODE, &show_ip_route_supernets_cmd); + +#if 0 + install_element (VIEW_NODE, &show_ip_route_summary_cmd); + install_element (ENABLE_NODE, &show_ip_route_summary_cmd); +#endif /* 0 */ + +#ifdef HAVE_IPV6 + install_element (CONFIG_NODE, &ipv6_route_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_cmd); + install_element (CONFIG_NODE, &ipv6_route_pref_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_pref_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_pref_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd); + install_element (VIEW_NODE, &show_ipv6_route_cmd); + install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd); + install_element (VIEW_NODE, &show_ipv6_route_addr_cmd); + install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd); + install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_protocol_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd); +#endif /* HAVE_IPV6 */ +} + +void +zebra_vty_init () +{ + zebra_vty_route_init (); +} diff --git a/zebra/zserv.c b/zebra/zserv.c new file mode 100644 index 0000000..aa1c834 --- /dev/null +++ b/zebra/zserv.c @@ -0,0 +1,1948 @@ +/* Zebra daemon server routine. + * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "prefix.h" +#include "command.h" +#include "if.h" +#include "thread.h" +#include "stream.h" +#include "memory.h" +#include "table.h" +#include "rib.h" +#include "network.h" +#include "sockunion.h" +#include "log.h" +#include "zclient.h" + +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/debug.h" +#include "zebra/ipforward.h" + +/* Event list of zebra. */ +enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; + +/* Zebra client list. */ +list client_list; + +/* Default rtm_table for all clients */ +int rtm_table_default = 0; + +void zebra_event (enum event event, int sock, struct zserv *client); + +extern struct thread_master *master; + +/* For logging of zebra meesages. */ +char *zebra_command_str [] = +{ + "NULL", + "ZEBRA_INTERFACE_ADD", + "ZEBRA_INTERFACE_DELETE", + "ZEBRA_INTERFACE_ADDRESS_ADD", + "ZEBRA_INTERFACE_ADDRESS_DELETE", + "ZEBRA_INTERFACE_UP", + "ZEBRA_INTERFACE_DOWN", + "ZEBRA_IPV4_ROUTE_ADD", + "ZEBRA_IPV4_ROUTE_DELETE", + "ZEBRA_IPV6_ROUTE_ADD", + "ZEBRA_IPV6_ROUTE_DELETE", + "ZEBRA_REDISTRIBUTE_ADD", + "ZEBRA_REDISTRIBUTE_DELETE", + "ZEBRA_REDISTRIBUTE_DEFAULT_ADD", + "ZEBRA_REDISTRIBUTE_DEFAULT_DELETE", + "ZEBRA_IPV4_NEXTHOP_LOOKUP", + "ZEBRA_IPV6_NEXTHOP_LOOKUP", + "ZEBRA_IPV4_IMPORT_LOOKUP", + "ZEBRA_IPV6_IMPORT_LOOKUP" +}; + +struct zebra_message_queue +{ + struct nsm_message_queue *next; + struct nsm_message_queue *prev; + + u_char *buf; + u_int16_t length; + u_int16_t written; +}; + +struct thread *t_write; +struct fifo message_queue; + +int +zebra_server_dequeue (struct thread *t) +{ + int sock; + int nbytes; + struct zebra_message_queue *queue; + + sock = THREAD_FD (t); + t_write = NULL; + + queue = (struct zebra_message_queue *) FIFO_HEAD (&message_queue); + if (queue) + { + nbytes = write (sock, queue->buf + queue->written, + queue->length - queue->written); + + if (nbytes <= 0) + { + if (errno != EAGAIN) + return -1; + } + else if (nbytes != (queue->length - queue->written)) + { + queue->written += nbytes; + } + else + { + FIFO_DEL (queue); + XFREE (MTYPE_TMP, queue->buf); + XFREE (MTYPE_TMP, queue); + } + } + + if (FIFO_TOP (&message_queue)) + THREAD_WRITE_ON (master, t_write, zebra_server_dequeue, NULL, sock); + + return 0; +} + +/* Enqueu message. */ +void +zebra_server_enqueue (int sock, u_char *buf, unsigned long length, + unsigned long written) +{ + struct zebra_message_queue *queue; + + queue = XCALLOC (MTYPE_TMP, sizeof (struct zebra_message_queue)); + queue->buf = XMALLOC (MTYPE_TMP, length); + memcpy (queue->buf, buf, length); + queue->length = length; + queue->written = written; + + FIFO_ADD (&message_queue, queue); + + THREAD_WRITE_ON (master, t_write, zebra_server_dequeue, NULL, sock); +} + +int +zebra_server_send_message (int sock, u_char *buf, unsigned long length) +{ + int nbytes; + + if (FIFO_TOP (&message_queue)) + { + zebra_server_enqueue (sock, buf, length, 0); + return 0; + } + + /* Send message. */ + nbytes = write (sock, buf, length); + + if (nbytes <= 0) + { + if (errno == EAGAIN) + zebra_server_enqueue (sock, buf, length, 0); + else + return -1; + } + else if (nbytes != length) + zebra_server_enqueue (sock, buf, length, nbytes); + + return 0; +} + +/* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */ +int +zsend_interface_add (struct zserv *client, struct interface *ifp) +{ + struct stream *s; + + /* Check this client need interface information. */ + if (! client->ifinfo) + return -1; + + s = client->obuf; + stream_reset (s); + + /* Place holder for size. */ + stream_putw (s, 0); + + /* Message type. */ + stream_putc (s, ZEBRA_INTERFACE_ADD); + + /* Interface information. */ + stream_put (s, ifp->name, INTERFACE_NAMSIZ); + stream_putl (s, ifp->ifindex); + stream_putl (s, ifp->flags); + stream_putl (s, ifp->metric); + stream_putl (s, ifp->mtu); + stream_putl (s, ifp->bandwidth); +#ifdef HAVE_SOCKADDR_DL + stream_put (s, &ifp->sdl, sizeof (ifp->sdl)); +#else + stream_putl (s, ifp->hw_addr_len); + if (ifp->hw_addr_len) + stream_put (s, ifp->hw_addr, ifp->hw_addr_len); +#endif /* HAVE_SOCKADDR_DL */ + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +/* Interface deletion from zebra daemon. */ +int +zsend_interface_delete (struct zserv *client, struct interface *ifp) +{ + struct stream *s; + + /* Check this client need interface information. */ + if (! client->ifinfo) + return -1; + + s = client->obuf; + stream_reset (s); + + /* Packet length placeholder. */ + stream_putw (s, 0); + + /* Interface information. */ + stream_putc (s, ZEBRA_INTERFACE_DELETE); + stream_put (s, ifp->name, INTERFACE_NAMSIZ); + stream_putl (s, ifp->ifindex); + stream_putl (s, ifp->flags); + stream_putl (s, ifp->metric); + stream_putl (s, ifp->mtu); + stream_putl (s, ifp->bandwidth); + + /* Write packet length. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +/* Interface address is added. Send ZEBRA_INTERFACE_ADDRESS_ADD to the + client. */ +int +zsend_interface_address_add (struct zserv *client, struct interface *ifp, + struct connected *ifc) +{ + int blen; + struct stream *s; + struct prefix *p; + + /* Check this client need interface information. */ + if (! client->ifinfo) + return -1; + + s = client->obuf; + stream_reset (s); + + /* Place holder for size. */ + stream_putw (s, 0); + + stream_putc (s, ZEBRA_INTERFACE_ADDRESS_ADD); + stream_putl (s, ifp->ifindex); + + /* Interface address flag. */ + stream_putc (s, ifc->flags); + + /* Prefix information. */ + p = ifc->address; + stream_putc (s, p->family); + blen = prefix_blen (p); + stream_put (s, &p->u.prefix, blen); + stream_putc (s, p->prefixlen); + + /* Destination. */ + p = ifc->destination; + if (p) + stream_put (s, &p->u.prefix, blen); + else + stream_put (s, NULL, blen); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +/* Interface address is deleted. Send ZEBRA_INTERFACE_ADDRESS_DELETE + to the client. */ +int +zsend_interface_address_delete (struct zserv *client, struct interface *ifp, + struct connected *ifc) +{ + int blen; + struct stream *s; + struct prefix *p; + + /* Check this client need interface information. */ + if (! client->ifinfo) + return -1; + + s = client->obuf; + stream_reset (s); + + /* Place holder for size. */ + stream_putw (s, 0); + + stream_putc (s, ZEBRA_INTERFACE_ADDRESS_DELETE); + stream_putl (s, ifp->ifindex); + + /* Interface address flag. */ + stream_putc (s, ifc->flags); + + /* Prefix information. */ + p = ifc->address; + stream_putc (s, p->family); + blen = prefix_blen (p); + stream_put (s, &p->u.prefix, blen); + + p = ifc->destination; + if (p) + stream_put (s, &p->u.prefix, blen); + else + stream_put (s, NULL, blen); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +int +zsend_interface_up (struct zserv *client, struct interface *ifp) +{ + struct stream *s; + + /* Check this client need interface information. */ + if (! client->ifinfo) + return -1; + + s = client->obuf; + stream_reset (s); + + /* Place holder for size. */ + stream_putw (s, 0); + + /* Zebra command. */ + stream_putc (s, ZEBRA_INTERFACE_UP); + + /* Interface information. */ + stream_put (s, ifp->name, INTERFACE_NAMSIZ); + stream_putl (s, ifp->ifindex); + stream_putl (s, ifp->flags); + stream_putl (s, ifp->metric); + stream_putl (s, ifp->mtu); + stream_putl (s, ifp->bandwidth); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +int +zsend_interface_down (struct zserv *client, struct interface *ifp) +{ + struct stream *s; + + /* Check this client need interface information. */ + if (! client->ifinfo) + return -1; + + s = client->obuf; + stream_reset (s); + + /* Place holder for size. */ + stream_putw (s, 0); + + /* Zebra command. */ + stream_putc (s, ZEBRA_INTERFACE_DOWN); + + /* Interface information. */ + stream_put (s, ifp->name, INTERFACE_NAMSIZ); + stream_putl (s, ifp->ifindex); + stream_putl (s, ifp->flags); + stream_putl (s, ifp->metric); + stream_putl (s, ifp->mtu); + stream_putl (s, ifp->bandwidth); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +int +zsend_ipv4_add_multipath (struct zserv *client, struct prefix *p, + struct rib *rib) +{ + int psize; + struct stream *s; + struct nexthop *nexthop; + struct in_addr empty; + + empty.s_addr = 0; + s = client->obuf; + stream_reset (s); + + /* Place holder for size. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV4_ROUTE_ADD); + stream_putc (s, rib->type); + stream_putc (s, rib->flags); + stream_putc (s, ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_IFINDEX | ZAPI_MESSAGE_METRIC); + + /* Prefix. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->u.prefix, psize); + + /* Nexthop */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + stream_putc (s, 1); + + if (nexthop->type == NEXTHOP_TYPE_IPV4 + || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + stream_put_in_addr (s, &nexthop->gate.ipv4); + else + stream_put_in_addr (s, &empty); + + /* Interface index. */ + stream_putc (s, 1); + stream_putl (s, nexthop->ifindex); + + break; + } + } + + /* Metric */ + stream_putl (s, rib->metric); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +int +zsend_ipv4_delete_multipath (struct zserv *client, struct prefix *p, + struct rib *rib) +{ + int psize; + struct stream *s; + struct nexthop *nexthop; + struct in_addr empty; + + empty.s_addr = 0; + + s = client->obuf; + stream_reset (s); + + /* Place holder for size. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV4_ROUTE_DELETE); + stream_putc (s, rib->type); + stream_putc (s, rib->flags); + stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX); + + /* Prefix. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->u.prefix, psize); + + /* Nexthop */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + stream_putc (s, 1); + + if (nexthop->type == NEXTHOP_TYPE_IPV4) + stream_put_in_addr (s, &nexthop->gate.ipv4); + else + stream_put_in_addr (s, &empty); + + /* Interface index. */ + stream_putc (s, 1); + stream_putl (s, nexthop->ifindex); + + break; + } + } + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +int +zsend_ipv4_add (struct zserv *client, int type, int flags, + struct prefix_ipv4 *p, struct in_addr *nexthop, + unsigned int ifindex) +{ + int psize; + struct stream *s; + + s = client->obuf; + stream_reset (s); + + /* Place holder for size. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV4_ROUTE_ADD); + stream_putc (s, type); + stream_putc (s, flags); + stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX); + + /* Prefix. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop */ + stream_putc (s, 1); + stream_put_in_addr (s, nexthop); + + /* Interface index. */ + stream_putc (s, 1); + stream_putl (s, ifindex); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +int +zsend_ipv4_delete (struct zserv *client, int type, int flags, + struct prefix_ipv4 *p, struct in_addr *nexthop, + unsigned int ifindex) +{ + int psize; + struct stream *s; + + s = client->obuf; + stream_reset (s); + + /* Place holder for size. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV4_ROUTE_DELETE); + stream_putc (s, type); + stream_putc (s, flags); + stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX); + + /* Prefix. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop */ + stream_putc (s, 1); + stream_put_in_addr (s, nexthop); + + /* Interface index. */ + stream_putc (s, 1); + stream_putl (s, ifindex); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +#ifdef HAVE_IPV6 +int +zsend_ipv6_add (struct zserv *client, int type, int flags, + struct prefix_ipv6 *p, struct in6_addr *nexthop, + unsigned int ifindex) +{ + int psize; + struct stream *s; + + s = client->obuf; + stream_reset (s); + + /* Place holder for size. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV6_ROUTE_ADD); + stream_putc (s, type); + stream_putc (s, flags); + stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX); + + /* Prefix. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop */ + stream_putc (s, 1); + stream_write (s, (u_char *)nexthop, 16); + + /* Interface index. */ + stream_putc (s, 1); + stream_putl (s, ifindex); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +int +zsend_ipv6_add_multipath (struct zserv *client, struct prefix *p, + struct rib *rib) +{ + int psize; + struct stream *s; + struct nexthop *nexthop; + struct in6_addr empty; + + memset (&empty, 0, sizeof (struct in6_addr)); + s = client->obuf; + stream_reset (s); + + /* Place holder for size. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV6_ROUTE_ADD); + stream_putc (s, rib->type); + stream_putc (s, rib->flags); + stream_putc (s, ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_IFINDEX | ZAPI_MESSAGE_METRIC); + + /* Prefix. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *) &p->u.prefix, psize); + + /* Nexthop */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + stream_putc (s, 1); + + if (nexthop->type == NEXTHOP_TYPE_IPV6) + stream_write (s, (u_char *) &nexthop->gate.ipv6, 16); + else + stream_write (s, (u_char *) &empty, 16); + + /* Interface index. */ + stream_putc (s, 1); + stream_putl (s, nexthop->ifindex); + + break; + } + } + + /* Metric */ + stream_putl (s, rib->metric); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +int +zsend_ipv6_delete (struct zserv *client, int type, int flags, + struct prefix_ipv6 *p, struct in6_addr *nexthop, + unsigned int ifindex) +{ + int psize; + struct stream *s; + + s = client->obuf; + stream_reset (s); + + /* Place holder for size. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV6_ROUTE_DELETE); + stream_putc (s, type); + stream_putc (s, flags); + stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX); + + /* Prefix. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->prefix, psize); + + /* Nexthop */ + stream_putc (s, 1); + stream_write (s, (u_char *)nexthop, 16); + + /* Interface index. */ + stream_putc (s, 1); + stream_putl (s, ifindex); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +int +zsend_ipv6_delete_multipath (struct zserv *client, struct prefix *p, + struct rib *rib) +{ + int psize; + struct stream *s; + struct nexthop *nexthop; + struct in6_addr empty; + + memset (&empty, 0, sizeof (struct in6_addr)); + s = client->obuf; + stream_reset (s); + + /* Place holder for size. */ + stream_putw (s, 0); + + /* Put command, type and nexthop. */ + stream_putc (s, ZEBRA_IPV6_ROUTE_DELETE); + stream_putc (s, rib->type); + stream_putc (s, rib->flags); + stream_putc (s, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX); + + /* Prefix. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *)&p->u.prefix, psize); + + /* Nexthop */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + stream_putc (s, 1); + + if (nexthop->type == NEXTHOP_TYPE_IPV6) + stream_write (s, (u_char *) &nexthop->gate.ipv6, 16); + else + stream_write (s, (u_char *) &empty, 16); + + /* Interface index. */ + stream_putc (s, 1); + stream_putl (s, nexthop->ifindex); + + break; + } + } + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +int +zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr) +{ + struct stream *s; + struct rib *rib; + unsigned long nump; + u_char num; + struct nexthop *nexthop; + + /* Lookup nexthop. */ + rib = rib_match_ipv6 (addr); + + /* Get output stream. */ + s = client->obuf; + stream_reset (s); + + /* Fill in result. */ + stream_putw (s, 0); + stream_putc (s, ZEBRA_IPV6_NEXTHOP_LOOKUP); + stream_put (s, &addr, 16); + + if (rib) + { + stream_putl (s, rib->metric); + num = 0; + nump = s->putp; + stream_putc (s, 0); + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + stream_putc (s, nexthop->type); + switch (nexthop->type) + { + case ZEBRA_NEXTHOP_IPV6: + stream_put (s, &nexthop->gate.ipv6, 16); + break; + case ZEBRA_NEXTHOP_IPV6_IFINDEX: + case ZEBRA_NEXTHOP_IPV6_IFNAME: + stream_put (s, &nexthop->gate.ipv6, 16); + stream_putl (s, nexthop->ifindex); + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + stream_putl (s, nexthop->ifindex); + break; + } + num++; + } + stream_putc_at (s, nump, num); + } + else + { + stream_putl (s, 0); + stream_putc (s, 0); + } + + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} +#endif /* HAVE_IPV6 */ + +int +zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) +{ + struct stream *s; + struct rib *rib; + unsigned long nump; + u_char num; + struct nexthop *nexthop; + + /* Lookup nexthop. */ + rib = rib_match_ipv4 (addr); + + /* Get output stream. */ + s = client->obuf; + stream_reset (s); + + /* Fill in result. */ + stream_putw (s, 0); + stream_putc (s, ZEBRA_IPV4_NEXTHOP_LOOKUP); + stream_put_in_addr (s, &addr); + + if (rib) + { + stream_putl (s, rib->metric); + num = 0; + nump = s->putp; + stream_putc (s, 0); + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + stream_putc (s, nexthop->type); + switch (nexthop->type) + { + case ZEBRA_NEXTHOP_IPV4: + stream_put_in_addr (s, &nexthop->gate.ipv4); + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + stream_putl (s, nexthop->ifindex); + break; + } + num++; + } + stream_putc_at (s, nump, num); + } + else + { + stream_putl (s, 0); + stream_putc (s, 0); + } + + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +int +zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p) +{ + struct stream *s; + struct rib *rib; + unsigned long nump; + u_char num; + struct nexthop *nexthop; + + /* Lookup nexthop. */ + rib = rib_lookup_ipv4 (p); + + /* Get output stream. */ + s = client->obuf; + stream_reset (s); + + /* Fill in result. */ + stream_putw (s, 0); + stream_putc (s, ZEBRA_IPV4_IMPORT_LOOKUP); + stream_put_in_addr (s, &p->prefix); + + if (rib) + { + stream_putl (s, rib->metric); + num = 0; + nump = s->putp; + stream_putc (s, 0); + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + stream_putc (s, nexthop->type); + switch (nexthop->type) + { + case ZEBRA_NEXTHOP_IPV4: + stream_put_in_addr (s, &nexthop->gate.ipv4); + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + stream_putl (s, nexthop->ifindex); + break; + } + num++; + } + stream_putc_at (s, nump, num); + } + else + { + stream_putl (s, 0); + stream_putc (s, 0); + } + + stream_putw_at (s, 0, stream_get_endp (s)); + + zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); + + return 0; +} + +/* Register zebra server interface information. Send current all + interface and address information. */ +void +zread_interface_add (struct zserv *client, u_short length) +{ + listnode ifnode; + listnode cnode; + struct interface *ifp; + struct connected *c; + + /* Interface information is needed. */ + client->ifinfo = 1; + + for (ifnode = listhead (iflist); ifnode; ifnode = nextnode (ifnode)) + { + ifp = getdata (ifnode); + + /* Skip pseudo interface. */ + if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) + continue; + + zsend_interface_add (client, ifp); + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + c = getdata (cnode); + if (CHECK_FLAG (c->conf, ZEBRA_IFC_REAL)) + zsend_interface_address_add (client, ifp, c); + } + } +} + +/* Unregister zebra server interface information. */ +void +zread_interface_delete (struct zserv *client, u_short length) +{ + client->ifinfo = 0; +} + +/* This function support multiple nexthop. */ +void +zread_ipv4_add (struct zserv *client, u_short length) +{ + int i; + struct rib *rib; + struct prefix_ipv4 p; + u_char message; + struct in_addr nexthop; + u_char nexthop_num; + u_char nexthop_type; + struct stream *s; + unsigned int ifindex; + u_char ifname_len; + + /* Get input stream. */ + s = client->ibuf; + + /* Allocate new rib. */ + rib = XMALLOC (MTYPE_RIB, sizeof (struct rib)); + memset (rib, 0, sizeof (struct rib)); + + /* Type, flags, message. */ + rib->type = stream_getc (s); + rib->flags = stream_getc (s); + message = stream_getc (s); + rib->uptime = time (NULL); + + /* IPv4 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop parse. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP)) + { + nexthop_num = stream_getc (s); + + for (i = 0; i < nexthop_num; i++) + { + nexthop_type = stream_getc (s); + + switch (nexthop_type) + { + case ZEBRA_NEXTHOP_IFINDEX: + ifindex = stream_getl (s); + nexthop_ifindex_add (rib, ifindex); + break; + case ZEBRA_NEXTHOP_IFNAME: + ifname_len = stream_getc (s); + stream_forward (s, ifname_len); + break; + case ZEBRA_NEXTHOP_IPV4: + nexthop.s_addr = stream_get_ipv4 (s); + nexthop_ipv4_add (rib, &nexthop); + break; + case ZEBRA_NEXTHOP_IPV6: + stream_forward (s, IPV6_MAX_BYTELEN); + break; + case ZEBRA_NEXTHOP_BLACKHOLE: + nexthop_blackhole_add (rib); + break; + } + } + } + + /* Distance. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) + rib->distance = stream_getc (s); + + /* Metric. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) + rib->metric = stream_getl (s); + + rib_add_ipv4_multipath (&p, rib); +} + +/* Zebra server IPv4 prefix delete function. */ +void +zread_ipv4_delete (struct zserv *client, u_short length) +{ + int i; + struct stream *s; + struct zapi_ipv4 api; + struct in_addr nexthop; + unsigned long ifindex; + struct prefix_ipv4 p; + u_char nexthop_num; + u_char nexthop_type; + u_char ifname_len; + + s = client->ibuf; + ifindex = 0; + nexthop.s_addr = 0; + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv4 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + nexthop_num = stream_getc (s); + + for (i = 0; i < nexthop_num; i++) + { + nexthop_type = stream_getc (s); + + switch (nexthop_type) + { + case ZEBRA_NEXTHOP_IFINDEX: + ifindex = stream_getl (s); + break; + case ZEBRA_NEXTHOP_IFNAME: + ifname_len = stream_getc (s); + stream_forward (s, ifname_len); + break; + case ZEBRA_NEXTHOP_IPV4: + nexthop.s_addr = stream_get_ipv4 (s); + break; + case ZEBRA_NEXTHOP_IPV6: + stream_forward (s, IPV6_MAX_BYTELEN); + break; + } + } + } + + /* Distance. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + else + api.distance = 0; + + /* Metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex, + client->rtm_table); +} + +/* Nexthop lookup for IPv4. */ +void +zread_ipv4_nexthop_lookup (struct zserv *client, u_short length) +{ + struct in_addr addr; + + addr.s_addr = stream_get_ipv4 (client->ibuf); + zsend_ipv4_nexthop_lookup (client, addr); +} + +/* Nexthop lookup for IPv4. */ +void +zread_ipv4_import_lookup (struct zserv *client, u_short length) +{ + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefixlen = stream_getc (client->ibuf); + p.prefix.s_addr = stream_get_ipv4 (client->ibuf); + + zsend_ipv4_import_lookup (client, &p); +} + +#ifdef HAVE_IPV6 +/* Zebra server IPv6 prefix add function. */ +void +zread_ipv6_add (struct zserv *client, u_short length) +{ + int i; + struct stream *s; + struct zapi_ipv6 api; + struct in6_addr nexthop; + unsigned long ifindex; + struct prefix_ipv6 p; + + s = client->ibuf; + ifindex = 0; + memset (&nexthop, 0, sizeof (struct in6_addr)); + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv4 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + u_char nexthop_type; + + api.nexthop_num = stream_getc (s); + for (i = 0; i < api.nexthop_num; i++) + { + nexthop_type = stream_getc (s); + + switch (nexthop_type) + { + case ZEBRA_NEXTHOP_IPV6: + stream_get (&nexthop, s, 16); + break; + case ZEBRA_NEXTHOP_IFINDEX: + ifindex = stream_getl (s); + break; + } + } + } + + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + else + api.distance = 0; + + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) + rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0); + else + rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, 0); +} + +/* Zebra server IPv6 prefix delete function. */ +void +zread_ipv6_delete (struct zserv *client, u_short length) +{ + int i; + struct stream *s; + struct zapi_ipv6 api; + struct in6_addr nexthop; + unsigned long ifindex; + struct prefix_ipv6 p; + + s = client->ibuf; + ifindex = 0; + memset (&nexthop, 0, sizeof (struct in6_addr)); + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv4 prefix. */ + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = stream_getc (s); + stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + u_char nexthop_type; + + api.nexthop_num = stream_getc (s); + for (i = 0; i < api.nexthop_num; i++) + { + nexthop_type = stream_getc (s); + + switch (nexthop_type) + { + case ZEBRA_NEXTHOP_IPV6: + stream_get (&nexthop, s, 16); + break; + case ZEBRA_NEXTHOP_IFINDEX: + ifindex = stream_getl (s); + break; + } + } + } + + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + else + api.distance = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) + rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0); + else + rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, 0); +} + +void +zebra_read_ipv6 (int command, struct zserv *client, u_short length) +{ + u_char type; + u_char flags; + struct in6_addr nexthop, *gate; + u_char *lim; + u_char *pnt; + unsigned int ifindex; + + pnt = stream_pnt (client->ibuf); + lim = pnt + length; + + type = stream_getc (client->ibuf); + flags = stream_getc (client->ibuf); + stream_get (&nexthop, client->ibuf, sizeof (struct in6_addr)); + + while (stream_pnt (client->ibuf) < lim) + { + int size; + struct prefix_ipv6 p; + + ifindex = stream_getl (client->ibuf); + + memset (&p, 0, sizeof (struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = stream_getc (client->ibuf); + size = PSIZE(p.prefixlen); + stream_get (&p.prefix, client->ibuf, size); + + if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) + gate = NULL; + else + gate = &nexthop; + + if (command == ZEBRA_IPV6_ROUTE_ADD) + rib_add_ipv6 (type, flags, &p, gate, ifindex, 0); + else + rib_delete_ipv6 (type, flags, &p, gate, ifindex, 0); + } +} + +void +zread_ipv6_nexthop_lookup (struct zserv *client, u_short length) +{ + struct in6_addr addr; + char buf[BUFSIZ]; + + stream_get (&addr, client->ibuf, 16); + printf ("DEBUG %s\n", inet_ntop (AF_INET6, &addr, buf, BUFSIZ)); + + zsend_ipv6_nexthop_lookup (client, &addr); +} +#endif /* HAVE_IPV6 */ + +/* Close zebra client. */ +void +zebra_client_close (struct zserv *client) +{ + /* Close file descriptor. */ + if (client->sock) + { + close (client->sock); + client->sock = -1; + } + + /* Free stream buffers. */ + if (client->ibuf) + stream_free (client->ibuf); + if (client->obuf) + stream_free (client->obuf); + + /* Release threads. */ + if (client->t_read) + thread_cancel (client->t_read); + if (client->t_write) + thread_cancel (client->t_write); + + /* Free client structure. */ + listnode_delete (client_list, client); + XFREE (0, client); +} + +/* Make new client. */ +void +zebra_client_create (int sock) +{ + struct zserv *client; + + client = XCALLOC (0, sizeof (struct zserv)); + + /* Make client input/output buffer. */ + client->sock = sock; + client->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); + client->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); + + /* Set table number. */ + client->rtm_table = rtm_table_default; + + /* Add this client to linked list. */ + listnode_add (client_list, client); + + /* Make new read thread. */ + zebra_event (ZEBRA_READ, sock, client); +} + +/* Handler of zebra service request. */ +int +zebra_client_read (struct thread *thread) +{ + int sock; + struct zserv *client; + int nbyte; + u_short length; + u_char command; + + /* Get thread data. Reset reading thread because I'm running. */ + sock = THREAD_FD (thread); + client = THREAD_ARG (thread); + client->t_read = NULL; + + /* Read length and command. */ + nbyte = stream_read (client->ibuf, sock, 3); + if (nbyte <= 0) + { + if (IS_ZEBRA_DEBUG_EVENT) + zlog_info ("connection closed socket [%d]", sock); + zebra_client_close (client); + return -1; + } + length = stream_getw (client->ibuf); + command = stream_getc (client->ibuf); + + if (length < 3) + { + if (IS_ZEBRA_DEBUG_EVENT) + zlog_info ("length %d is less than 3 ", length); + zebra_client_close (client); + return -1; + } + + length -= 3; + + /* Read rest of data. */ + if (length) + { + nbyte = stream_read (client->ibuf, sock, length); + if (nbyte <= 0) + { + if (IS_ZEBRA_DEBUG_EVENT) + zlog_info ("connection closed [%d] when reading zebra data", sock); + zebra_client_close (client); + return -1; + } + } + + /* Debug packet information. */ + if (IS_ZEBRA_DEBUG_EVENT) + zlog_info ("zebra message comes from socket [%d]", sock); + + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_info ("zebra message received [%s] %d", + zebra_command_str[command], length); + + switch (command) + { + case ZEBRA_INTERFACE_ADD: + zread_interface_add (client, length); + break; + case ZEBRA_INTERFACE_DELETE: + zread_interface_delete (client, length); + break; + case ZEBRA_IPV4_ROUTE_ADD: + zread_ipv4_add (client, length); + break; + case ZEBRA_IPV4_ROUTE_DELETE: + zread_ipv4_delete (client, length); + break; +#ifdef HAVE_IPV6 + case ZEBRA_IPV6_ROUTE_ADD: + zread_ipv6_add (client, length); + break; + case ZEBRA_IPV6_ROUTE_DELETE: + zread_ipv6_delete (client, length); + break; +#endif /* HAVE_IPV6 */ + case ZEBRA_REDISTRIBUTE_ADD: + zebra_redistribute_add (command, client, length); + break; + case ZEBRA_REDISTRIBUTE_DELETE: + zebra_redistribute_delete (command, client, length); + break; + case ZEBRA_REDISTRIBUTE_DEFAULT_ADD: + zebra_redistribute_default_add (command, client, length); + break; + case ZEBRA_REDISTRIBUTE_DEFAULT_DELETE: + zebra_redistribute_default_delete (command, client, length); + break; + case ZEBRA_IPV4_NEXTHOP_LOOKUP: + zread_ipv4_nexthop_lookup (client, length); + break; +#ifdef HAVE_IPV6 + case ZEBRA_IPV6_NEXTHOP_LOOKUP: + zread_ipv6_nexthop_lookup (client, length); + break; +#endif /* HAVE_IPV6 */ + case ZEBRA_IPV4_IMPORT_LOOKUP: + zread_ipv4_import_lookup (client, length); + break; + default: + zlog_info ("Zebra received unknown command %d", command); + break; + } + + stream_reset (client->ibuf); + zebra_event (ZEBRA_READ, sock, client); + + return 0; +} + +/* Write output buffer to the socket. */ +void +zebra_write (struct thread *thread) +{ + int sock; + struct zserv *client; + + /* Thread treatment. */ + sock = THREAD_FD (thread); + client = THREAD_ARG (thread); + client->t_write = NULL; + + stream_flush (client->obuf, sock); +} + +/* Accept code of zebra server socket. */ +int +zebra_accept (struct thread *thread) +{ + int val; + int accept_sock; + int client_sock; + struct sockaddr_in client; + socklen_t len; + + accept_sock = THREAD_FD (thread); + + len = sizeof (struct sockaddr_in); + client_sock = accept (accept_sock, (struct sockaddr *) &client, &len); + + if (client_sock < 0) + { + zlog_warn ("Can't accept zebra socket: %s", strerror (errno)); + return -1; + } + + /* Make client socket non-blocking. */ + + val = fcntl (client_sock, F_GETFL, 0); + fcntl (client_sock, F_SETFL, (val | O_NONBLOCK)); + + /* Create new zebra client. */ + zebra_client_create (client_sock); + + /* Register myself. */ + zebra_event (ZEBRA_SERV, accept_sock, NULL); + + return 0; +} + +/* Make zebra's server socket. */ +void +zebra_serv () +{ + int ret; + int accept_sock; + struct sockaddr_in addr; + + accept_sock = socket (AF_INET, SOCK_STREAM, 0); + + if (accept_sock < 0) + { + zlog_warn ("Can't bind to socket: %s", strerror (errno)); + zlog_warn ("zebra can't provice full functionality due to above error"); + return; + } + + memset (&addr, 0, sizeof (struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons (ZEBRA_PORT); +#ifdef HAVE_SIN_LEN + addr.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + sockopt_reuseaddr (accept_sock); + sockopt_reuseport (accept_sock); + + ret = bind (accept_sock, (struct sockaddr *)&addr, + sizeof (struct sockaddr_in)); + if (ret < 0) + { + zlog_warn ("Can't bind to socket: %s", strerror (errno)); + zlog_warn ("zebra can't provice full functionality due to above error"); + close (accept_sock); /* Avoid sd leak. */ + return; + } + + ret = listen (accept_sock, 1); + if (ret < 0) + { + zlog_warn ("Can't listen to socket: %s", strerror (errno)); + zlog_warn ("zebra can't provice full functionality due to above error"); + close (accept_sock); /* Avoid sd leak. */ + return; + } + + zebra_event (ZEBRA_SERV, accept_sock, NULL); +} + +/* For sockaddr_un. */ +#include + +/* zebra server UNIX domain socket. */ +void +zebra_serv_un (char *path) +{ + int ret; + int sock, len; + struct sockaddr_un serv; + mode_t old_mask; + + /* First of all, unlink existing socket */ + unlink (path); + + /* Set umask */ + old_mask = umask (0077); + + /* Make UNIX domain socket. */ + sock = socket (AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + { + perror ("sock"); + return; + } + + /* Make server socket. */ + memset (&serv, 0, sizeof (struct sockaddr_un)); + serv.sun_family = AF_UNIX; + strncpy (serv.sun_path, path, strlen (path)); +#ifdef HAVE_SUN_LEN + len = serv.sun_len = SUN_LEN(&serv); +#else + len = sizeof (serv.sun_family) + strlen (serv.sun_path); +#endif /* HAVE_SUN_LEN */ + + ret = bind (sock, (struct sockaddr *) &serv, len); + if (ret < 0) + { + perror ("bind"); + close (sock); + return; + } + + ret = listen (sock, 5); + if (ret < 0) + { + perror ("listen"); + close (sock); + return; + } + + umask (old_mask); + + zebra_event (ZEBRA_SERV, sock, NULL); +} + +/* Zebra's event management function. */ +extern struct thread_master *master; + +void +zebra_event (enum event event, int sock, struct zserv *client) +{ + switch (event) + { + case ZEBRA_SERV: + thread_add_read (master, zebra_accept, client, sock); + break; + case ZEBRA_READ: + client->t_read = + thread_add_read (master, zebra_client_read, client, sock); + break; + case ZEBRA_WRITE: + /**/ + break; + } +} + +/* Display default rtm_table for all clients. */ +DEFUN (show_table, + show_table_cmd, + "show table", + SHOW_STR + "default routing table to use for all clients\n") +{ + vty_out (vty, "table %d%s", rtm_table_default, + VTY_NEWLINE); + return CMD_SUCCESS; +} + +DEFUN (config_table, + config_table_cmd, + "table TABLENO", + "Configure target kernel routing table\n" + "TABLE integer\n") +{ + rtm_table_default = strtol (argv[0], (char**)0, 10); + return CMD_SUCCESS; +} + +DEFUN (no_ip_forwarding, + no_ip_forwarding_cmd, + "no ip forwarding", + NO_STR + IP_STR + "Turn off IP forwarding") +{ + int ret; + + ret = ipforward (); + + if (ret == 0) + { + vty_out (vty, "IP forwarding is already off%s", VTY_NEWLINE); + return CMD_ERR_NOTHING_TODO; + } + + ret = ipforward_off (); + if (ret != 0) + { + vty_out (vty, "Can't turn off IP forwarding%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* This command is for debugging purpose. */ +DEFUN (show_zebra_client, + show_zebra_client_cmd, + "show zebra client", + SHOW_STR + "Zebra information" + "Client information") +{ + listnode node; + struct zserv *client; + + for (node = listhead (client_list); node; nextnode (node)) + { + client = getdata (node); + vty_out (vty, "Client fd %d%s", client->sock, VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +/* Table configuration write function. */ +int +config_write_table (struct vty *vty) +{ + if (rtm_table_default) + vty_out (vty, "table %d%s", rtm_table_default, + VTY_NEWLINE); + return 0; +} + +/* table node for routing tables. */ +struct cmd_node table_node = +{ + TABLE_NODE, + "", /* This node has no interface. */ + 1 +}; + +/* Only display ip forwarding is enabled or not. */ +DEFUN (show_ip_forwarding, + show_ip_forwarding_cmd, + "show ip forwarding", + SHOW_STR + IP_STR + "IP forwarding status\n") +{ + int ret; + + ret = ipforward (); + + if (ret == 0) + vty_out (vty, "IP forwarding is off%s", VTY_NEWLINE); + else + vty_out (vty, "IP forwarding is on%s", VTY_NEWLINE); + return CMD_SUCCESS; +} + +#ifdef HAVE_IPV6 +/* Only display ipv6 forwarding is enabled or not. */ +DEFUN (show_ipv6_forwarding, + show_ipv6_forwarding_cmd, + "show ipv6 forwarding", + SHOW_STR + "IPv6 information\n" + "Forwarding status\n") +{ + int ret; + + ret = ipforward_ipv6 (); + + switch (ret) + { + case -1: + vty_out (vty, "ipv6 forwarding is unknown%s", VTY_NEWLINE); + break; + case 0: + vty_out (vty, "ipv6 forwarding is %s%s", "off", VTY_NEWLINE); + break; + case 1: + vty_out (vty, "ipv6 forwarding is %s%s", "on", VTY_NEWLINE); + break; + default: + vty_out (vty, "ipv6 forwarding is %s%s", "off", VTY_NEWLINE); + break; + } + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_forwarding, + no_ipv6_forwarding_cmd, + "no ipv6 forwarding", + NO_STR + IP_STR + "Doesn't forward IPv6 protocol packet") +{ + int ret; + + ret = ipforward_ipv6_off (); + if (ret != 0) + { + vty_out (vty, "Can't turn off IPv6 forwarding%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +#endif /* HAVE_IPV6 */ + +/* IPForwarding configuration write function. */ +int +config_write_forwarding (struct vty *vty) +{ + if (! ipforward ()) + vty_out (vty, "no ip forwarding%s", VTY_NEWLINE); +#ifdef HAVE_IPV6 + if (! ipforward_ipv6 ()) + vty_out (vty, "no ipv6 forwarding%s", VTY_NEWLINE); +#endif /* HAVE_IPV6 */ + vty_out (vty, "!%s", VTY_NEWLINE); + return 0; +} + +/* table node for routing tables. */ +struct cmd_node forwarding_node = +{ + FORWARDING_NODE, + "", /* This node has no interface. */ + 1 +}; + + +/* Initialisation of zebra and installation of commands. */ +void +zebra_init () +{ + /* Client list init. */ + client_list = list_new (); + + /* Forwarding is on by default. */ + ipforward_on (); +#ifdef HAVE_IPV6 + ipforward_ipv6_on (); +#endif /* HAVE_IPV6 */ + + /* Make zebra server socket. */ +#ifdef HAVE_TCP_ZEBRA + zebra_serv (); +#else + zebra_serv_un (ZEBRA_SERV_PATH); +#endif /* HAVE_TCP_ZEBRA */ + + /* Install configuration write function. */ + install_node (&table_node, config_write_table); + install_node (&forwarding_node, config_write_forwarding); + + install_element (VIEW_NODE, &show_ip_forwarding_cmd); + install_element (ENABLE_NODE, &show_ip_forwarding_cmd); + install_element (CONFIG_NODE, &no_ip_forwarding_cmd); + install_element (ENABLE_NODE, &show_zebra_client_cmd); + +#ifdef HAVE_NETLINK + install_element (VIEW_NODE, &show_table_cmd); + install_element (ENABLE_NODE, &show_table_cmd); + install_element (CONFIG_NODE, &config_table_cmd); +#endif /* HAVE_NETLINK */ + +#ifdef HAVE_IPV6 + install_element (VIEW_NODE, &show_ipv6_forwarding_cmd); + install_element (ENABLE_NODE, &show_ipv6_forwarding_cmd); + install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd); +#endif /* HAVE_IPV6 */ + + FIFO_INIT(&message_queue); + t_write = NULL; +} diff --git a/zebra/zserv.h b/zebra/zserv.h new file mode 100644 index 0000000..c762280 --- /dev/null +++ b/zebra/zserv.h @@ -0,0 +1,132 @@ +/* Zebra daemon server header. + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_ZSERV_H +#define _ZEBRA_ZSERV_H + +/* Default port information. */ +#define ZEBRA_PORT 2600 +#define ZEBRA_VTY_PORT 2601 +#define ZEBRA_VTYSH_PATH "/tmp/.zebra" +#define ZEBRA_SERV_PATH "/tmp/.zserv" + +/* Default configuration filename. */ +#define DEFAULT_CONFIG_FILE "zebra.conf" + +/* Client structure. */ +struct zserv +{ + /* Client file descriptor. */ + int sock; + + /* Input/output buffer to the client. */ + struct stream *ibuf; + struct stream *obuf; + + /* Threads for read/write. */ + struct thread *t_read; + struct thread *t_write; + + /* default routing table this client munges */ + int rtm_table; + + /* This client's redistribute flag. */ + u_char redist[ZEBRA_ROUTE_MAX]; + + /* Redistribute default route flag. */ + u_char redist_default; + + /* Interface information. */ + u_char ifinfo; +}; + +/* Count prefix size from mask length */ +#define PSIZE(a) (((a) + 7) / (8)) + +/* Prototypes. */ +void zebra_init (); +void zebra_if_init (); +void hostinfo_get (); +void rib_init (); +void interface_list (); +void kernel_init (); +void route_read (); +void rtadv_init (); +void zebra_snmp_init (); + +int +zsend_interface_add (struct zserv *, struct interface *); +int +zsend_interface_delete (struct zserv *, struct interface *); + +int +zsend_interface_address_add (struct zserv *, struct interface *, + struct connected *); + +int +zsend_interface_address_delete (struct zserv *, struct interface *, + struct connected *); + +int +zsend_interface_up (struct zserv *, struct interface *); + +int +zsend_interface_down (struct zserv *, struct interface *); + +int +zsend_ipv4_add (struct zserv *client, int type, int flags, + struct prefix_ipv4 *p, struct in_addr *nexthop, + unsigned int ifindex); + +int +zsend_ipv4_delete (struct zserv *client, int type, int flags, + struct prefix_ipv4 *p, struct in_addr *nexthop, + unsigned int ifindex); + +int +zsend_ipv4_add_multipath (struct zserv *, struct prefix *, struct rib *); + +int +zsend_ipv4_delete_multipath (struct zserv *, struct prefix *, struct rib *); + +#ifdef HAVE_IPV6 +int +zsend_ipv6_add (struct zserv *client, int type, int flags, + struct prefix_ipv6 *p, struct in6_addr *nexthop, + unsigned int ifindex); + +int +zsend_ipv6_delete (struct zserv *client, int type, int flags, + struct prefix_ipv6 *p, struct in6_addr *nexthop, + unsigned int ifindex); + +int +zsend_ipv6_add_multipath (struct zserv *, struct prefix *, struct rib *); + +int +zsend_ipv6_delete_multipath (struct zserv *, struct prefix *, struct rib *); + +#endif /* HAVE_IPV6 */ + +extern pid_t pid; +extern pid_t old_pid; + +#endif /* _ZEBRA_ZEBRA_H */